diff --git a/cc/cc.gyp b/cc/cc.gyp index b5b1dde9d9c3bf..23123729cbe4ad 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp @@ -265,6 +265,13 @@ 'output/output_surface.cc', 'output/output_surface.h', 'output/output_surface_client.h', + 'output/overlay_candidate.cc', + 'output/overlay_candidate.h', + 'output/overlay_candidate_validator.h', + 'output/overlay_processor.cc', + 'output/overlay_processor.h', + 'output/overlay_strategy_single_on_top.cc', + 'output/overlay_strategy_single_on_top.h', 'output/program_binding.cc', 'output/program_binding.h', 'output/render_surface_filters.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index f4b84bab7ced67..7c29f9cf818a26 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -53,6 +53,7 @@ 'output/filter_operations_unittest.cc', 'output/gl_renderer_unittest.cc', 'output/output_surface_unittest.cc', + 'output/overlay_unittest.cc', 'output/renderer_pixeltest.cc', 'output/shader_unittest.cc', 'output/software_renderer_unittest.cc', diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index b751f06c9416b1..5bec9d1153eedb 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -14,6 +14,7 @@ #include "cc/base/cc_export.h" #include "cc/base/rolling_time_delta_history.h" #include "cc/output/context_provider.h" +#include "cc/output/overlay_candidate_validator.h" #include "cc/output/software_output_device.h" #include "cc/scheduler/frame_rate_controller.h" @@ -139,6 +140,11 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // device is present, returns 0. base::TimeDelta GpuLatencyEstimate(); + // Get the class capable of informing cc of hardware overlay capability. + OverlayCandidateValidator* overlay_candidate_validator() const { + return overlay_candidate_validator_.get(); + } + protected: // Synchronously initialize context3d and enter hardware mode. // This can only supported in threaded compositing mode. @@ -154,6 +160,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { struct OutputSurface::Capabilities capabilities_; scoped_refptr context_provider_; scoped_ptr software_device_; + scoped_ptr overlay_candidate_validator_; gfx::Size surface_size_; float device_scale_factor_; diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc new file mode 100644 index 00000000000000..dd3ebc27ef05c7 --- /dev/null +++ b/cc/output/overlay_candidate.cc @@ -0,0 +1,17 @@ +// 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/output/overlay_candidate_validator.h" + +namespace cc { + +OverlayCandidate::OverlayCandidate() + : transform(NONE), + format(RGBA_8888), + uv_rect(0.f, 0.f, 1.f, 1.f), + overlay_handled(false) {} + +OverlayCandidate::~OverlayCandidate() {} + +} // namespace cc diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h new file mode 100644 index 00000000000000..c53013630d66aa --- /dev/null +++ b/cc/output/overlay_candidate.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef CC_OUTPUT_OVERLAY_CANDIDATE_H_ +#define CC_OUTPUT_OVERLAY_CANDIDATE_H_ + +#include + +#include "base/basictypes.h" +#include "cc/base/cc_export.h" +#include "cc/resources/resource_format.h" +#include "ui/gfx/geometry/rect.h" + +namespace cc { + +struct CC_EXPORT OverlayCandidate { + enum OverlayTransform { + NONE, + FLIP_HORIZONTAL, + FLIP_VERTICAL, + ROTATE_90, + ROTATE_180, + ROTATE_270, + }; + + OverlayCandidate(); + ~OverlayCandidate(); + + // Transformation to apply to layer during composition. + OverlayTransform transform; + // Format of the buffer to composite. + ResourceFormat format; + // Rect on the display to position the overlay to. + gfx::Rect display_rect; + // Crop within the buffer to be placed inside |display_rect|. + gfx::RectF uv_rect; + + // To be modified by the implementer if this candidate can go into + // an overlay. + bool overlay_handled; +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_CANDIDATE_H_ diff --git a/cc/output/overlay_candidate_validator.h b/cc/output/overlay_candidate_validator.h new file mode 100644 index 00000000000000..026f4f3b696b78 --- /dev/null +++ b/cc/output/overlay_candidate_validator.h @@ -0,0 +1,35 @@ +// 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. + +#ifndef CC_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_ +#define CC_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_ + +#include + +#include "base/basictypes.h" +#include "cc/base/cc_export.h" +#include "cc/output/overlay_candidate.h" +#include "cc/resources/resource_format.h" +#include "ui/gfx/geometry/rect.h" + +namespace cc { + +// This class that can be used to answer questions about possible overlay +// configurations for a particular output device. +class CC_EXPORT OverlayCandidateValidator { + public: + typedef std::vector OverlayCandidateList; + + // A list of possible overlay candidates is presented to this function. + // The expected result is that those candidates that can be in a separate + // plane are marked with |overlay_handled| set to true, otherwise they are + // to be traditionally composited. + virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) = 0; + + virtual ~OverlayCandidateValidator() {} +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_ diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc new file mode 100644 index 00000000000000..afdb966fe0133d --- /dev/null +++ b/cc/output/overlay_processor.cc @@ -0,0 +1,42 @@ +// 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/output/overlay_processor.h" + +#include "cc/output/output_surface.h" +#include "cc/output/overlay_strategy_single_on_top.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/texture_draw_quad.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/transform.h" + +namespace cc { + +OverlayProcessor::OverlayProcessor(OutputSurface* surface, + ResourceProvider* resource_provider) + : surface_(surface), resource_provider_(resource_provider) {} + +void OverlayProcessor::Initialize() { + DCHECK(surface_); + DCHECK(resource_provider_); + OverlayCandidateValidator* candidates = + surface_->overlay_candidate_validator(); + if (candidates) { + strategies_.push_back(scoped_ptr( + new OverlayStrategySingleOnTop(candidates, resource_provider_))); + } +} + +OverlayProcessor::~OverlayProcessor() {} + +void OverlayProcessor::ProcessForOverlays( + RenderPassList* render_passes_in_draw_order) { + for (StrategyList::iterator it = strategies_.begin(); it != strategies_.end(); + ++it) { + if ((*it)->Attempt(render_passes_in_draw_order)) + return; + } +} + +} // namespace cc diff --git a/cc/output/overlay_processor.h b/cc/output/overlay_processor.h new file mode 100644 index 00000000000000..41a1f4d915ee85 --- /dev/null +++ b/cc/output/overlay_processor.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef CC_OUTPUT_OVERLAY_PROCESSOR_H_ +#define CC_OUTPUT_OVERLAY_PROCESSOR_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/quads/render_pass.h" + +namespace cc { +class OutputSurface; +class ResourceProvider; + +class CC_EXPORT OverlayProcessor { + public: + class CC_EXPORT Strategy { + public: + virtual ~Strategy() {} + // Returns false if the strategy cannot be made to work with the + // current set of render passes. Returns true if the strategy was successful + // and adds any additional passes necessary to represent overlays to + // |render_passes_in_draw_order|. + virtual bool Attempt(RenderPassList* render_passes_in_draw_order) = 0; + }; + typedef ScopedPtrVector StrategyList; + + OverlayProcessor(OutputSurface* surface, ResourceProvider* resource_provider); + virtual ~OverlayProcessor(); + // Virtual to allow testing different strategies. + virtual void Initialize(); + + void ProcessForOverlays(RenderPassList* render_passes_in_draw_order); + + protected: + StrategyList strategies_; + OutputSurface* surface_; + ResourceProvider* resource_provider_; + + private: + DISALLOW_COPY_AND_ASSIGN(OverlayProcessor); +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_PROCESSOR_H_ diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc new file mode 100644 index 00000000000000..4c2064196ddbca --- /dev/null +++ b/cc/output/overlay_strategy_single_on_top.cc @@ -0,0 +1,81 @@ +// 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/output/overlay_strategy_single_on_top.h" + +#include "cc/output/output_surface.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/texture_draw_quad.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/transform.h" + +namespace cc { + +OverlayStrategySingleOnTop::OverlayStrategySingleOnTop( + OverlayCandidateValidator* capability_checker, + ResourceProvider* resource_provider) + : capability_checker_(capability_checker), + resource_provider_(resource_provider) {} + +bool OverlayStrategySingleOnTop::Attempt( + RenderPassList* render_passes_in_draw_order) { + // Only attempt to handle very simple case for now. + if (!capability_checker_) + return false; + + RenderPass* root_render_pass = render_passes_in_draw_order->back(); + DCHECK(root_render_pass); + + QuadList& quad_list = root_render_pass->quad_list; + const DrawQuad* candidate_quad = quad_list.front(); + if (candidate_quad->material != DrawQuad::TEXTURE_CONTENT) + return false; + + const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(candidate_quad); + if (!resource_provider_->AllowOverlay(quad.resource_id)) + return false; + + // Simple quads only. + if (!quad.quadTransform().IsIdentityOrTranslation() || quad.needs_blending || + quad.shared_quad_state->opacity != 1.f || + quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode || + quad.premultiplied_alpha || quad.background_color != SK_ColorTRANSPARENT) + return false; + + // Add our primary surface. + OverlayCandidateValidator::OverlayCandidateList candidates; + OverlayCandidate main_image; + main_image.display_rect = root_render_pass->output_rect; + main_image.format = RGBA_8888; + candidates.push_back(main_image); + + // Add the overlay. + OverlayCandidate candidate; + gfx::RectF float_rect(quad.rect); + quad.quadTransform().TransformRect(&float_rect); + candidate.transform = + quad.flipped ? OverlayCandidate::FLIP_VERTICAL : OverlayCandidate::NONE; + candidate.display_rect = gfx::ToNearestRect(float_rect); + candidate.uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right); + candidate.format = RGBA_8888; + candidates.push_back(candidate); + + // Check for support. + capability_checker_->CheckOverlaySupport(&candidates); + + // If the candidate can be handled by an overlay, create a pass for it. + if (candidates[1].overlay_handled) { + scoped_ptr overlay_pass = RenderPass::Create(); + overlay_pass->overlay_state = RenderPass::SIMPLE_OVERLAY; + + scoped_ptr overlay_quad = quad_list.take(quad_list.begin()); + quad_list.erase(quad_list.begin()); + overlay_pass->quad_list.push_back(overlay_quad.Pass()); + render_passes_in_draw_order->insert(render_passes_in_draw_order->begin(), + overlay_pass.Pass()); + } + return candidates[1].overlay_handled; +} + +} // namespace cc diff --git a/cc/output/overlay_strategy_single_on_top.h b/cc/output/overlay_strategy_single_on_top.h new file mode 100644 index 00000000000000..99005fd390c6de --- /dev/null +++ b/cc/output/overlay_strategy_single_on_top.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef CC_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_ +#define CC_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/output/overlay_processor.h" +#include "cc/quads/render_pass.h" + +namespace cc { +class OverlayCandidateValidator; + +class CC_EXPORT OverlayStrategySingleOnTop : public OverlayProcessor::Strategy { + public: + OverlayStrategySingleOnTop(OverlayCandidateValidator* capability_checker, + ResourceProvider* resource_provider); + virtual bool Attempt(RenderPassList* render_passes_in_draw_order) OVERRIDE; + + private: + OverlayCandidateValidator* capability_checker_; + ResourceProvider* resource_provider_; + DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop); +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_ diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc new file mode 100644 index 00000000000000..ab22cb48550844 --- /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( + 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, + RenderPass::NO_OVERLAY); + + scoped_ptr shared_state = SharedQuadState::Create(); + shared_state->opacity = 1.f; + pass->shared_quad_state_list.push_back(shared_state.Pass()); + return pass.Pass(); +} + +scoped_ptr 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 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 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->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 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 resource_provider( + ResourceProvider::Create(&output_surface, NULL, 0, false, 1)); + + 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); + + 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 provider_; + scoped_ptr output_surface_; + FakeOutputSurfaceClient client_; + 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. + 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 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 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); + + 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 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()); + + // 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 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()); + 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 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()); + 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 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()); + 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 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()); + 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 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()); + 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 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()); + overlay_processor_->ProcessForOverlays(&pass_list); + ASSERT_EQ(1U, pass_list.size()); + EXPECT_EQ(RenderPass::NO_OVERLAY, pass_list.back()->overlay_state); +} + +} // namespace +} // namespace cc diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc index cdf3b94c3c5635..1eeefe4313d35c 100644 --- a/cc/quads/render_pass.cc +++ b/cc/quads/render_pass.cc @@ -35,14 +35,16 @@ scoped_ptr RenderPass::Create(size_t num_layers) { RenderPass::RenderPass() : id(Id(-1, -1)), - has_transparent_background(true) { + has_transparent_background(true), + overlay_state(NO_OVERLAY) { shared_quad_state_list.reserve(kDefaultNumSharedQuadStatesToReserve); quad_list.reserve(kDefaultNumQuadsToReserve); } RenderPass::RenderPass(size_t num_layers) : id(Id(-1, -1)), - has_transparent_background(true) { + has_transparent_background(true), + overlay_state(NO_OVERLAY) { // Each layer usually produces one shared quad state, so the number of layers // is a good hint for what to reserve here. shared_quad_state_list.reserve(num_layers); @@ -61,7 +63,8 @@ scoped_ptr RenderPass::Copy(Id new_id) const { output_rect, damage_rect, transform_to_root_target, - has_transparent_background); + has_transparent_background, + overlay_state); return copy_pass.Pass(); } @@ -80,7 +83,8 @@ void RenderPass::CopyAll(const ScopedPtrVector& in, source->output_rect, source->damage_rect, source->transform_to_root_target, - source->has_transparent_background); + source->has_transparent_background, + source->overlay_state); for (size_t i = 0; i < source->shared_quad_state_list.size(); ++i) { copy_pass->shared_quad_state_list.push_back( source->shared_quad_state_list[i]->Copy()); @@ -131,7 +135,8 @@ void RenderPass::SetAll(Id id, const gfx::Rect& output_rect, const gfx::RectF& damage_rect, const gfx::Transform& transform_to_root_target, - bool has_transparent_background) { + bool has_transparent_background, + OverlayState overlay_state) { DCHECK_GT(id.layer_id, 0); DCHECK_GE(id.index, 0); @@ -140,6 +145,7 @@ void RenderPass::SetAll(Id id, this->damage_rect = damage_rect; this->transform_to_root_target = transform_to_root_target; this->has_transparent_background = has_transparent_background; + this->overlay_state = overlay_state; DCHECK(quad_list.empty()); DCHECK(shared_quad_state_list.empty()); diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h index 4285e53010311d..5cada2a2f146ac 100644 --- a/cc/quads/render_pass.h +++ b/cc/quads/render_pass.h @@ -62,6 +62,11 @@ class CC_EXPORT RenderPass { } }; + // Specifies whether the pass is going into an overlay, needs to be rendered + // into a buffer before it can be presented to overlay hardware or a quad + // inside it is presented as is. + enum OverlayState { NO_OVERLAY, RENDER_AND_OVERLAY, SIMPLE_OVERLAY, }; + ~RenderPass(); static scoped_ptr Create(); @@ -84,7 +89,8 @@ class CC_EXPORT RenderPass { const gfx::Rect& output_rect, const gfx::RectF& damage_rect, const gfx::Transform& transform_to_root_target, - bool has_transparent_background); + bool has_transparent_background, + OverlayState overlay_state); scoped_ptr AsValue() const; @@ -111,6 +117,8 @@ class CC_EXPORT RenderPass { QuadList quad_list; SharedQuadStateList shared_quad_state_list; + OverlayState overlay_state; + protected: explicit RenderPass(size_t num_layers); RenderPass(); diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc index fd58523ada5829..1305741158f76a 100644 --- a/cc/quads/render_pass_unittest.cc +++ b/cc/quads/render_pass_unittest.cc @@ -31,6 +31,7 @@ struct RenderPassSize { gfx::RectF damage_rect; bool has_transparent_background; ScopedPtrVector copy_callbacks; + RenderPass::OverlayState overlay_state; }; static void CompareRenderPassLists(const RenderPassList& expected_list, @@ -47,6 +48,7 @@ static void CompareRenderPassLists(const RenderPassList& expected_list, 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()); @@ -69,13 +71,15 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; + RenderPass::OverlayState overlay_state = RenderPass::SIMPLE_OVERLAY; scoped_ptr pass = TestRenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, transform_to_root, - has_transparent_background); + has_transparent_background, + overlay_state); pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest()); // Stick a quad in the pass, this should not get copied. @@ -103,6 +107,7 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target); EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect); EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background); + EXPECT_EQ(pass->overlay_state, copy->overlay_state); EXPECT_EQ(0u, copy->quad_list.size()); // The copy request should not be copied/duplicated. @@ -121,13 +126,15 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; + RenderPass::OverlayState overlay_state = RenderPass::SIMPLE_OVERLAY; scoped_ptr pass = TestRenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, transform_to_root, - has_transparent_background); + has_transparent_background, + overlay_state); // Two quads using one shared state. scoped_ptr shared_state1 = SharedQuadState::Create(); @@ -190,13 +197,15 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); gfx::Rect contrib_damage_rect(11, 16, 10, 15); bool contrib_has_transparent_background = true; + RenderPass::OverlayState contrib_overlay_state = RenderPass::SIMPLE_OVERLAY; scoped_ptr contrib = TestRenderPass::Create(); contrib->SetAll(contrib_id, contrib_output_rect, contrib_damage_rect, contrib_transform_to_root, - contrib_has_transparent_background); + contrib_has_transparent_background, + contrib_overlay_state); scoped_ptr contrib_shared_state = SharedQuadState::Create(); contrib_shared_state->SetAll(gfx::Transform(), @@ -249,13 +258,15 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) { gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; + RenderPass::OverlayState overlay_state = RenderPass::SIMPLE_OVERLAY; scoped_ptr pass = TestRenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, transform_to_root, - has_transparent_background); + has_transparent_background, + overlay_state); // A shared state with a quad. scoped_ptr shared_state1 = SharedQuadState::Create(); diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 1cb215bd20993c..55dafbd47d20e3 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -232,6 +232,7 @@ ResourceProvider::Resource::Resource() type(InvalidType), format(RGBA_8888), has_shared_bitmap_id(false), + allow_overlay(false), shared_bitmap(NULL) {} ResourceProvider::Resource::~Resource() {} @@ -610,6 +611,11 @@ bool ResourceProvider::IsLost(ResourceId id) { return resource->lost; } +bool ResourceProvider::AllowOverlay(ResourceId id) { + Resource* resource = GetResource(id); + return resource->allow_overlay; +} + ResourceProvider::ResourceId ResourceProvider::CreateResource( const gfx::Size& size, GLint wrap_mode, @@ -784,6 +790,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( resource.release_callback = base::Bind(&SingleReleaseCallback::Run, base::Owned(release_callback.release())); + resource.allow_overlay = mailbox.allow_overlay(); return id; } diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index 73b5a23dcdf3c2..056ce2fc6f60c9 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h @@ -94,6 +94,7 @@ class CC_EXPORT ResourceProvider { bool InUseByConsumer(ResourceId id); bool IsLost(ResourceId id); + bool AllowOverlay(ResourceId id); // Producer interface. @@ -438,6 +439,7 @@ class CC_EXPORT ResourceProvider { ResourceType type; ResourceFormat format; bool has_shared_bitmap_id; + bool allow_overlay; SharedBitmapId shared_bitmap_id; SharedBitmap* shared_bitmap; linked_ptr direct_raster_buffer; diff --git a/cc/resources/texture_mailbox.cc b/cc/resources/texture_mailbox.cc index a6c2fde43bfc95..a08930d07699a7 100644 --- a/cc/resources/texture_mailbox.cc +++ b/cc/resources/texture_mailbox.cc @@ -12,16 +12,22 @@ namespace cc { TextureMailbox::TextureMailbox() : shared_memory_(NULL) {} TextureMailbox::TextureMailbox(const gpu::MailboxHolder& mailbox_holder) - : mailbox_holder_(mailbox_holder), shared_memory_(NULL) {} + : mailbox_holder_(mailbox_holder), + shared_memory_(NULL), + allow_overlay_(false) {} TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox, uint32 target, uint32 sync_point) - : mailbox_holder_(mailbox, target, sync_point), shared_memory_(NULL) {} + : mailbox_holder_(mailbox, target, sync_point), + shared_memory_(NULL), + allow_overlay_(false) {} TextureMailbox::TextureMailbox(base::SharedMemory* shared_memory, const gfx::Size& size) - : shared_memory_(shared_memory), shared_memory_size_(size) {} + : shared_memory_(shared_memory), + shared_memory_size_(size), + allow_overlay_(false) {} TextureMailbox::~TextureMailbox() {} diff --git a/cc/resources/texture_mailbox.h b/cc/resources/texture_mailbox.h index 229f7a73514889..e29004268f4b87 100644 --- a/cc/resources/texture_mailbox.h +++ b/cc/resources/texture_mailbox.h @@ -40,6 +40,9 @@ class CC_EXPORT TextureMailbox { mailbox_holder_.sync_point = sync_point; } + bool allow_overlay() const { return allow_overlay_; } + void set_allow_overlay(bool allow_overlay) { allow_overlay_ = allow_overlay; } + base::SharedMemory* shared_memory() const { return shared_memory_; } gfx::Size shared_memory_size() const { return shared_memory_size_; } size_t shared_memory_size_in_bytes() const; @@ -48,6 +51,7 @@ class CC_EXPORT TextureMailbox { gpu::MailboxHolder mailbox_holder_; base::SharedMemory* shared_memory_; gfx::Size shared_memory_size_; + bool allow_overlay_; }; } // namespace cc diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index 5b108bb2304e25..4d06101759b7e6 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc @@ -97,7 +97,8 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, source.output_rect, source.damage_rect, source.transform_to_root_target, - source.has_transparent_background); + source.has_transparent_background, + source.overlay_state); // Contributing passes aggregated in to the pass list need to take the // transform of the surface quad into account to update their transform to @@ -203,7 +204,8 @@ void SurfaceAggregator::CopyPasses(const RenderPassList& source_pass_list, source.output_rect, source.damage_rect, source.transform_to_root_target, - source.has_transparent_background); + source.has_transparent_background, + source.overlay_state); CopyQuadsToPass(source.quad_list, source.shared_quad_state_list, diff --git a/content/common/cc_messages.cc b/content/common/cc_messages.cc index fef8ebcd460389..2c6370efc731ea 100644 --- a/content/common/cc_messages.cc +++ b/content/common/cc_messages.cc @@ -285,6 +285,7 @@ void ParamTraits::Log( void ParamTraits::Write( Message* m, const param_type& p) { + DCHECK(p.overlay_state == cc::RenderPass::NO_OVERLAY); WriteParam(m, p.id); WriteParam(m, p.output_rect); WriteParam(m, p.damage_rect); @@ -421,7 +422,8 @@ bool ParamTraits::Read( output_rect, damage_rect, transform_to_root_target, - has_transparent_background); + has_transparent_background, + cc::RenderPass::NO_OVERLAY); size_t last_shared_quad_state_index = kuint32max; for (size_t i = 0; i < quad_list_size; ++i) { diff --git a/content/common/cc_messages_unittest.cc b/content/common/cc_messages_unittest.cc index 7711c23f38c857..8a7f0d849ddfbf 100644 --- a/content/common/cc_messages_unittest.cc +++ b/content/common/cc_messages_unittest.cc @@ -433,7 +433,8 @@ TEST_F(CCMessagesTest, AllQuads) { arbitrary_rect1, arbitrary_rectf1, arbitrary_matrix, - arbitrary_bool1); + arbitrary_bool1, + cc::RenderPass::NO_OVERLAY); pass_in->shared_quad_state_list.push_back(shared_state1_in.Pass()); pass_in->quad_list.push_back(checkerboard_in.PassAs()); @@ -454,7 +455,8 @@ TEST_F(CCMessagesTest, AllQuads) { arbitrary_rect1, arbitrary_rectf1, arbitrary_matrix, - arbitrary_bool1); + arbitrary_bool1, + cc::RenderPass::NO_OVERLAY); pass_cmp->shared_quad_state_list.push_back(shared_state1_cmp.Pass()); pass_cmp->quad_list.push_back(checkerboard_cmp.PassAs()); @@ -531,7 +533,8 @@ TEST_F(CCMessagesTest, UnusedSharedQuadStates) { gfx::Rect(100, 100), gfx::RectF(), gfx::Transform(), - false); + false, + cc::RenderPass::NO_OVERLAY); // The first SharedQuadState is used. scoped_ptr shared_state1_in = SharedQuadState::Create();