// 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 "cc/base/scoped_ptr_vector.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_single_on_top.h" #include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/render_pass.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/geometry_test_utils.h" #include "cc/test/test_context_provider.h" #include "cc/test/test_shared_bitmap_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::_; using testing::Mock; namespace cc { namespace { const gfx::Rect kOverlayRect(0, 0, 128, 128); const gfx::PointF kUVTopLeft(0.1f, 0.2f); const gfx::PointF kUVBottomRight(1.0f, 1.0f); void MailboxReleased(unsigned sync_point, bool lost_resource) {} class SingleOverlayValidator : public OverlayCandidateValidator { public: virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) OVERRIDE; }; void SingleOverlayValidator::CheckOverlaySupport( OverlayCandidateList* surfaces) { ASSERT_EQ(2U, surfaces->size()); OverlayCandidate& candidate = surfaces->back(); EXPECT_EQ(kOverlayRect.ToString(), candidate.display_rect.ToString()); EXPECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight).ToString(), candidate.uv_rect.ToString()); candidate.overlay_handled = true; } class SingleOverlayProcessor : public OverlayProcessor { public: SingleOverlayProcessor(OutputSurface* surface, ResourceProvider* resource_provider); // Virtual to allow testing different strategies. virtual void Initialize() OVERRIDE; }; SingleOverlayProcessor::SingleOverlayProcessor( OutputSurface* surface, ResourceProvider* resource_provider) : OverlayProcessor(surface, resource_provider) { EXPECT_EQ(surface, surface_); EXPECT_EQ(resource_provider, resource_provider_); } void SingleOverlayProcessor::Initialize() { OverlayCandidateValidator* candidates = surface_->overlay_candidate_validator(); ASSERT_TRUE(candidates != NULL); strategies_.push_back(scoped_ptr( new OverlayStrategySingleOnTop(candidates, resource_provider_))); } class DefaultOverlayProcessor : public OverlayProcessor { public: DefaultOverlayProcessor(OutputSurface* surface, ResourceProvider* resource_provider); size_t GetStrategyCount(); }; DefaultOverlayProcessor::DefaultOverlayProcessor( OutputSurface* surface, ResourceProvider* resource_provider) : OverlayProcessor(surface, resource_provider) {} size_t DefaultOverlayProcessor::GetStrategyCount() { return strategies_.size(); } class OverlayOutputSurface : public OutputSurface { public: explicit OverlayOutputSurface(scoped_refptr context_provider) : OutputSurface(context_provider) {} void InitWithSingleOverlayValidator() { overlay_candidate_validator_.reset(new SingleOverlayValidator); } }; scoped_ptr CreateRenderPass() { RenderPass::Id id(1, 0); gfx::Rect output_rect(0, 0, 256, 256); bool has_transparent_background = true; scoped_ptr 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.Pass(); } ResourceProvider::ResourceId CreateResource( ResourceProvider* resource_provider) { unsigned sync_point = 0; TextureMailbox mailbox = TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point); mailbox.set_allow_overlay(true); scoped_ptr release_callback = SingleReleaseCallback::Create(base::Bind(&MailboxReleased)); return resource_provider->CreateResourceFromTextureMailbox( mailbox, release_callback.Pass()); } scoped_ptr CreateCandidateQuad( ResourceProvider* resource_provider, const SharedQuadState* shared_quad_state) { ResourceProvider::ResourceId resource_id = CreateResource(resource_provider); bool premultiplied_alpha = false; bool flipped = false; float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; scoped_ptr overlay_quad = TextureDrawQuad::Create(); overlay_quad->SetNew(shared_quad_state, kOverlayRect, kOverlayRect, kOverlayRect, resource_id, premultiplied_alpha, kUVTopLeft, kUVBottomRight, SK_ColorTRANSPARENT, vertex_opacity, flipped); return overlay_quad.Pass(); } scoped_ptr CreateCheckeredQuad( ResourceProvider* resource_provider, const SharedQuadState* shared_quad_state) { scoped_ptr checkerboard_quad = CheckerboardDrawQuad::Create(); checkerboard_quad->SetNew( shared_quad_state, kOverlayRect, kOverlayRect, SkColor()); return checkerboard_quad.PassAs(); } 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]; RenderPass* actual = actual_list[i]; EXPECT_EQ(expected->id, actual->id); EXPECT_RECT_EQ(expected->output_rect, actual->output_rect); EXPECT_EQ(expected->transform_to_root_target, actual->transform_to_root_target); EXPECT_RECT_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 (size_t i = 0; i < expected->quad_list.size(); ++i) { EXPECT_EQ(expected->quad_list[i]->rect.ToString(), actual->quad_list[i]->rect.ToString()); EXPECT_EQ( expected->quad_list[i]->shared_quad_state->content_bounds.ToString(), actual->quad_list[i]->shared_quad_state->content_bounds.ToString()); } } } TEST(OverlayTest, NoOverlaysByDefault) { scoped_refptr provider = TestContextProvider::Create(); OverlayOutputSurface output_surface(provider); EXPECT_EQ(NULL, output_surface.overlay_candidate_validator()); output_surface.InitWithSingleOverlayValidator(); EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL); } TEST(OverlayTest, OverlaysProcessorHasStrategy) { scoped_refptr provider = TestContextProvider::Create(); OverlayOutputSurface output_surface(provider); FakeOutputSurfaceClient client; EXPECT_TRUE(output_surface.BindToClient(&client)); output_surface.InitWithSingleOverlayValidator(); EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL); scoped_ptr shared_bitmap_manager( new TestSharedBitmapManager()); scoped_ptr resource_provider(ResourceProvider::Create( &output_surface, shared_bitmap_manager.get(), 0, false, 1, false)); scoped_ptr overlay_processor( new DefaultOverlayProcessor(&output_surface, resource_provider.get())); overlay_processor->Initialize(); EXPECT_GE(1U, overlay_processor->GetStrategyCount()); } class SingleOverlayOnTopTest : public testing::Test { protected: virtual void SetUp() { provider_ = TestContextProvider::Create(); output_surface_.reset(new OverlayOutputSurface(provider_)); EXPECT_TRUE(output_surface_->BindToClient(&client_)); output_surface_->InitWithSingleOverlayValidator(); EXPECT_TRUE(output_surface_->overlay_candidate_validator() != NULL); shared_bitmap_manager_.reset(new TestSharedBitmapManager()); resource_provider_ = ResourceProvider::Create( output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, false); overlay_processor_.reset(new SingleOverlayProcessor( output_surface_.get(), resource_provider_.get())); overlay_processor_->Initialize(); } scoped_refptr provider_; scoped_ptr output_surface_; FakeOutputSurfaceClient client_; scoped_ptr shared_bitmap_manager_; scoped_ptr resource_provider_; scoped_ptr overlay_processor_; }; TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { scoped_ptr pass = CreateRenderPass(); scoped_ptr original_quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); pass->quad_list.push_back( original_quad->Copy(pass->shared_quad_state_list.back())); // Add something behind it. pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); RenderPassList pass_list; pass_list.push_back(pass.Pass()); // Check for potential candidates. OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); ASSERT_EQ(2U, candidate_list.size()); RenderPass* main_pass = pass_list.back(); // 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_quad->resource_id, candidate_list.back().resource_id); } TEST_F(SingleOverlayOnTopTest, NoCandidates) { scoped_ptr pass = CreateRenderPass(); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); RenderPassList pass_list; pass_list.push_back(pass.Pass()); RenderPassList original_pass_list; RenderPass::CopyAll(pass_list, &original_pass_list); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(0U, candidate_list.size()); // There should be nothing new here. CompareRenderPassLists(pass_list, original_pass_list); } TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { scoped_ptr pass = CreateRenderPass(); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back( CreateCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back()) .PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); RenderPassList original_pass_list; RenderPass::CopyAll(pass_list, &original_pass_list); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); 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 pass = CreateRenderPass(); scoped_ptr original_quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); pass->quad_list.push_back( original_quad->Copy(pass->shared_quad_state_list.back())); // Add something behind it. pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass_list.push_back(pass.Pass()); RenderPassList original_pass_list; RenderPass::CopyAll(pass_list, &original_pass_list); // Check for potential candidates. OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(2U, candidate_list.size()); // This should be the same. ASSERT_EQ(2U, pass_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectPremultipliedAlpha) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); quad->premultiplied_alpha = true; pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectBlending) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); quad->needs_blending = true; pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); quad->background_color = SK_ColorBLACK; pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectBlendMode) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); pass->shared_quad_state_list.back()->blend_mode = SkXfermode::kScreen_Mode; pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectOpacity) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); pass->shared_quad_state_list.back()->opacity = 0.5f; pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectTransform) { scoped_ptr pass = CreateRenderPass(); scoped_ptr quad = CreateCandidateQuad( resource_provider_.get(), pass->shared_quad_state_list.back()); pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.f, 2.f); pass->quad_list.push_back(quad.PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); EXPECT_EQ(0U, candidate_list.size()); } class OverlayInfoRendererGL : public GLRenderer { public: OverlayInfoRendererGL(RendererClient* client, const LayerTreeSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) : GLRenderer(client, settings, output_surface, resource_provider, NULL, 0), expect_overlays_(false) {} MOCK_METHOD2(DoDrawQuad, void(DrawingFrame* frame, const DrawQuad* quad)); virtual 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_NE(0U, frame->overlay_list.back().resource_id); } void set_expect_overlays(bool expect_overlays) { expect_overlays_ = expect_overlays; } private: bool expect_overlays_; }; class FakeRendererClient : public RendererClient { public: // RendererClient methods. virtual 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_ = ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1, false); provider_->support()->SetScheduleOverlayPlaneCallback(base::Bind( &MockOverlayScheduler::Schedule, base::Unretained(&scheduler_))); } void Init(bool use_validator) { if (use_validator) output_surface_->InitWithSingleOverlayValidator(); renderer_ = make_scoped_ptr(new OverlayInfoRendererGL(&renderer_client_, &settings_, output_surface_.get(), resource_provider_.get())); } void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); } LayerTreeSettings settings_; FakeOutputSurfaceClient output_surface_client_; scoped_ptr output_surface_; FakeRendererClient renderer_client_; scoped_ptr resource_provider_; scoped_ptr renderer_; scoped_refptr 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 pass = CreateRenderPass(); pass->quad_list.push_back( CreateCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back()) .PassAs()); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); RenderPassList pass_list; pass_list.push_back(pass.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(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, OccludedQuadDrawn) { bool use_validator = true; Init(use_validator); renderer_->set_expect_overlays(false); gfx::Rect viewport_rect(16, 16); scoped_ptr pass = CreateRenderPass(); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back( CreateCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back()) .PassAs()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); // 3 quads in the pass, all should draw. 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_); } TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) { bool use_validator = false; Init(use_validator); renderer_->set_expect_overlays(false); gfx::Rect viewport_rect(16, 16); scoped_ptr pass = CreateRenderPass(); pass->quad_list.push_back( CreateCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back()) .PassAs()); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); pass->quad_list.push_back(CreateCheckeredQuad( resource_provider_.get(), pass->shared_quad_state_list.back())); RenderPassList pass_list; pass_list.push_back(pass.Pass()); // Should see no overlays. 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_); } TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { bool use_validator = true; Init(use_validator); renderer_->set_expect_overlays(true); ResourceProvider::ResourceId resource1 = CreateResource(resource_provider_.get()); ResourceProvider::ResourceId resource2 = CreateResource(resource_provider_.get()); DirectRenderer::DrawingFrame frame1; frame1.overlay_list.resize(2); OverlayCandidate& overlay1 = frame1.overlay_list.back(); overlay1.resource_id = resource1; overlay1.plane_z_order = 1; DirectRenderer::DrawingFrame frame2; frame2.overlay_list.resize(2); OverlayCandidate& overlay2 = frame2.overlay_list.back(); overlay2.resource_id = resource2; overlay2.plane_z_order = 1; EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); SwapBuffers(); Mock::VerifyAndClearExpectations(&scheduler_); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); renderer_->FinishDrawingFrame(&frame2); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); SwapBuffers(); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); Mock::VerifyAndClearExpectations(&scheduler_); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); SwapBuffers(); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); Mock::VerifyAndClearExpectations(&scheduler_); // No overlays, release the resource. EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); DirectRenderer::DrawingFrame frame3; renderer_->set_expect_overlays(false); renderer_->FinishDrawingFrame(&frame3); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); SwapBuffers(); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); Mock::VerifyAndClearExpectations(&scheduler_); // Use the same buffer twice. renderer_->set_expect_overlays(true); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); SwapBuffers(); Mock::VerifyAndClearExpectations(&scheduler_); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); 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_->FinishDrawingFrame(&frame3); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); SwapBuffers(); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); Mock::VerifyAndClearExpectations(&scheduler_); } } // namespace } // namespace cc