| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stddef.h> |
| |
| #include <utility> |
| |
| #include "cc/base/region.h" |
| #include "cc/output/compositor_frame_metadata.h" |
| #include "cc/output/gl_renderer.h" |
| #include "cc/output/output_surface.h" |
| #include "cc/output/output_surface_client.h" |
| #include "cc/output/overlay_candidate_validator.h" |
| #include "cc/output/overlay_processor.h" |
| #include "cc/output/overlay_strategy_sandwich.h" |
| #include "cc/output/overlay_strategy_single_on_top.h" |
| #include "cc/output/overlay_strategy_underlay.h" |
| #include "cc/quads/render_pass.h" |
| #include "cc/quads/solid_color_draw_quad.h" |
| #include "cc/quads/stream_video_draw_quad.h" |
| #include "cc/quads/texture_draw_quad.h" |
| #include "cc/resources/resource_provider.h" |
| #include "cc/resources/texture_mailbox.h" |
| #include "cc/test/fake_output_surface_client.h" |
| #include "cc/test/fake_resource_provider.h" |
| #include "cc/test/geometry_test_utils.h" |
| #include "cc/test/test_context_provider.h" |
| #include "cc/test/test_shared_bitmap_manager.h" |
| #include "cc/test/test_web_graphics_context_3d.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| |
| using testing::_; |
| using testing::Mock; |
| |
| namespace cc { |
| namespace { |
| |
| const gfx::Size kDisplaySize(256, 256); |
| const gfx::Rect kOverlayRect(0, 0, 128, 128); |
| const gfx::Rect kOverlayTopLeftRect(0, 0, 64, 64); |
| const gfx::Rect kOverlayBottomRightRect(64, 64, 64, 64); |
| const gfx::Rect kOverlayClipRect(0, 0, 128, 128); |
| const gfx::PointF kUVTopLeft(0.1f, 0.2f); |
| const gfx::PointF kUVBottomRight(1.0f, 1.0f); |
| const gfx::Transform kNormalTransform = |
| gfx::Transform(0.9f, 0, 0, 0.8f, 0.1f, 0.2f); // x,y -> x,y. |
| const gfx::Transform kXMirrorTransform = |
| gfx::Transform(-0.9f, 0, 0, 0.8f, 1.0f, 0.2f); // x,y -> 1-x,y. |
| const gfx::Transform kYMirrorTransform = |
| gfx::Transform(0.9f, 0, 0, -0.8f, 0.1f, 1.0f); // x,y -> x,1-y. |
| const gfx::Transform kBothMirrorTransform = |
| gfx::Transform(-0.9f, 0, 0, -0.8f, 1.0f, 1.0f); // x,y -> 1-x,1-y. |
| const gfx::Transform kSwapTransform = |
| gfx::Transform(0, 1, 1, 0, 0, 0); // x,y -> y,x. |
| |
| void MailboxReleased(const gpu::SyncToken& sync_token, |
| bool lost_resource, |
| BlockingTaskRunner* main_thread_task_runner) {} |
| |
| class SingleOverlayValidator : public OverlayCandidateValidator { |
| public: |
| void GetStrategies(OverlayProcessor::StrategyList* strategies) override { |
| strategies->push_back( |
| make_scoped_ptr(new OverlayStrategySingleOnTop(this))); |
| strategies->push_back(make_scoped_ptr(new OverlayStrategyUnderlay(this))); |
| } |
| bool AllowCALayerOverlays() override { return false; } |
| void CheckOverlaySupport(OverlayCandidateList* surfaces) override { |
| // We may have 1 or 2 surfaces depending on whether this ran through the |
| // full renderer and picked up the output surface, or not. |
| ASSERT_LE(1U, surfaces->size()); |
| ASSERT_GE(2U, surfaces->size()); |
| |
| OverlayCandidate& candidate = surfaces->back(); |
| EXPECT_TRUE(!candidate.use_output_surface_for_resource); |
| if (candidate.display_rect.width() == 64) { |
| EXPECT_EQ(gfx::RectF(kOverlayBottomRightRect), candidate.display_rect); |
| } else { |
| EXPECT_NEAR(kOverlayRect.x(), candidate.display_rect.x(), 0.01f); |
| EXPECT_NEAR(kOverlayRect.y(), candidate.display_rect.y(), 0.01f); |
| EXPECT_NEAR(kOverlayRect.width(), candidate.display_rect.width(), 0.01f); |
| EXPECT_NEAR(kOverlayRect.height(), candidate.display_rect.height(), |
| 0.01f); |
| } |
| EXPECT_FLOAT_RECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight), |
| candidate.uv_rect); |
| if (!candidate.clip_rect.IsEmpty()) { |
| EXPECT_EQ(true, candidate.is_clipped); |
| EXPECT_EQ(kOverlayClipRect, candidate.clip_rect); |
| } |
| candidate.overlay_handled = true; |
| } |
| }; |
| |
| class CALayerValidator : public OverlayCandidateValidator { |
| public: |
| void GetStrategies(OverlayProcessor::StrategyList* strategies) override {} |
| bool AllowCALayerOverlays() override { return true; } |
| void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} |
| }; |
| |
| class SingleOnTopOverlayValidator : public SingleOverlayValidator { |
| public: |
| void GetStrategies(OverlayProcessor::StrategyList* strategies) override { |
| strategies->push_back( |
| make_scoped_ptr(new OverlayStrategySingleOnTop(this))); |
| } |
| }; |
| |
| class UnderlayOverlayValidator : public SingleOverlayValidator { |
| public: |
| void GetStrategies(OverlayProcessor::StrategyList* strategies) override { |
| strategies->push_back(make_scoped_ptr(new OverlayStrategyUnderlay(this))); |
| } |
| }; |
| |
| class SandwichOverlayValidator : public OverlayCandidateValidator { |
| public: |
| void GetStrategies(OverlayProcessor::StrategyList* strategies) override { |
| strategies->push_back(make_scoped_ptr(new OverlayStrategySandwich(this))); |
| } |
| bool AllowCALayerOverlays() override { return false; } |
| void CheckOverlaySupport(OverlayCandidateList* surfaces) override { |
| for (OverlayCandidate& candidate : *surfaces) |
| candidate.overlay_handled = true; |
| } |
| }; |
| |
| class DefaultOverlayProcessor : public OverlayProcessor { |
| public: |
| explicit DefaultOverlayProcessor(OutputSurface* surface); |
| size_t GetStrategyCount(); |
| }; |
| |
| DefaultOverlayProcessor::DefaultOverlayProcessor(OutputSurface* surface) |
| : OverlayProcessor(surface) { |
| } |
| |
| size_t DefaultOverlayProcessor::GetStrategyCount() { |
| return strategies_.size(); |
| } |
| |
| class OverlayOutputSurface : public OutputSurface { |
| public: |
| explicit OverlayOutputSurface(scoped_refptr<ContextProvider> context_provider) |
| : OutputSurface(context_provider) { |
| surface_size_ = kDisplaySize; |
| device_scale_factor_ = 1; |
| is_displayed_as_overlay_plane_ = true; |
| } |
| |
| void SetScaleFactor(float scale_factor) { |
| device_scale_factor_ = scale_factor; |
| } |
| |
| // OutputSurface implementation |
| void SwapBuffers(CompositorFrame* frame) override; |
| |
| void SetOverlayCandidateValidator(OverlayCandidateValidator* validator) { |
| overlay_candidate_validator_.reset(validator); |
| } |
| |
| OverlayCandidateValidator* GetOverlayCandidateValidator() const override { |
| return overlay_candidate_validator_.get(); |
| } |
| |
| bool IsDisplayedAsOverlayPlane() const override { |
| return is_displayed_as_overlay_plane_; |
| } |
| unsigned GetOverlayTextureId() const override { return 10000; } |
| void set_is_displayed_as_overlay_plane(bool value) { |
| is_displayed_as_overlay_plane_ = value; |
| } |
| |
| private: |
| scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_; |
| bool is_displayed_as_overlay_plane_; |
| }; |
| |
| void OverlayOutputSurface::SwapBuffers(CompositorFrame* frame) { |
| client_->DidSwapBuffers(); |
| client_->DidSwapBuffersComplete(); |
| } |
| |
| scoped_ptr<RenderPass> CreateRenderPass() { |
| RenderPassId id(1, 0); |
| gfx::Rect output_rect(0, 0, 256, 256); |
| bool has_transparent_background = true; |
| |
| scoped_ptr<RenderPass> pass = RenderPass::Create(); |
| pass->SetAll(id, |
| output_rect, |
| output_rect, |
| gfx::Transform(), |
| has_transparent_background); |
| |
| SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); |
| shared_state->opacity = 1.f; |
| return pass; |
| } |
| |
| ResourceId CreateResource(ResourceProvider* resource_provider, |
| const gfx::Size& size, |
| bool is_overlay_candidate) { |
| TextureMailbox mailbox = |
| TextureMailbox(gpu::Mailbox::Generate(), gpu::SyncToken(), GL_TEXTURE_2D, |
| size, is_overlay_candidate); |
| scoped_ptr<SingleReleaseCallbackImpl> release_callback = |
| SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased)); |
| |
| return resource_provider->CreateResourceFromTextureMailbox( |
| mailbox, std::move(release_callback)); |
| } |
| |
| SolidColorDrawQuad* CreateSolidColorQuadAt( |
| const SharedQuadState* shared_quad_state, |
| SkColor color, |
| RenderPass* render_pass, |
| const gfx::Rect& rect) { |
| SolidColorDrawQuad* quad = |
| render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| quad->SetNew(shared_quad_state, rect, rect, color, false); |
| return quad; |
| } |
| |
| TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass, |
| const gfx::Rect& rect) { |
| bool premultiplied_alpha = false; |
| bool flipped = false; |
| bool nearest_neighbor = false; |
| float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| gfx::Size resource_size_in_pixels = gfx::Size(64, 64); |
| bool is_overlay_candidate = true; |
| ResourceId resource_id = CreateResource( |
| resource_provider, resource_size_in_pixels, is_overlay_candidate); |
| |
| TextureDrawQuad* overlay_quad = |
| render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); |
| overlay_quad->SetNew(shared_quad_state, |
| rect, |
| rect, |
| rect, |
| resource_id, |
| premultiplied_alpha, |
| kUVTopLeft, |
| kUVBottomRight, |
| SK_ColorTRANSPARENT, |
| vertex_opacity, |
| flipped, |
| nearest_neighbor); |
| overlay_quad->set_resource_size_in_pixels(resource_size_in_pixels); |
| |
| return overlay_quad; |
| } |
| |
| StreamVideoDrawQuad* CreateCandidateVideoQuadAt( |
| ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass, |
| const gfx::Rect& rect, |
| const gfx::Transform& transform) { |
| gfx::Size resource_size_in_pixels = gfx::Size(64, 64); |
| bool is_overlay_candidate = true; |
| ResourceId resource_id = CreateResource( |
| resource_provider, resource_size_in_pixels, is_overlay_candidate); |
| |
| StreamVideoDrawQuad* overlay_quad = |
| render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>(); |
| overlay_quad->SetNew(shared_quad_state, rect, rect, rect, resource_id, |
| resource_size_in_pixels, transform); |
| |
| return overlay_quad; |
| } |
| |
| TextureDrawQuad* CreateFullscreenCandidateQuad( |
| ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass) { |
| return CreateCandidateQuadAt( |
| resource_provider, shared_quad_state, render_pass, kOverlayRect); |
| } |
| |
| StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad( |
| ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass, |
| const gfx::Transform& transform) { |
| return CreateCandidateVideoQuadAt(resource_provider, shared_quad_state, |
| render_pass, kOverlayRect, transform); |
| } |
| |
| void CreateOpaqueQuadAt(ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass, |
| const gfx::Rect& rect) { |
| SolidColorDrawQuad* color_quad = |
| render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); |
| color_quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); |
| } |
| |
| void CreateFullscreenOpaqueQuad(ResourceProvider* resource_provider, |
| const SharedQuadState* shared_quad_state, |
| RenderPass* render_pass) { |
| CreateOpaqueQuadAt(resource_provider, shared_quad_state, render_pass, |
| kOverlayRect); |
| } |
| |
| static void CompareRenderPassLists(const RenderPassList& expected_list, |
| const RenderPassList& actual_list) { |
| EXPECT_EQ(expected_list.size(), actual_list.size()); |
| for (size_t i = 0; i < actual_list.size(); ++i) { |
| RenderPass* expected = expected_list[i].get(); |
| RenderPass* actual = actual_list[i].get(); |
| |
| EXPECT_EQ(expected->id, actual->id); |
| EXPECT_EQ(expected->output_rect, actual->output_rect); |
| EXPECT_EQ(expected->transform_to_root_target, |
| actual->transform_to_root_target); |
| EXPECT_EQ(expected->damage_rect, actual->damage_rect); |
| EXPECT_EQ(expected->has_transparent_background, |
| actual->has_transparent_background); |
| |
| EXPECT_EQ(expected->shared_quad_state_list.size(), |
| actual->shared_quad_state_list.size()); |
| EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size()); |
| |
| for (auto exp_iter = expected->quad_list.cbegin(), |
| act_iter = actual->quad_list.cbegin(); |
| exp_iter != expected->quad_list.cend(); |
| ++exp_iter, ++act_iter) { |
| EXPECT_EQ(exp_iter->rect.ToString(), act_iter->rect.ToString()); |
| EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_bounds.ToString(), |
| act_iter->shared_quad_state->quad_layer_bounds.ToString()); |
| } |
| } |
| } |
| |
| template <typename OverlayCandidateValidatorType> |
| class OverlayTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| provider_ = TestContextProvider::Create(); |
| output_surface_.reset(new OverlayOutputSurface(provider_)); |
| EXPECT_TRUE(output_surface_->BindToClient(&client_)); |
| output_surface_->SetOverlayCandidateValidator( |
| new OverlayCandidateValidatorType); |
| |
| shared_bitmap_manager_.reset(new TestSharedBitmapManager()); |
| resource_provider_ = FakeResourceProvider::Create( |
| output_surface_.get(), shared_bitmap_manager_.get()); |
| |
| overlay_processor_.reset(new OverlayProcessor(output_surface_.get())); |
| overlay_processor_->Initialize(); |
| } |
| |
| scoped_refptr<TestContextProvider> provider_; |
| scoped_ptr<OverlayOutputSurface> output_surface_; |
| FakeOutputSurfaceClient client_; |
| scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; |
| scoped_ptr<ResourceProvider> resource_provider_; |
| scoped_ptr<OverlayProcessor> overlay_processor_; |
| gfx::Rect damage_rect_; |
| }; |
| |
| typedef OverlayTest<SingleOnTopOverlayValidator> SingleOverlayOnTopTest; |
| typedef OverlayTest<UnderlayOverlayValidator> UnderlayTest; |
| typedef OverlayTest<SandwichOverlayValidator> SandwichTest; |
| typedef OverlayTest<CALayerValidator> CALayerOverlayTest; |
| |
| TEST(OverlayTest, NoOverlaysByDefault) { |
| scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); |
| OverlayOutputSurface output_surface(provider); |
| EXPECT_EQ(NULL, output_surface.GetOverlayCandidateValidator()); |
| |
| output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator); |
| EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != NULL); |
| } |
| |
| TEST(OverlayTest, OverlaysProcessorHasStrategy) { |
| scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); |
| OverlayOutputSurface output_surface(provider); |
| FakeOutputSurfaceClient client; |
| EXPECT_TRUE(output_surface.BindToClient(&client)); |
| output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator); |
| |
| scoped_ptr<SharedBitmapManager> shared_bitmap_manager( |
| new TestSharedBitmapManager()); |
| scoped_ptr<ResourceProvider> resource_provider = FakeResourceProvider::Create( |
| &output_surface, shared_bitmap_manager.get()); |
| |
| scoped_ptr<DefaultOverlayProcessor> overlay_processor( |
| new DefaultOverlayProcessor(&output_surface)); |
| overlay_processor->Initialize(); |
| EXPECT_GE(2U, overlay_processor->GetStrategyCount()); |
| } |
| |
| TEST_F(SandwichTest, SuccessfulSingleOverlay) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( |
| resource_provider_.get(), pass->shared_quad_state_list.back(), |
| pass.get()); |
| unsigned original_resource_id = original_quad->resource_id(); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| |
| RenderPass* main_pass = pass_list.back().get(); |
| // Check that the quad is gone. |
| EXPECT_EQ(2U, main_pass->quad_list.size()); |
| const QuadList& quad_list = main_pass->quad_list; |
| for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); |
| it != quad_list.BackToFrontEnd(); ++it) { |
| EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); |
| } |
| |
| // Check that the right resource id got extracted. |
| EXPECT_EQ(original_resource_id, candidate_list.back().resource_id); |
| } |
| |
| TEST_F(SandwichTest, CroppedSingleOverlay) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| pass->shared_quad_state_list.back()->is_clipped = true; |
| pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 32, 64, 64); |
| |
| TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( |
| resource_provider_.get(), pass->shared_quad_state_list.back(), |
| pass.get()); |
| original_quad->uv_top_left = gfx::PointF(0, 0); |
| original_quad->uv_bottom_right = gfx::PointF(1, 1); |
| unsigned candidate_id = original_quad->resource_id(); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| // Ensure that the display and uv rects have cropping applied to them. |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(candidate_id, candidate_list[0].resource_id); |
| EXPECT_EQ(gfx::RectF(0.f, 32.f, 64.f, 64.f), candidate_list[0].display_rect); |
| EXPECT_EQ(gfx::RectF(0.f, 0.25f, 0.5f, 0.5f), candidate_list[0].uv_rect); |
| } |
| |
| TEST_F(SandwichTest, SuccessfulTwoOverlays) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| // Add two non-overlapping candidates. |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayTopLeftRect); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayBottomRightRect); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| // Both candidates should become overlays. |
| EXPECT_EQ(1u, pass_list.size()); |
| EXPECT_EQ(2u, candidate_list.size()); |
| EXPECT_EQ(gfx::RectF(kOverlayTopLeftRect), candidate_list[0].display_rect); |
| EXPECT_EQ(gfx::RectF(kOverlayBottomRightRect), |
| candidate_list[1].display_rect); |
| |
| // The overlay quads should be gone. |
| const QuadList& quad_list = pass_list.back()->quad_list; |
| EXPECT_EQ(1u, quad_list.size()); |
| EXPECT_EQ(DrawQuad::SOLID_COLOR, quad_list.front()->material); |
| } |
| |
| TEST_F(SandwichTest, OverlappingOverlays) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| // Add two overlapping candidates. |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayTopLeftRect); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayRect); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| // Only one of the candidates should become an overlay. |
| EXPECT_EQ(1u, pass_list.size()); |
| EXPECT_EQ(1u, candidate_list.size()); |
| EXPECT_EQ(gfx::RectF(kOverlayTopLeftRect), candidate_list[0].display_rect); |
| |
| // One of the overlay quads should be gone. |
| const QuadList& quad_list = pass_list.back()->quad_list; |
| EXPECT_EQ(2u, quad_list.size()); |
| EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, quad_list.front()->material); |
| EXPECT_EQ(DrawQuad::SOLID_COLOR, quad_list.back()->material); |
| } |
| |
| TEST_F(SandwichTest, SuccessfulSandwichOverlay) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| gfx::Rect(16, 16, 32, 32)); |
| unsigned candidate_id = |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| gfx::Rect(32, 32, 32, 32)) |
| ->resource_id(); |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| gfx::Rect(kDisplaySize)); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(2U, candidate_list.size()); |
| |
| RenderPass* main_pass = pass_list.back().get(); |
| // Check that the quad is gone. |
| EXPECT_EQ(3U, main_pass->quad_list.size()); |
| const QuadList& quad_list = main_pass->quad_list; |
| for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); |
| it != quad_list.BackToFrontEnd(); ++it) { |
| EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); |
| } |
| |
| EXPECT_EQ(candidate_id, candidate_list[0].resource_id); |
| EXPECT_EQ(gfx::RectF(32.f, 32.f, 32.f, 32.f), candidate_list[0].display_rect); |
| EXPECT_TRUE(candidate_list[1].use_output_surface_for_resource); |
| EXPECT_EQ(gfx::RectF(32.f, 32.f, 16.f, 16.f), candidate_list[1].display_rect); |
| EXPECT_EQ(gfx::RectF(32.f / 256.f, 32.f / 256.f, 16.f / 256.f, 16.f / 256.f), |
| candidate_list[1].uv_rect); |
| } |
| |
| TEST_F(SandwichTest, MultiQuadOverlay) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| // Put two non-intersecting quads on top. |
| const gfx::Rect rect1(gfx::Rect(0, 0, 32, 32)); |
| const gfx::Rect rect2(gfx::Rect(32, 32, 32, 32)); |
| Region covered_region; |
| covered_region.Union(rect1); |
| covered_region.Union(rect2); |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect1); |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect2); |
| |
| // Then a candidate that we'll turn into an overlay. |
| unsigned candidate_id = |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| gfx::Rect(0, 0, 64, 64)) |
| ->resource_id(); |
| |
| // Then some opaque background. |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| gfx::Rect(kDisplaySize)); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Run the overlay strategy on that input. |
| RenderPass* main_pass = pass_list.back().get(); |
| OverlayCandidateList candidate_list; |
| EXPECT_EQ(4U, main_pass->quad_list.size()); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(3U, candidate_list.size()); |
| |
| // Check that the candidate quad is gone and that we now have two transparent |
| // quads for the same region that was covered on the overlay. |
| EXPECT_EQ(5U, main_pass->quad_list.size()); |
| const QuadList& quad_list = main_pass->quad_list; |
| Region transparent_quad_region; |
| for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); |
| it != quad_list.BackToFrontEnd(); ++it) { |
| EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); |
| if (it->material == DrawQuad::SOLID_COLOR) { |
| const SolidColorDrawQuad* solid_color_quad = |
| SolidColorDrawQuad::MaterialCast(*it); |
| if (solid_color_quad->color == SK_ColorTRANSPARENT) |
| transparent_quad_region.Union(solid_color_quad->rect); |
| } |
| } |
| DCHECK(covered_region == transparent_quad_region); |
| |
| // Check that overlays cover the same region that the quads covered. |
| EXPECT_EQ(candidate_id, candidate_list[0].resource_id); |
| EXPECT_EQ(gfx::RectF(64.f, 64.f), candidate_list[0].display_rect); |
| EXPECT_TRUE(candidate_list[1].use_output_surface_for_resource); |
| EXPECT_TRUE(candidate_list[2].use_output_surface_for_resource); |
| Region overlay_region; |
| overlay_region.Union(gfx::ToEnclosingRect(candidate_list[1].display_rect)); |
| overlay_region.Union(gfx::ToEnclosingRect(candidate_list[2].display_rect)); |
| DCHECK(covered_region == overlay_region); |
| } |
| |
| TEST_F(SandwichTest, DamageRect) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| damage_rect_ = kOverlayRect; |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| |
| // Primary plane. |
| OverlayCandidate output_surface_plane; |
| output_surface_plane.display_rect = gfx::RectF(kOverlayRect); |
| output_surface_plane.quad_rect_in_target_space = kOverlayRect; |
| output_surface_plane.use_output_surface_for_resource = true; |
| output_surface_plane.overlay_handled = true; |
| candidate_list.push_back(output_surface_plane); |
| |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(2u, candidate_list.size()); |
| EXPECT_TRUE(damage_rect_.IsEmpty()); |
| } |
| |
| TEST_F(SandwichTest, DamageRectNonEmpty) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| damage_rect_ = kOverlayRect; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| |
| // Primary plane. |
| OverlayCandidate output_surface_plane; |
| output_surface_plane.display_rect = gfx::RectF(kOverlayRect); |
| output_surface_plane.quad_rect_in_target_space = kOverlayRect; |
| output_surface_plane.use_output_surface_for_resource = true; |
| output_surface_plane.overlay_handled = true; |
| candidate_list.push_back(output_surface_plane); |
| |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(3u, candidate_list.size()); |
| EXPECT_EQ(damage_rect_, kOverlayRect); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| TextureDrawQuad* original_quad = |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| unsigned original_resource_id = original_quad->resource_id(); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| |
| RenderPass* main_pass = pass_list.back().get(); |
| // Check that the quad is gone. |
| EXPECT_EQ(2U, main_pass->quad_list.size()); |
| const QuadList& quad_list = main_pass->quad_list; |
| for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); |
| it != quad_list.BackToFrontEnd(); |
| ++it) { |
| EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); |
| } |
| |
| // Check that the right resource id got extracted. |
| EXPECT_EQ(original_resource_id, candidate_list.back().resource_id); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, DamageRect) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| damage_rect_ = kOverlayRect; |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| |
| // Primary plane. |
| OverlayCandidate output_surface_plane; |
| output_surface_plane.display_rect = gfx::RectF(kOverlayRect); |
| output_surface_plane.quad_rect_in_target_space = kOverlayRect; |
| output_surface_plane.use_output_surface_for_resource = true; |
| output_surface_plane.overlay_handled = true; |
| candidate_list.push_back(output_surface_plane); |
| |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| DCHECK(damage_rect_.IsEmpty()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, NoCandidates) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(0U, candidate_list.size()); |
| // There should be nothing new here. |
| CompareRenderPassLists(pass_list, original_pass_list); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(0U, candidate_list.size()); |
| // There should be nothing new here. |
| CompareRenderPassLists(pass_list, original_pass_list); |
| } |
| |
| // Test with multiple render passes. |
| TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) { |
| RenderPassList pass_list; |
| pass_list.push_back(CreateRenderPass()); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| // Check for potential candidates. |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, candidate_list.size()); |
| |
| // This should be the same. |
| ASSERT_EQ(2U, pass_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectPremultipliedAlpha) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| TextureDrawQuad* quad = |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| quad->premultiplied_alpha = true; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectBlending) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| TextureDrawQuad* quad = |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| quad->needs_blending = true; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| TextureDrawQuad* quad = |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| quad->background_color = SK_ColorBLACK; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectBlendMode) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->blend_mode = SkXfermode::kScreen_Mode; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectOpacity) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->opacity = 0.5f; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutXAxis(45.f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowClipped) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->is_clipped = true; |
| pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowVerticalFlip) { |
| gfx::Rect rect = kOverlayRect; |
| rect.set_width(rect.width() / 2); |
| rect.Offset(0, -rect.height()); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f, |
| -1.0f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, |
| candidate_list.back().transform); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowHorizontalFlip) { |
| gfx::Rect rect = kOverlayRect; |
| rect.set_height(rect.height() / 2); |
| rect.Offset(-rect.width(), 0); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(-1.0f, |
| 2.0f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, |
| candidate_list.back().transform); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) { |
| gfx::Rect rect = kOverlayRect; |
| rect.set_width(rect.width() / 2); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f, |
| 1.0f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, Allow90DegreeRotation) { |
| gfx::Rect rect = kOverlayRect; |
| rect.Offset(0, -rect.height()); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutZAxis(90.f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, Allow180DegreeRotation) { |
| gfx::Rect rect = kOverlayRect; |
| rect.Offset(-rect.width(), -rect.height()); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutZAxis(180.f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, Allow270DegreeRotation) { |
| gfx::Rect rect = kOverlayRect; |
| rect.Offset(-rect.width(), 0); |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), rect); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutZAxis(270.f); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayTopLeftRect); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); |
| shared_state->opacity = 0.f; |
| CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(), |
| kOverlayBottomRightRect); |
| shared_state = pass->CreateAndAppendSharedQuadState(); |
| shared_state->opacity = 1.f; |
| CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateSolidColorQuadAt(pass->shared_quad_state_list.back(), |
| SK_ColorTRANSPARENT, pass.get(), |
| kOverlayBottomRightRect); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); |
| shared_state->opacity = 0.5f; |
| CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(), |
| kOverlayBottomRightRect); |
| shared_state = pass->CreateAndAppendSharedQuadState(); |
| shared_state->opacity = 1.f; |
| CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); |
| CreateSolidColorQuadAt(shared_state, SK_ColorTRANSPARENT, pass.get(), |
| kOverlayBottomRightRect)->opaque_rect = |
| kOverlayBottomRightRect; |
| CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| RenderPassList original_pass_list; |
| RenderPass::CopyAll(pass_list, &original_pass_list); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateVideoQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), kSwapTransform); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowVideoXMirrorTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateVideoQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), kXMirrorTransform); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowVideoBothMirrorTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateVideoQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), kBothMirrorTransform); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowVideoNormalTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateVideoQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), kNormalTransform); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateVideoQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get(), kYMirrorTransform); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, candidate_list.size()); |
| } |
| |
| TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayBottomRightRect); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(-1, candidate_list[0].plane_z_order); |
| EXPECT_EQ(2U, pass_list[0]->quad_list.size()); |
| // The overlay quad should have changed to a SOLID_COLOR quad. |
| EXPECT_EQ(pass_list[0]->quad_list.back()->material, DrawQuad::SOLID_COLOR); |
| } |
| |
| TEST_F(UnderlayTest, AllowOnTop) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->CreateAndAppendSharedQuadState()->opacity = 0.5f; |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| EXPECT_EQ(1U, pass_list.size()); |
| ASSERT_EQ(1U, candidate_list.size()); |
| EXPECT_EQ(-1, candidate_list[0].plane_z_order); |
| // The overlay quad should have changed to a SOLID_COLOR quad. |
| EXPECT_EQ(pass_list[0]->quad_list.front()->material, DrawQuad::SOLID_COLOR); |
| } |
| |
| // The first time an underlay is scheduled its damage must not be subtracted. |
| TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| damage_rect_ = kOverlayRect; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| EXPECT_EQ(kOverlayRect, damage_rect_); |
| } |
| |
| // An identical underlay for two frames in a row means the damage can be |
| // subtracted the second time. |
| TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) { |
| for (int i = 0; i < 2; ++i) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| damage_rect_ = kOverlayRect; |
| |
| // Add something behind it. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| } |
| |
| // The second time the same overlay rect is scheduled it will be subtracted |
| // from the damage rect. |
| EXPECT_TRUE(damage_rect_.IsEmpty()); |
| } |
| |
| // Underlay damage can only be subtracted if the previous frame's underlay |
| // was the same rect. |
| TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) { |
| gfx::Rect overlay_rects[] = {kOverlayBottomRightRect, kOverlayRect}; |
| for (int i = 0; i < 2; ++i) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| overlay_rects[i]); |
| |
| damage_rect_ = overlay_rects[i]; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| |
| EXPECT_EQ(overlay_rects[i], damage_rect_); |
| } |
| } |
| |
| TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) { |
| for (int i = 0; i < 2; ++i) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| // Add an overlapping quad above the candidate. |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| damage_rect_ = kOverlayRect; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| } |
| |
| EXPECT_EQ(kOverlayRect, damage_rect_); |
| } |
| |
| TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) { |
| for (int i = 0; i < 2; ++i) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| // Add a non-overlapping quad above the candidate. |
| CreateOpaqueQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayTopLeftRect); |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayBottomRightRect); |
| |
| damage_rect_ = kOverlayBottomRightRect; |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| OverlayCandidateList candidate_list; |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &candidate_list, nullptr, |
| &damage_rect_); |
| } |
| |
| EXPECT_TRUE(damage_rect_.IsEmpty()); |
| } |
| |
| OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) { |
| OverlayCandidateList list; |
| OverlayCandidate output_surface_plane; |
| output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect); |
| output_surface_plane.quad_rect_in_target_space = |
| root_render_pass->output_rect; |
| output_surface_plane.use_output_surface_for_resource = true; |
| output_surface_plane.overlay_handled = true; |
| list.push_back(output_surface_plane); |
| return list; |
| } |
| |
| TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutZAxis(45.f); |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(0U, overlay_list.size()); |
| EXPECT_EQ(1U, ca_layer_list.size()); |
| } |
| |
| TEST_F(CALayerOverlayTest, Disallow3DTransform) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back() |
| ->quad_to_target_transform.RotateAboutXAxis(45.f); |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(1U, overlay_list.size()); |
| EXPECT_EQ(0U, ca_layer_list.size()); |
| } |
| |
| TEST_F(CALayerOverlayTest, AllowContainingClip) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->is_clipped = true; |
| pass->shared_quad_state_list.back()->clip_rect = kOverlayRect; |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(0U, overlay_list.size()); |
| EXPECT_EQ(1U, ca_layer_list.size()); |
| } |
| |
| TEST_F(CALayerOverlayTest, SkipDisjointClip) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->is_clipped = true; |
| pass->shared_quad_state_list.back()->clip_rect = |
| gfx::Rect(128, 128, 128, 128); |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(0U, overlay_list.size()); |
| EXPECT_EQ(0U, ca_layer_list.size()); |
| } |
| |
| TEST_F(CALayerOverlayTest, DisallowNontrivialClip) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->is_clipped = true; |
| pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(64, 64, 128, 128); |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(1U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(1U, overlay_list.size()); |
| EXPECT_EQ(0U, ca_layer_list.size()); |
| } |
| |
| TEST_F(CALayerOverlayTest, SkipTransparent) { |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| pass->shared_quad_state_list.back()->opacity = 0; |
| |
| gfx::Rect damage_rect; |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| CALayerOverlayList ca_layer_list; |
| OverlayCandidateList overlay_list( |
| BackbufferOverlayList(pass_list.back().get())); |
| overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list, |
| &overlay_list, &ca_layer_list, |
| &damage_rect); |
| ASSERT_EQ(1U, pass_list.size()); |
| EXPECT_EQ(0U, pass_list.back()->quad_list.size()); |
| EXPECT_EQ(0U, overlay_list.size()); |
| EXPECT_EQ(0U, ca_layer_list.size()); |
| } |
| |
| class OverlayInfoRendererGL : public GLRenderer { |
| public: |
| OverlayInfoRendererGL(RendererClient* client, |
| const RendererSettings* settings, |
| OutputSurface* output_surface, |
| ResourceProvider* resource_provider) |
| : GLRenderer(client, |
| settings, |
| output_surface, |
| resource_provider, |
| NULL, |
| 0), |
| expect_overlays_(false) {} |
| |
| MOCK_METHOD3(DoDrawQuad, |
| void(DrawingFrame* frame, |
| const DrawQuad* quad, |
| const gfx::QuadF* draw_region)); |
| |
| using GLRenderer::BeginDrawingFrame; |
| |
| void FinishDrawingFrame(DrawingFrame* frame) override { |
| GLRenderer::FinishDrawingFrame(frame); |
| |
| if (!expect_overlays_) { |
| EXPECT_EQ(0U, frame->overlay_list.size()); |
| return; |
| } |
| |
| ASSERT_EQ(2U, frame->overlay_list.size()); |
| EXPECT_GE(frame->overlay_list.back().resource_id, 0U); |
| } |
| |
| void set_expect_overlays(bool expect_overlays) { |
| expect_overlays_ = expect_overlays; |
| } |
| |
| private: |
| bool expect_overlays_; |
| }; |
| |
| class FakeRendererClient : public RendererClient { |
| public: |
| // RendererClient methods. |
| void SetFullRootLayerDamage() override {} |
| }; |
| |
| class MockOverlayScheduler { |
| public: |
| MOCK_METHOD5(Schedule, |
| void(int plane_z_order, |
| gfx::OverlayTransform plane_transform, |
| unsigned overlay_texture_id, |
| const gfx::Rect& display_bounds, |
| const gfx::RectF& uv_rect)); |
| }; |
| |
| class GLRendererWithOverlaysTest : public testing::Test { |
| protected: |
| GLRendererWithOverlaysTest() { |
| provider_ = TestContextProvider::Create(); |
| output_surface_.reset(new OverlayOutputSurface(provider_)); |
| CHECK(output_surface_->BindToClient(&output_surface_client_)); |
| resource_provider_ = |
| FakeResourceProvider::Create(output_surface_.get(), nullptr); |
| |
| provider_->support()->SetScheduleOverlayPlaneCallback(base::Bind( |
| &MockOverlayScheduler::Schedule, base::Unretained(&scheduler_))); |
| } |
| |
| void Init(bool use_validator) { |
| if (use_validator) |
| output_surface_->SetOverlayCandidateValidator(new SingleOverlayValidator); |
| |
| renderer_ = |
| make_scoped_ptr(new OverlayInfoRendererGL(&renderer_client_, |
| &settings_, |
| output_surface_.get(), |
| resource_provider_.get())); |
| } |
| |
| void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } |
| |
| RendererSettings settings_; |
| FakeOutputSurfaceClient output_surface_client_; |
| scoped_ptr<OverlayOutputSurface> output_surface_; |
| FakeRendererClient renderer_client_; |
| scoped_ptr<ResourceProvider> resource_provider_; |
| scoped_ptr<OverlayInfoRendererGL> renderer_; |
| scoped_refptr<TestContextProvider> provider_; |
| MockOverlayScheduler scheduler_; |
| }; |
| |
| TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) { |
| bool use_validator = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| gfx::Rect viewport_rect(16, 16); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateCandidateQuadAt(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get(), |
| kOverlayBottomRightRect); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Candidate pass was taken out and extra skipped pass added, |
| // so only draw 2 quads. |
| EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(2); |
| EXPECT_CALL(scheduler_, |
| Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, |
| gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) |
| .Times(1); |
| EXPECT_CALL(scheduler_, Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, |
| kOverlayBottomRightRect, |
| BoundingRect(kUVTopLeft, kUVBottomRight))) |
| .Times(1); |
| renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); |
| |
| SwapBuffers(); |
| |
| Mock::VerifyAndClearExpectations(renderer_.get()); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) { |
| bool use_validator = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| gfx::Rect viewport_rect(16, 16); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Candidate quad should fail to be overlaid on top because of occlusion. |
| // Expect to be replaced with transparent hole quad and placed in underlay. |
| EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3); |
| EXPECT_CALL(scheduler_, |
| Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, |
| gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) |
| .Times(1); |
| EXPECT_CALL(scheduler_, |
| Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect, |
| BoundingRect(kUVTopLeft, kUVBottomRight))) |
| .Times(1); |
| renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); |
| |
| SwapBuffers(); |
| |
| Mock::VerifyAndClearExpectations(renderer_.get()); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) { |
| bool use_validator = false; |
| Init(use_validator); |
| renderer_->set_expect_overlays(false); |
| gfx::Rect viewport_rect(16, 16); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| // Should not see the primary surface's overlay. |
| output_surface_->set_is_displayed_as_overlay_plane(false); |
| EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3); |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(renderer_.get()); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| // GLRenderer skips drawing occluded quads when partial swap is enabled. |
| TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) { |
| provider_->TestContext3d()->set_have_post_sub_buffer(true); |
| settings_.partial_swap_enabled = true; |
| bool use_validator = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| gfx::Rect viewport_rect(16, 16); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| output_surface_->set_is_displayed_as_overlay_plane(true); |
| EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(0); |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(renderer_.get()); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| // GLRenderer skips drawing occluded quads when empty swap is enabled. |
| TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) { |
| provider_->TestContext3d()->set_have_commit_overlay_planes(true); |
| bool use_validator = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| gfx::Rect viewport_rect(16, 16); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| |
| CreateFullscreenCandidateQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), |
| pass.get()); |
| |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| CreateFullscreenOpaqueQuad(resource_provider_.get(), |
| pass->shared_quad_state_list.back(), pass.get()); |
| |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| output_surface_->set_is_displayed_as_overlay_plane(true); |
| EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(0); |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(renderer_.get()); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { |
| bool use_validator = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| |
| ResourceId resource1 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| ResourceId resource2 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| ResourceId resource3 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| DirectRenderer::DrawingFrame frame1; |
| frame1.render_passes_in_draw_order = &pass_list; |
| frame1.overlay_list.resize(2); |
| frame1.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay1 = frame1.overlay_list.back(); |
| overlay1.resource_id = resource1; |
| overlay1.plane_z_order = 1; |
| |
| DirectRenderer::DrawingFrame frame2; |
| frame2.render_passes_in_draw_order = &pass_list; |
| frame2.overlay_list.resize(2); |
| frame2.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay2 = frame2.overlay_list.back(); |
| overlay2.resource_id = resource2; |
| overlay2.plane_z_order = 1; |
| |
| DirectRenderer::DrawingFrame frame3; |
| frame3.render_passes_in_draw_order = &pass_list; |
| frame3.overlay_list.resize(2); |
| frame3.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay3 = frame3.overlay_list.back(); |
| overlay3.resource_id = resource3; |
| overlay3.plane_z_order = 1; |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame2); |
| renderer_->FinishDrawingFrame(&frame2); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame3); |
| renderer_->FinishDrawingFrame(&frame3); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| SwapBuffers(); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| // No overlays, release the resource. |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| DirectRenderer::DrawingFrame frame_no_overlays; |
| frame_no_overlays.render_passes_in_draw_order = &pass_list; |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| SwapBuffers(); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| // Use the same buffer twice. |
| renderer_->set_expect_overlays(true); |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithExtraDelay) { |
| bool use_validator = true; |
| settings_.delay_releasing_overlay_resources = true; |
| Init(use_validator); |
| renderer_->set_expect_overlays(true); |
| |
| ResourceId resource1 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| ResourceId resource2 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| ResourceId resource3 = |
| CreateResource(resource_provider_.get(), gfx::Size(32, 32), true); |
| |
| scoped_ptr<RenderPass> pass = CreateRenderPass(); |
| RenderPassList pass_list; |
| pass_list.push_back(std::move(pass)); |
| |
| DirectRenderer::DrawingFrame frame1; |
| frame1.render_passes_in_draw_order = &pass_list; |
| frame1.overlay_list.resize(2); |
| frame1.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay1 = frame1.overlay_list.back(); |
| overlay1.resource_id = resource1; |
| overlay1.plane_z_order = 1; |
| |
| DirectRenderer::DrawingFrame frame2; |
| frame2.render_passes_in_draw_order = &pass_list; |
| frame2.overlay_list.resize(2); |
| frame2.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay2 = frame2.overlay_list.back(); |
| overlay2.resource_id = resource2; |
| overlay2.plane_z_order = 1; |
| |
| DirectRenderer::DrawingFrame frame3; |
| frame3.render_passes_in_draw_order = &pass_list; |
| frame3.overlay_list.resize(2); |
| frame3.overlay_list.front().use_output_surface_for_resource = true; |
| OverlayCandidate& overlay3 = frame3.overlay_list.back(); |
| overlay3.resource_id = resource3; |
| overlay3.plane_z_order = 1; |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame2); |
| renderer_->FinishDrawingFrame(&frame2); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame3); |
| renderer_->FinishDrawingFrame(&frame3); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| // No overlays, release the resource. |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| DirectRenderer::DrawingFrame frame_no_overlays; |
| frame_no_overlays.render_passes_in_draw_order = &pass_list; |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| SwapBuffers(); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| // Use the same buffer twice. |
| renderer_->set_expect_overlays(true); |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); |
| renderer_->BeginDrawingFrame(&frame1); |
| renderer_->FinishDrawingFrame(&frame1); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| |
| EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); |
| renderer_->set_expect_overlays(false); |
| renderer_->BeginDrawingFrame(&frame_no_overlays); |
| renderer_->FinishDrawingFrame(&frame_no_overlays); |
| EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); |
| SwapBuffers(); |
| EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); |
| Mock::VerifyAndClearExpectations(&scheduler_); |
| } |
| |
| } // namespace |
| } // namespace cc |