普通文本  |  791行  |  28.84 KB

// 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::Rect kOverlayTopLeftRect(0, 0, 64, 64);
const gfx::Rect kOverlayBottomRightRect(64, 64, 64, 64);
const gfx::PointF kUVTopLeft(0.1f, 0.2f);
const gfx::PointF kUVBottomRight(1.0f, 1.0f);

void MailboxReleased(unsigned sync_point,
                     bool lost_resource,
                     BlockingTaskRunner* main_thread_task_runner) {
}

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();
  if (candidate.display_rect.width() == 64)
    EXPECT_EQ(kOverlayBottomRightRect, candidate.display_rect);
  else
    EXPECT_EQ(kOverlayRect, candidate.display_rect);
  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<Strategy>(
      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<ContextProvider> context_provider)
      : OutputSurface(context_provider) {}

  void InitWithSingleOverlayValidator() {
    overlay_candidate_validator_.reset(new SingleOverlayValidator);
  }
};

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.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<SingleReleaseCallbackImpl> release_callback =
      SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));

  return resource_provider->CreateResourceFromTextureMailbox(
      mailbox, release_callback.Pass());
}

TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider,
                                       const SharedQuadState* shared_quad_state,
                                       RenderPass* render_pass,
                                       const gfx::Rect& rect) {
  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};

  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);

  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);
}

void CreateCheckeredQuadAt(ResourceProvider* resource_provider,
                           const SharedQuadState* shared_quad_state,
                           RenderPass* render_pass,
                           const gfx::Rect& rect) {
  CheckerboardDrawQuad* checkerboard_quad =
      render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
  checkerboard_quad->SetNew(shared_quad_state, rect, rect, SkColor());
}

void CreateFullscreenCheckeredQuad(ResourceProvider* resource_provider,
                                   const SharedQuadState* shared_quad_state,
                                   RenderPass* render_pass) {
  CreateCheckeredQuadAt(
      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];
    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 (QuadList::Iterator exp_iter = expected->quad_list.begin(),
                            act_iter = actual->quad_list.begin();
         exp_iter != expected->quad_list.end();
         ++exp_iter, ++act_iter) {
      EXPECT_EQ(exp_iter->rect.ToString(), act_iter->rect.ToString());
      EXPECT_EQ(exp_iter->shared_quad_state->content_bounds.ToString(),
                act_iter->shared_quad_state->content_bounds.ToString());
    }
  }
}

TEST(OverlayTest, NoOverlaysByDefault) {
  scoped_refptr<TestContextProvider> 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<TestContextProvider> 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<SharedBitmapManager> shared_bitmap_manager(
      new TestSharedBitmapManager());
  scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
      &output_surface, shared_bitmap_manager.get(), NULL, 0, false, 1, false));

  scoped_ptr<DefaultOverlayProcessor> 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(),
                                                  NULL,
                                                  0,
                                                  false,
                                                  1,
                                                  false);

    overlay_processor_.reset(new SingleOverlayProcessor(
        output_surface_.get(), resource_provider_.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<SingleOverlayProcessor> overlay_processor_;
};

TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) {
  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.
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  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_resource_id, candidate_list.back().resource_id);
}

TEST_F(SingleOverlayOnTopTest, NoCandidates) {
  scoped_ptr<RenderPass> pass = CreateRenderPass();
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  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<RenderPass> pass = CreateRenderPass();
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(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(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<RenderPass> pass = CreateRenderPass();
  CreateFullscreenCandidateQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  // Add something behind it.
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  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<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(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<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(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<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(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<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(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<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(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<RenderPass> pass = CreateRenderPass();
  CreateFullscreenCandidateQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.f,
                                                                         2.f);

  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, AllowNotTopIfNotOccluded) {
  scoped_ptr<RenderPass> pass = CreateRenderPass();
  CreateCheckeredQuadAt(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(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(1U, pass_list.size());
  EXPECT_EQ(2U, 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, 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<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();

  CreateFullscreenCandidateQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  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<RenderPass> pass = CreateRenderPass();

  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(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(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<RenderPass> pass = CreateRenderPass();

  CreateFullscreenCandidateQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());
  CreateFullscreenCheckeredQuad(resource_provider_.get(),
                                pass->shared_quad_state_list.back(),
                                pass.get());

  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