Index: cc/output/overlay_unittest.cc |
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ab22cb485508442ad778d6188befc7fb53f5d2ef |
--- /dev/null |
+++ b/cc/output/overlay_unittest.cc |
@@ -0,0 +1,426 @@ |
+// 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/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 "testing/gtest/include/gtest/gtest.h" |
+ |
+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<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() { |
+ RenderPass::Id 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, |
+ RenderPass::NO_OVERLAY); |
+ |
+ scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create(); |
+ shared_state->opacity = 1.f; |
+ pass->shared_quad_state_list.push_back(shared_state.Pass()); |
+ return pass.Pass(); |
+} |
+ |
+scoped_ptr<TextureDrawQuad> CreateCandidateQuad( |
+ ResourceProvider* resource_provider, |
+ const SharedQuadState* shared_quad_state) { |
+ unsigned sync_point = 0; |
+ TextureMailbox mailbox = |
+ TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point); |
+ mailbox.set_allow_overlay(true); |
+ scoped_ptr<SingleReleaseCallback> release_callback = |
+ SingleReleaseCallback::Create(base::Bind(&MailboxReleased)); |
+ |
+ ResourceProvider::ResourceId resource_id = |
+ resource_provider->CreateResourceFromTextureMailbox( |
+ mailbox, release_callback.Pass()); |
+ bool premultiplied_alpha = false; |
+ bool flipped = false; |
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
+ |
+ scoped_ptr<TextureDrawQuad> 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<DrawQuad> CreateCheckeredQuad( |
+ ResourceProvider* resource_provider, |
+ const SharedQuadState* shared_quad_state) { |
+ scoped_ptr<CheckerboardDrawQuad> checkerboard_quad = |
+ CheckerboardDrawQuad::Create(); |
+ checkerboard_quad->SetNew( |
+ shared_quad_state, kOverlayRect, kOverlayRect, SkColor()); |
+ return checkerboard_quad.PassAs<DrawQuad>(); |
+} |
+ |
+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->overlay_state, actual->overlay_state); |
+ |
+ 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<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<ResourceProvider> resource_provider( |
+ ResourceProvider::Create(&output_surface, NULL, 0, false, 1)); |
+ |
+ 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); |
+ |
+ resource_provider_ = |
+ ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1); |
+ |
+ 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<ResourceProvider> resource_provider_; |
+ scoped_ptr<SingleOverlayProcessor> overlay_processor_; |
+}; |
+ |
+TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> 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. |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ |
+ // This should have one more pass with an overlay. |
+ ASSERT_EQ(2U, pass_list.size()); |
+ |
+ RenderPass* overlay_pass = pass_list.front(); |
+ EXPECT_EQ(RenderPass::SIMPLE_OVERLAY, overlay_pass->overlay_state); |
+ RenderPass* main_pass = pass_list.back(); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, main_pass->overlay_state); |
+ |
+ // Check that the quad is what we expect it to be. |
+ EXPECT_EQ(1U, overlay_pass->quad_list.size()); |
+ const DrawQuad* overlay_quad = overlay_pass->quad_list.front(); |
+ EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, overlay_quad->material); |
+ EXPECT_EQ(original_quad->resource_id, |
+ TextureDrawQuad::MaterialCast(overlay_quad)->resource_id); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, NoCandidates) { |
+ scoped_ptr<RenderPass> 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); |
+ |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ // There should be nothing new here. |
+ CompareRenderPassLists(pass_list, original_pass_list); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { |
+ scoped_ptr<RenderPass> 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<DrawQuad>()); |
+ |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ |
+ RenderPassList original_pass_list; |
+ RenderPass::CopyAll(pass_list, &original_pass_list); |
+ |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ // 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(); |
+ scoped_ptr<TextureDrawQuad> 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()); |
+ |
+ // Check for potential candidates. |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ |
+ // This should have one more pass with an overlay. |
+ ASSERT_EQ(3U, pass_list.size()); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectPremultipliedAlpha) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad( |
+ resource_provider_.get(), pass->shared_quad_state_list.back()); |
+ quad->premultiplied_alpha = true; |
+ |
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectBlending) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad( |
+ resource_provider_.get(), pass->shared_quad_state_list.back()); |
+ quad->needs_blending = true; |
+ |
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad( |
+ resource_provider_.get(), pass->shared_quad_state_list.back()); |
+ quad->background_color = SK_ColorBLACK; |
+ |
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectBlendMode) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> 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<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectOpacity) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> 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<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+TEST_F(SingleOverlayOnTopTest, RejectTransform) { |
+ scoped_ptr<RenderPass> pass = CreateRenderPass(); |
+ scoped_ptr<TextureDrawQuad> 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<DrawQuad>()); |
+ RenderPassList pass_list; |
+ pass_list.push_back(pass.Pass()); |
+ overlay_processor_->ProcessForOverlays(&pass_list); |
+ ASSERT_EQ(1U, pass_list.size()); |
+ EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); |
+} |
+ |
+} // namespace |
+} // namespace cc |