summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Cameron <ccameron@chromium.org>2016-01-22 11:10:55 -0800
committerChristopher Cameron <ccameron@chromium.org>2016-01-22 19:14:30 +0000
commite3ed48b2ecb1053ab1e848c0a146eee78b6b8305 (patch)
tree56c8a8c32512678b68b7d71d96e18e9c50b0dafb
parentdfe92cc3d612d52ae5f0ec5131df513b3ec6248a (diff)
downloadchromium_src-e3ed48b2ecb1053ab1e848c0a146eee78b6b8305.zip
chromium_src-e3ed48b2ecb1053ab1e848c0a146eee78b6b8305.tar.gz
chromium_src-e3ed48b2ecb1053ab1e848c0a146eee78b6b8305.tar.bz2
Mac: Add support for clipping and arbitrary transforms
Create a hierarchy as described in the design document at https://docs.google.com/document/d/1DtSN9zzvCF44_FQPM7ie01UxGHagQ66zfF5L9HnigQY/edit#heading=h.xm56c9edenjg Move maintenance of this hierarchy to a separate file, ca_layer_tree_mac.mm. Remove support for overlays from ImageTransportOverlayMac, because they now just add complication for not much additional energy savings. BUG=533681 CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel Review URL: https://codereview.chromium.org/1585323004 Cr-Commit-Position: refs/heads/master@{#370606} (cherry picked from commit efbddf0092035837fe9d2e2ebdb90237906869bb) Review URL: https://codereview.chromium.org/1629473002 . Cr-Commit-Position: refs/branch-heads/2623@{#82} Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
-rw-r--r--cc/output/ca_layer_overlay.cc65
-rw-r--r--cc/output/ca_layer_overlay.h8
-rw-r--r--cc/output/gl_renderer.cc16
-rw-r--r--cc/output/overlay_unittest.cc46
-rw-r--r--content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm1
-rw-r--r--content/common/gpu/ca_layer_tree_mac.h188
-rw-r--r--content/common/gpu/ca_layer_tree_mac.mm402
-rw-r--r--content/common/gpu/image_transport_surface_overlay_mac.h17
-rw-r--r--content/common/gpu/image_transport_surface_overlay_mac.mm273
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/test/gpu/gpu_tests/pixel_expectations.py4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc2
-rw-r--r--ui/gl/gl_surface.cc5
-rw-r--r--ui/gl/gl_surface.h5
14 files changed, 752 insertions, 282 deletions
diff --git a/cc/output/ca_layer_overlay.cc b/cc/output/ca_layer_overlay.cc
index 8704a06..2a0d84c 100644
--- a/cc/output/ca_layer_overlay.cc
+++ b/cc/output/ca_layer_overlay.cc
@@ -89,7 +89,7 @@ CALayerResult FromTextureQuad(ResourceProvider* resource_provider,
// frame is the composition of a vertical flip about the anchor point, and a
// translation by the height of the layer.
ca_layer_overlay->transform.preTranslate(
- 0, ca_layer_overlay->bounds_size.height(), 0);
+ 0, ca_layer_overlay->bounds_rect.height(), 0);
ca_layer_overlay->transform.preScale(1, -1, 1);
}
ca_layer_overlay->contents_resource_id = resource_id;
@@ -125,10 +125,6 @@ CALayerResult FromDrawQuad(ResourceProvider* resource_provider,
if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode)
return CA_LAYER_FAILED_QUAD_BLEND_MODE;
- // TODO(ccameron): Handle 3D transforms.
- if (!quad->shared_quad_state->quad_to_target_transform.IsFlat())
- return CA_LAYER_FAILED_QUAD_TRANSFORM;
-
// Early-out for invisible quads.
if (quad->shared_quad_state->opacity == 0.f) {
*skip = true;
@@ -146,31 +142,16 @@ CALayerResult FromDrawQuad(ResourceProvider* resource_provider,
if (quad->IsTopEdge())
ca_layer_overlay->edge_aa_mask |= GL_CA_LAYER_EDGE_TOP_CHROMIUM;
- // Check rect clipping.
- gfx::RectF quad_rect(quad->rect);
- if (quad->shared_quad_state->is_clipped) {
- gfx::RectF clip_rect = gfx::RectF(quad->shared_quad_state->clip_rect);
- gfx::RectF quad_rect_in_clip_space = gfx::RectF(quad->rect);
- quad->shared_quad_state->quad_to_target_transform.TransformRect(
- &quad_rect_in_clip_space);
- quad_rect_in_clip_space.Intersect(display_rect);
- // Skip quads that are entirely clipped.
- if (!quad_rect_in_clip_space.Intersects(clip_rect)) {
- *skip = true;
- return CA_LAYER_SUCCESS;
- }
- // Fall back if the clip rect actually has an effect.
- // TODO(ccameron): Handle more clip rects.
- if (!clip_rect.Contains(quad_rect_in_clip_space)) {
- return CA_LAYER_FAILED_QUAD_CLIPPING;
- }
- }
+ // Set rect clipping and sorting context ID.
+ ca_layer_overlay->sorting_context_id =
+ quad->shared_quad_state->sorting_context_id;
+ ca_layer_overlay->is_clipped = quad->shared_quad_state->is_clipped;
+ ca_layer_overlay->clip_rect = gfx::RectF(quad->shared_quad_state->clip_rect);
ca_layer_overlay->opacity = quad->shared_quad_state->opacity;
- ca_layer_overlay->bounds_size = gfx::SizeF(quad->rect.size());
- ca_layer_overlay->transform.setTranslate(quad->rect.x(), quad->rect.y(), 0);
- ca_layer_overlay->transform.postConcat(
- quad->shared_quad_state->quad_to_target_transform.matrix());
+ ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
+ ca_layer_overlay->transform =
+ quad->shared_quad_state->quad_to_target_transform.matrix();
switch (quad->material) {
case DrawQuad::IO_SURFACE_CONTENT:
@@ -202,7 +183,6 @@ CALayerResult FromDrawQuad(ResourceProvider* resource_provider,
case DrawQuad::YUV_VIDEO_CONTENT:
return CA_LAYER_FAILED_YUV_VIDEO_CONTENT;
default:
- return CA_LAYER_FAILED_UNKNOWN;
break;
}
@@ -220,18 +200,37 @@ bool ProcessForCALayerOverlays(ResourceProvider* resource_provider,
const QuadList& quad_list,
CALayerOverlayList* ca_layer_overlays) {
CALayerResult result = CA_LAYER_SUCCESS;
+ ca_layer_overlays->reserve(quad_list.size());
+
for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
++it) {
const DrawQuad* quad = *it;
- CALayerOverlay ca_layer_overlay;
+ CALayerOverlay ca_layer;
bool skip = false;
- result = FromDrawQuad(resource_provider, display_rect, quad,
- &ca_layer_overlay, &skip);
+ result =
+ FromDrawQuad(resource_provider, display_rect, quad, &ca_layer, &skip);
if (result != CA_LAYER_SUCCESS)
break;
+
if (skip)
continue;
- ca_layer_overlays->push_back(ca_layer_overlay);
+
+ // It is not possible to correctly represent two different clipping settings
+ // within one sorting context.
+ if (!ca_layer_overlays->empty()) {
+ const CALayerOverlay& previous_ca_layer = ca_layer_overlays->back();
+ if (ca_layer.sorting_context_id &&
+ previous_ca_layer.sorting_context_id == ca_layer.sorting_context_id) {
+ if (previous_ca_layer.is_clipped != ca_layer.is_clipped ||
+ previous_ca_layer.clip_rect != ca_layer.clip_rect) {
+ // TODO(ccameron): Add a histogram value for this.
+ result = CA_LAYER_FAILED_UNKNOWN;
+ break;
+ }
+ }
+ }
+
+ ca_layer_overlays->push_back(ca_layer);
}
UMA_HISTOGRAM_ENUMERATION("Compositing.Renderer.CALayerResult", result,
diff --git a/cc/output/ca_layer_overlay.h b/cc/output/ca_layer_overlay.h
index ab234f4..f0b7c22 100644
--- a/cc/output/ca_layer_overlay.h
+++ b/cc/output/ca_layer_overlay.h
@@ -20,6 +20,12 @@ class CC_EXPORT CALayerOverlay {
CALayerOverlay();
~CALayerOverlay();
+ // If |is_clipped| is true, then clip to |clip_rect| in the target space.
+ bool is_clipped = false;
+ gfx::RectF clip_rect;
+ // Layers in a non-zero sorting context exist in the same 3D space and should
+ // intersect.
+ unsigned sorting_context_id = 0;
// Texture that corresponds to an IOSurface to set as the content of the
// CALayer. If this is 0 then the CALayer is a solid color.
unsigned contents_resource_id = 0;
@@ -32,7 +38,7 @@ class CC_EXPORT CALayerOverlay {
// The edge anti-aliasing mask property for the CALayer.
unsigned edge_aa_mask = 0;
// The bounds for the CALayer in pixels.
- gfx::SizeF bounds_size;
+ gfx::RectF bounds_rect;
// The transform to apply to the CALayer.
SkMatrix44 transform = SkMatrix44(SkMatrix44::kIdentity_Constructor);
};
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index acd7bf2..2b389f3 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -3551,14 +3551,16 @@ void GLRenderer::ScheduleCALayers(DrawingFrame* frame) {
ca_layer_overlay.contents_rect.height(),
};
GLfloat bounds_rect[4] = {
- 0, 0, ca_layer_overlay.bounds_size.width(),
- ca_layer_overlay.bounds_size.height(),
+ ca_layer_overlay.bounds_rect.x(), ca_layer_overlay.bounds_rect.y(),
+ ca_layer_overlay.bounds_rect.width(),
+ ca_layer_overlay.bounds_rect.height(),
};
- GLboolean is_clipped = GL_FALSE;
- GLfloat clip_rect[4] = {
- 0, 0, 0, 0,
- };
- GLint sorting_context_id = 0;
+ GLboolean is_clipped = ca_layer_overlay.is_clipped;
+ GLfloat clip_rect[4] = {ca_layer_overlay.clip_rect.x(),
+ ca_layer_overlay.clip_rect.y(),
+ ca_layer_overlay.clip_rect.width(),
+ ca_layer_overlay.clip_rect.height()};
+ GLint sorting_context_id = ca_layer_overlay.sorting_context_id;
GLfloat transform[16];
ca_layer_overlay.transform.asColMajorf(transform);
gl_->ScheduleCALayerCHROMIUM(
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 140935c..c9c3017 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1516,7 +1516,7 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
EXPECT_EQ(1U, ca_layer_list.size());
}
-TEST_F(CALayerOverlayTest, Disallow3DTransform) {
+TEST_F(CALayerOverlayTest, ThreeDTransform) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
@@ -1534,42 +1534,22 @@ TEST_F(CALayerOverlayTest, Disallow3DTransform) {
&overlay_list, &ca_layer_list,
&damage_rect);
ASSERT_EQ(1U, pass_list.size());
- EXPECT_EQ(1U, pass_list.back()->quad_list.size());
- EXPECT_EQ(1U, overlay_list.size());
- EXPECT_EQ(0U, ca_layer_list.size());
-}
-
-TEST_F(CALayerOverlayTest, AllowContainingClip) {
- scoped_ptr<RenderPass> pass = CreateRenderPass();
- CreateFullscreenCandidateQuad(resource_provider_.get(),
- pass->shared_quad_state_list.back(),
- pass.get());
- pass->shared_quad_state_list.back()->is_clipped = true;
- pass->shared_quad_state_list.back()->clip_rect = kOverlayRect;
-
- gfx::Rect damage_rect;
- RenderPassList pass_list;
- pass_list.push_back(std::move(pass));
- CALayerOverlayList ca_layer_list;
- OverlayCandidateList overlay_list(
- BackbufferOverlayList(pass_list.back().get()));
- overlay_processor_->ProcessForOverlays(resource_provider_.get(), &pass_list,
- &overlay_list, &ca_layer_list,
- &damage_rect);
- ASSERT_EQ(1U, pass_list.size());
EXPECT_EQ(0U, pass_list.back()->quad_list.size());
EXPECT_EQ(0U, overlay_list.size());
EXPECT_EQ(1U, ca_layer_list.size());
+ gfx::Transform expected_transform;
+ expected_transform.RotateAboutXAxis(45.f);
+ gfx::Transform actual_transform(ca_layer_list.back().transform);
+ EXPECT_EQ(expected_transform.ToString(), actual_transform.ToString());
}
-TEST_F(CALayerOverlayTest, SkipDisjointClip) {
+TEST_F(CALayerOverlayTest, AllowContainingClip) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
- pass->shared_quad_state_list.back()->clip_rect =
- gfx::Rect(128, 128, 128, 128);
+ pass->shared_quad_state_list.back()->clip_rect = kOverlayRect;
gfx::Rect damage_rect;
RenderPassList pass_list;
@@ -1583,10 +1563,10 @@ TEST_F(CALayerOverlayTest, SkipDisjointClip) {
ASSERT_EQ(1U, pass_list.size());
EXPECT_EQ(0U, pass_list.back()->quad_list.size());
EXPECT_EQ(0U, overlay_list.size());
- EXPECT_EQ(0U, ca_layer_list.size());
+ EXPECT_EQ(1U, ca_layer_list.size());
}
-TEST_F(CALayerOverlayTest, DisallowNontrivialClip) {
+TEST_F(CALayerOverlayTest, NontrivialClip) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
@@ -1605,9 +1585,11 @@ TEST_F(CALayerOverlayTest, DisallowNontrivialClip) {
&damage_rect);
ASSERT_EQ(1U, pass_list.size());
- EXPECT_EQ(1U, pass_list.back()->quad_list.size());
- EXPECT_EQ(1U, overlay_list.size());
- EXPECT_EQ(0U, ca_layer_list.size());
+ EXPECT_EQ(0U, pass_list.back()->quad_list.size());
+ EXPECT_EQ(0U, overlay_list.size());
+ EXPECT_EQ(1U, ca_layer_list.size());
+ EXPECT_TRUE(ca_layer_list.back().is_clipped);
+ EXPECT_EQ(gfx::RectF(64, 64, 128, 128), ca_layer_list.back().clip_rect);
}
TEST_F(CALayerOverlayTest, SkipTransparent) {
diff --git a/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm b/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
index 9c12c7e..2b1c3ec 100644
--- a/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
+++ b/content/browser/compositor/browser_compositor_overlay_candidate_validator_mac.mm
@@ -28,7 +28,6 @@ BrowserCompositorOverlayCandidateValidatorMac::
void BrowserCompositorOverlayCandidateValidatorMac::GetStrategies(
cc::OverlayProcessor::StrategyList* strategies) {
- strategies->push_back(make_scoped_ptr(new cc::OverlayStrategySandwich(this)));
}
bool BrowserCompositorOverlayCandidateValidatorMac::AllowCALayerOverlays() {
diff --git a/content/common/gpu/ca_layer_tree_mac.h b/content/common/gpu/ca_layer_tree_mac.h
new file mode 100644
index 0000000..163474e
--- /dev/null
+++ b/content/common/gpu/ca_layer_tree_mac.h
@@ -0,0 +1,188 @@
+// Copyright 2016 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 CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_
+#define CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_
+
+#include <IOSurface/IOSurface.h>
+#include <QuartzCore/QuartzCore.h>
+#include <deque>
+#include <vector>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/transform.h"
+
+namespace content {
+
+// The CALayerTree will construct a hierarchy of CALayers from a linear list,
+// using the algorithm and structure referenced described in
+// https://docs.google.com/document/d/1DtSN9zzvCF44_FQPM7ie01UxGHagQ66zfF5L9HnigQY/edit?usp=sharing
+class CALayerTree {
+ public:
+ CALayerTree();
+
+ // This will remove all CALayers from this tree from their superlayer.
+ ~CALayerTree();
+
+ // Append the description of a new CALayer to the tree. This will not
+ // create any new CALayers until CommitScheduledCALayers is called. This
+ // cannot be called anymore after CommitScheduledCALayers has been called.
+ bool ScheduleCALayer(bool is_clipped,
+ const gfx::Rect& clip_rect,
+ unsigned sorting_context_id,
+ const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity);
+
+ // Create a CALayer tree for the scheduled layers, and set |superlayer| to
+ // have only this tree as its sublayers. If |old_tree| is non-null, then try
+ // to re-use the CALayers of |old_tree| as much as possible. |old_tree| will
+ // be destroyed at the end of the function, and any CALayers in it which were
+ // not re-used by |this| will be removed from the CALayer hierarchy.
+ void CommitScheduledCALayers(CALayer* superlayer,
+ scoped_ptr<CALayerTree> old_tree,
+ float scale_factor);
+
+ private:
+ struct RootLayer;
+ struct ClipAndSortingLayer;
+ struct TransformLayer;
+ struct ContentLayer;
+
+ struct RootLayer {
+ RootLayer();
+
+ // This will remove |ca_layer| from its superlayer, if |ca_layer| is
+ // non-nil.
+ ~RootLayer();
+
+ // Append a new content layer, without modifying the actual CALayer
+ // structure.
+ bool AddContentLayer(bool is_clipped,
+ const gfx::Rect& clip_rect,
+ unsigned sorting_context_id,
+ const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity);
+
+ // Allocate CALayers for this layer and its children, and set their
+ // properties appropriately. Re-use the CALayers from |old_layer| if
+ // possible. If re-using a CALayer from |old_layer|, reset its |ca_layer|
+ // to nil, so that its destructor will not remove an active CALayer.
+ void CommitToCA(CALayer* superlayer,
+ RootLayer* old_layer,
+ float scale_factor);
+
+ std::vector<ClipAndSortingLayer> clip_and_sorting_layers;
+ base::scoped_nsobject<CALayer> ca_layer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RootLayer);
+ };
+ struct ClipAndSortingLayer {
+ ClipAndSortingLayer(bool is_clipped,
+ gfx::Rect clip_rect,
+ unsigned sorting_context_id,
+ bool is_singleton_sorting_context);
+ ClipAndSortingLayer(ClipAndSortingLayer&& layer);
+
+ // See the behavior of RootLayer for the effects of these functions on the
+ // |ca_layer| member and |old_layer| argument.
+ ~ClipAndSortingLayer();
+ void AddContentLayer(const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity);
+ void CommitToCA(CALayer* superlayer,
+ ClipAndSortingLayer* old_layer,
+ float scale_factor);
+
+ std::vector<TransformLayer> transform_layers;
+ bool is_clipped = false;
+ gfx::Rect clip_rect;
+ unsigned sorting_context_id = 0;
+ bool is_singleton_sorting_context = false;
+ base::scoped_nsobject<CALayer> ca_layer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClipAndSortingLayer);
+ };
+ struct TransformLayer {
+ TransformLayer(const gfx::Transform& transform);
+ TransformLayer(TransformLayer&& layer);
+
+ // See the behavior of RootLayer for the effects of these functions on the
+ // |ca_layer| member and |old_layer| argument.
+ ~TransformLayer();
+ void AddContentLayer(base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity);
+ void CommitToCA(CALayer* superlayer,
+ TransformLayer* old_layer,
+ float scale_factor);
+
+ gfx::Transform transform;
+ std::vector<ContentLayer> content_layers;
+ base::scoped_nsobject<CALayer> ca_layer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransformLayer);
+ };
+ struct ContentLayer {
+ ContentLayer(base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity);
+ ContentLayer(ContentLayer&& layer);
+
+ // See the behavior of RootLayer for the effects of these functions on the
+ // |ca_layer| member and |old_layer| argument.
+ ~ContentLayer();
+ void CommitToCA(CALayer* parent,
+ ContentLayer* old_layer,
+ float scale_factor);
+
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
+ gfx::RectF contents_rect;
+ gfx::Rect rect;
+ unsigned background_color = 0;
+ unsigned edge_aa_mask = 0;
+ float opacity = 1;
+ base::scoped_nsobject<CALayer> ca_layer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ContentLayer);
+ };
+
+ RootLayer root_layer_;
+ float scale_factor_ = 1;
+ bool has_committed_ = false;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CALayerTree);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CA_LAYER_TREE_MAC_H_
diff --git a/content/common/gpu/ca_layer_tree_mac.mm b/content/common/gpu/ca_layer_tree_mac.mm
new file mode 100644
index 0000000..47343c4
--- /dev/null
+++ b/content/common/gpu/ca_layer_tree_mac.mm
@@ -0,0 +1,402 @@
+// Copyright 2016 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 "content/common/gpu/ca_layer_tree_mac.h"
+
+#include "base/command_line.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/cocoa/animation_utils.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gfx/geometry/dip_util.h"
+
+namespace content {
+
+CALayerTree::CALayerTree() {}
+CALayerTree::~CALayerTree() {}
+
+bool CALayerTree::ScheduleCALayer(
+ bool is_clipped,
+ const gfx::Rect& clip_rect,
+ unsigned sorting_context_id,
+ const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity) {
+ if (has_committed_) {
+ DLOG(ERROR) << "ScheduleCALayer called after CommitScheduledCALayers.";
+ return false;
+ }
+ return root_layer_.AddContentLayer(is_clipped, clip_rect, sorting_context_id,
+ transform, io_surface, contents_rect, rect,
+ background_color, edge_aa_mask, opacity);
+}
+
+void CALayerTree::CommitScheduledCALayers(CALayer* superlayer,
+ scoped_ptr<CALayerTree> old_tree,
+ float scale_factor) {
+ RootLayer* old_root_layer = nullptr;
+ if (old_tree) {
+ DCHECK(old_tree->has_committed_);
+ if (old_tree->scale_factor_ == scale_factor)
+ old_root_layer = &old_tree->root_layer_;
+ }
+
+ root_layer_.CommitToCA(superlayer, old_root_layer, scale_factor);
+ // If there are any extra CALayers in |old_tree| that were not stolen by this
+ // tree, they will be removed from the CALayer tree in this deallocation.
+ old_tree.reset();
+ has_committed_ = true;
+ scale_factor_ = scale_factor;
+}
+
+CALayerTree::RootLayer::RootLayer() {}
+
+// Note that for all destructors, the the CALayer will have been reset to nil if
+// another layer has taken it.
+CALayerTree::RootLayer::~RootLayer() {
+ [ca_layer removeFromSuperlayer];
+}
+
+CALayerTree::ClipAndSortingLayer::ClipAndSortingLayer(
+ bool is_clipped,
+ gfx::Rect clip_rect,
+ unsigned sorting_context_id,
+ bool is_singleton_sorting_context)
+ : is_clipped(is_clipped),
+ clip_rect(clip_rect),
+ sorting_context_id(sorting_context_id),
+ is_singleton_sorting_context(is_singleton_sorting_context) {}
+
+CALayerTree::ClipAndSortingLayer::ClipAndSortingLayer(
+ ClipAndSortingLayer&& layer)
+ : transform_layers(std::move(layer.transform_layers)),
+ is_clipped(layer.is_clipped),
+ clip_rect(layer.clip_rect),
+ sorting_context_id(layer.sorting_context_id),
+ is_singleton_sorting_context(
+ layer.is_singleton_sorting_context),
+ ca_layer(layer.ca_layer) {
+ // Ensure that the ca_layer be reset, so that when the destructor is called,
+ // the layer hierarchy is unaffected.
+ // TODO(ccameron): Add a move constructor for scoped_nsobject to do this
+ // automatically.
+ layer.ca_layer.reset();
+}
+
+CALayerTree::ClipAndSortingLayer::~ClipAndSortingLayer() {
+ [ca_layer removeFromSuperlayer];
+}
+
+CALayerTree::TransformLayer::TransformLayer(const gfx::Transform& transform)
+ : transform(transform) {}
+
+CALayerTree::TransformLayer::TransformLayer(TransformLayer&& layer)
+ : transform(layer.transform),
+ content_layers(std::move(layer.content_layers)),
+ ca_layer(layer.ca_layer) {
+ layer.ca_layer.reset();
+}
+
+CALayerTree::TransformLayer::~TransformLayer() {
+ [ca_layer removeFromSuperlayer];
+}
+
+CALayerTree::ContentLayer::ContentLayer(
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity)
+ : io_surface(io_surface),
+ contents_rect(contents_rect),
+ rect(rect),
+ background_color(background_color),
+ edge_aa_mask(edge_aa_mask),
+ opacity(opacity) {}
+
+CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer)
+ : io_surface(layer.io_surface),
+ contents_rect(layer.contents_rect),
+ rect(layer.rect),
+ background_color(layer.background_color),
+ edge_aa_mask(layer.edge_aa_mask),
+ opacity(layer.opacity),
+ ca_layer(layer.ca_layer) {
+ DCHECK(!layer.ca_layer);
+ layer.io_surface.reset();
+ layer.ca_layer.reset();
+}
+
+CALayerTree::ContentLayer::~ContentLayer() {
+ [ca_layer removeFromSuperlayer];
+}
+
+bool CALayerTree::RootLayer::AddContentLayer(
+ bool is_clipped,
+ const gfx::Rect& clip_rect,
+ unsigned sorting_context_id,
+ const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity) {
+ bool needs_new_clip_and_sorting_layer = true;
+
+ // In sorting_context_id 0, all quads are listed in back-to-front order.
+ // This is accomplished by having the CALayers be siblings of each other.
+ // If a quad has a 3D transform, it is necessary to put it in its own sorting
+ // context, so that it will not intersect with quads before and after it.
+ bool is_singleton_sorting_context =
+ !sorting_context_id && !transform.IsFlat();
+
+ if (!clip_and_sorting_layers.empty()) {
+ ClipAndSortingLayer& current_layer = clip_and_sorting_layers.back();
+ // It is in error to change the clipping settings within a non-zero sorting
+ // context. The result will be incorrect layering and intersection.
+ if (sorting_context_id &&
+ current_layer.sorting_context_id == sorting_context_id &&
+ (current_layer.is_clipped != is_clipped ||
+ current_layer.clip_rect != clip_rect)) {
+ DLOG(ERROR) << "CALayer changed clip inside non-zero sorting context.";
+ return false;
+ }
+ if (!is_singleton_sorting_context &&
+ !current_layer.is_singleton_sorting_context &&
+ current_layer.is_clipped == is_clipped &&
+ current_layer.clip_rect == clip_rect &&
+ current_layer.sorting_context_id == sorting_context_id) {
+ needs_new_clip_and_sorting_layer = false;
+ }
+ }
+ if (needs_new_clip_and_sorting_layer) {
+ clip_and_sorting_layers.push_back(
+ ClipAndSortingLayer(is_clipped, clip_rect, sorting_context_id,
+ is_singleton_sorting_context));
+ }
+ clip_and_sorting_layers.back().AddContentLayer(
+ transform, io_surface, contents_rect, rect, background_color,
+ edge_aa_mask, opacity);
+ return true;
+}
+
+void CALayerTree::ClipAndSortingLayer::AddContentLayer(
+ const gfx::Transform& transform,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity) {
+ bool needs_new_transform_layer = true;
+ if (!transform_layers.empty()) {
+ const TransformLayer& current_layer = transform_layers.back();
+ if (current_layer.transform == transform)
+ needs_new_transform_layer = false;
+ }
+ if (needs_new_transform_layer)
+ transform_layers.push_back(TransformLayer(transform));
+ transform_layers.back().AddContentLayer(
+ io_surface, contents_rect, rect, background_color, edge_aa_mask, opacity);
+}
+
+void CALayerTree::TransformLayer::AddContentLayer(
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ const gfx::RectF& contents_rect,
+ const gfx::Rect& rect,
+ unsigned background_color,
+ unsigned edge_aa_mask,
+ float opacity) {
+ content_layers.push_back(ContentLayer(io_surface, contents_rect, rect,
+ background_color, edge_aa_mask,
+ opacity));
+}
+
+void CALayerTree::RootLayer::CommitToCA(CALayer* superlayer,
+ RootLayer* old_layer,
+ float scale_factor) {
+ if (old_layer) {
+ DCHECK(old_layer->ca_layer);
+ std::swap(ca_layer, old_layer->ca_layer);
+ } else {
+ ca_layer.reset([[CALayer alloc] init]);
+ [ca_layer setAnchorPoint:CGPointZero];
+ [superlayer setSublayers:nil];
+ [superlayer addSublayer:ca_layer];
+ [superlayer setBorderWidth:0];
+ }
+ DCHECK_EQ([ca_layer superlayer], superlayer);
+
+ for (size_t i = 0; i < clip_and_sorting_layers.size(); ++i) {
+ ClipAndSortingLayer* old_clip_and_sorting_layer = nullptr;
+ if (old_layer && i < old_layer->clip_and_sorting_layers.size()) {
+ old_clip_and_sorting_layer = &old_layer->clip_and_sorting_layers[i];
+ }
+ clip_and_sorting_layers[i].CommitToCA(
+ ca_layer.get(), old_clip_and_sorting_layer, scale_factor);
+ }
+}
+
+void CALayerTree::ClipAndSortingLayer::CommitToCA(
+ CALayer* superlayer,
+ ClipAndSortingLayer* old_layer,
+ float scale_factor) {
+ bool update_is_clipped = true;
+ bool update_clip_rect = true;
+ if (old_layer) {
+ DCHECK(old_layer->ca_layer);
+ std::swap(ca_layer, old_layer->ca_layer);
+ update_is_clipped = old_layer->is_clipped != is_clipped;
+ update_clip_rect = old_layer->clip_rect != clip_rect;
+ } else {
+ ca_layer.reset([[CALayer alloc] init]);
+ [ca_layer setAnchorPoint:CGPointZero];
+ [superlayer addSublayer:ca_layer];
+ }
+ DCHECK_EQ([ca_layer superlayer], superlayer);
+
+ if (update_is_clipped)
+ [ca_layer setMasksToBounds:is_clipped];
+
+ if (update_clip_rect) {
+ if (is_clipped) {
+ gfx::RectF dip_clip_rect = gfx::RectF(clip_rect);
+ dip_clip_rect.Scale(1 / scale_factor);
+ [ca_layer setPosition:CGPointMake(dip_clip_rect.x(), dip_clip_rect.y())];
+ [ca_layer setBounds:CGRectMake(0, 0, dip_clip_rect.width(),
+ dip_clip_rect.height())];
+ [ca_layer
+ setSublayerTransform:CATransform3DMakeTranslation(
+ -dip_clip_rect.x(), -dip_clip_rect.y(), 0)];
+ } else {
+ [ca_layer setPosition:CGPointZero];
+ [ca_layer setBounds:CGRectZero];
+ [ca_layer setSublayerTransform:CATransform3DIdentity];
+ }
+ }
+
+ for (size_t i = 0; i < transform_layers.size(); ++i) {
+ TransformLayer* old_transform_layer = nullptr;
+ if (old_layer && i < old_layer->transform_layers.size())
+ old_transform_layer = &old_layer->transform_layers[i];
+ transform_layers[i].CommitToCA(ca_layer.get(), old_transform_layer,
+ scale_factor);
+ }
+}
+
+void CALayerTree::TransformLayer::CommitToCA(CALayer* superlayer,
+ TransformLayer* old_layer,
+ float scale_factor) {
+ bool update_transform = true;
+ if (old_layer) {
+ DCHECK(old_layer->ca_layer);
+ std::swap(ca_layer, old_layer->ca_layer);
+ update_transform = old_layer->transform != transform;
+ } else {
+ ca_layer.reset([[CATransformLayer alloc] init]);
+ [superlayer addSublayer:ca_layer];
+ }
+ DCHECK_EQ([ca_layer superlayer], superlayer);
+
+ if (update_transform) {
+ gfx::Transform pre_scale;
+ gfx::Transform post_scale;
+ pre_scale.Scale(1 / scale_factor, 1 / scale_factor);
+ post_scale.Scale(scale_factor, scale_factor);
+ gfx::Transform conjugated_transform = pre_scale * transform * post_scale;
+
+ CATransform3D ca_transform;
+ conjugated_transform.matrix().asColMajord(&ca_transform.m11);
+ [ca_layer setTransform:ca_transform];
+ }
+
+ for (size_t i = 0; i < content_layers.size(); ++i) {
+ ContentLayer* old_content_layer = nullptr;
+ if (old_layer && i < old_layer->content_layers.size())
+ old_content_layer = &old_layer->content_layers[i];
+ content_layers[i].CommitToCA(ca_layer.get(), old_content_layer,
+ scale_factor);
+ }
+}
+
+void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
+ ContentLayer* old_layer,
+ float scale_factor) {
+ bool update_contents = true;
+ bool update_contents_rect = true;
+ bool update_rect = true;
+ bool update_background_color = true;
+ bool update_edge_aa_mask = true;
+ bool update_opacity = true;
+ if (old_layer) {
+ DCHECK(old_layer->ca_layer);
+ std::swap(ca_layer, old_layer->ca_layer);
+ update_contents = old_layer->io_surface != io_surface;
+ update_contents_rect = old_layer->contents_rect != contents_rect;
+ update_rect = old_layer->rect != rect;
+ update_background_color = old_layer->background_color != background_color;
+ update_edge_aa_mask = old_layer->edge_aa_mask != edge_aa_mask;
+ update_opacity = old_layer->opacity != opacity;
+ } else {
+ ca_layer.reset([[CALayer alloc] init]);
+ [ca_layer setAnchorPoint:CGPointZero];
+ [superlayer addSublayer:ca_layer];
+ }
+ DCHECK_EQ([ca_layer superlayer], superlayer);
+ bool update_anything = update_contents || update_contents_rect ||
+ update_rect || update_background_color ||
+ update_edge_aa_mask || update_opacity;
+
+ if (update_contents) {
+ [ca_layer setContents:static_cast<id>(io_surface.get())];
+ if ([ca_layer respondsToSelector:(@selector(setContentsScale:))])
+ [ca_layer setContentsScale:scale_factor];
+ }
+ if (update_contents_rect)
+ [ca_layer setContentsRect:contents_rect.ToCGRect()];
+ if (update_rect) {
+ gfx::RectF dip_rect = gfx::RectF(rect);
+ dip_rect.Scale(1 / scale_factor);
+ [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())];
+ [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())];
+ }
+ if (update_background_color) {
+ CGFloat rgba_color_components[4] = {
+ SkColorGetR(background_color) / 255.,
+ SkColorGetG(background_color) / 255.,
+ SkColorGetB(background_color) / 255.,
+ SkColorGetA(background_color) / 255.,
+ };
+ base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate(
+ CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components));
+ [ca_layer setBackgroundColor:srgb_background_color];
+ }
+ if (update_edge_aa_mask)
+ [ca_layer setEdgeAntialiasingMask:edge_aa_mask];
+ if (update_opacity)
+ [ca_layer setOpacity:opacity];
+
+ static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowMacOverlayBorders);
+ if (show_borders) {
+ base::ScopedCFTypeRef<CGColorRef> color;
+ if (update_anything) {
+ // Pink represents a CALayer that changed this frame.
+ color.reset(CGColorCreateGenericRGB(1, 0, 1, 1));
+ } else {
+ // Grey represents a CALayer that has not changed.
+ color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1));
+ }
+ [ca_layer setBorderWidth:1];
+ [ca_layer setBorderColor:color];
+ }
+}
+
+} // namespace content
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.h b/content/common/gpu/image_transport_surface_overlay_mac.h
index 66ce211..5b86a5e9 100644
--- a/content/common/gpu/image_transport_surface_overlay_mac.h
+++ b/content/common/gpu/image_transport_surface_overlay_mac.h
@@ -21,6 +21,8 @@
namespace content {
+class CALayerTree;
+
class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
public ImageTransportSurface,
public ui::GpuSwitchingObserver {
@@ -53,10 +55,11 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
float opacity,
unsigned background_color,
unsigned edge_aa_mask,
- const gfx::RectF& bounds_rect,
+ const gfx::RectF& rect,
bool is_clipped,
const gfx::RectF& clip_rect,
- const gfx::Transform& transform) override;
+ const gfx::Transform& transform,
+ int sorting_context_id) override;
bool IsSurfaceless() const override;
// ImageTransportSurface implementation
@@ -78,9 +81,9 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
void UpdateRootAndPartialDamagePlanes(
const linked_ptr<OverlayPlane>& new_root_plane,
const gfx::RectF& pixel_damage_rect);
- void UpdateOverlayPlanes(
- const std::vector<linked_ptr<OverlayPlane>>& new_overlay_planes);
- void UpdateCALayerTree();
+ void UpdateRootAndPartialDamageCALayers(float scale_factor);
+ void UpdateCALayerTree(scoped_ptr<CALayerTree> ca_layer_tree,
+ float scale_factor);
// Returns true if the front of |pending_swaps_| has completed, or has timed
// out by |now|.
@@ -123,7 +126,7 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
// Planes that have been scheduled, but have not had a subsequent SwapBuffers
// call made yet.
linked_ptr<OverlayPlane> pending_root_plane_;
- std::vector<linked_ptr<OverlayPlane>> pending_overlay_planes_;
+ scoped_ptr<CALayerTree> pending_ca_layer_tree_;
// A queue of all frames that have been created by SwapBuffersInternal but
// have not yet been displayed. This queue is checked at the beginning of
@@ -133,7 +136,7 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
// The planes that are currently being displayed on the screen.
linked_ptr<OverlayPlane> current_root_plane_;
std::list<linked_ptr<OverlayPlane>> current_partial_damage_planes_;
- std::list<linked_ptr<OverlayPlane>> current_overlay_planes_;
+ scoped_ptr<CALayerTree> current_ca_layer_tree_;
// The time of the last swap was issued. If this is more than two vsyncs, then
// use the simpler non-smooth animation path.
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm
index 03c2eed..724f135 100644
--- a/content/common/gpu/image_transport_surface_overlay_mac.mm
+++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
@@ -22,12 +22,14 @@ typedef void* GLeglImageOES;
#include "base/command_line.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "content/common/gpu/ca_layer_tree_mac.h"
#include "content/common/gpu/gpu_messages.h"
#include "ui/accelerated_widget_mac/io_surface_context.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_fence.h"
@@ -96,89 +98,53 @@ class ImageTransportSurfaceOverlayMac::OverlayPlane {
public:
static linked_ptr<OverlayPlane> CreateWithFrameRect(
int z_order,
- int io_surface_id,
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
const gfx::RectF& pixel_frame_rect,
const gfx::RectF& contents_rect) {
gfx::Transform transform;
transform.Translate(pixel_frame_rect.x(), pixel_frame_rect.y());
return linked_ptr<OverlayPlane>(
- new OverlayPlane(z_order, io_surface_id, io_surface, contents_rect, 1.f,
- base::ScopedCFTypeRef<CGColorRef>(), 0,
- pixel_frame_rect.size(), transform, pixel_frame_rect));
+ new OverlayPlane(z_order, io_surface, contents_rect, pixel_frame_rect));
}
- static linked_ptr<OverlayPlane> CreateWithTransform(
- int z_order,
- int io_surface_id,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- const gfx::RectF& contents_rect,
- float opacity,
- base::ScopedCFTypeRef<CGColorRef> background_color,
- unsigned int edge_aa_mask,
- const gfx::SizeF& bounds_size,
- const gfx::Transform& transform) {
- gfx::RectF pixel_frame_rect = gfx::RectF(bounds_size);
- transform.TransformRect(&pixel_frame_rect);
- return linked_ptr<OverlayPlane>(new OverlayPlane(
- z_order, io_surface_id, io_surface, contents_rect, opacity,
- background_color, edge_aa_mask, bounds_size, transform,
- pixel_frame_rect));
- }
-
- ~OverlayPlane() { DCHECK(!ca_layer); }
+ ~OverlayPlane() {
+ [ca_layer setContents:nil];
+ [ca_layer removeFromSuperlayer];
+ ca_layer.reset();
+ }
const int z_order;
- base::scoped_nsobject<CALayer> ca_layer;
-
- // The IOSurface to set the CALayer's contents to.
- const int io_surface_id;
const base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
const gfx::RectF contents_rect;
- float opacity;
- const base::ScopedCFTypeRef<CGColorRef> background_color;
- unsigned int edge_aa_mask;
- const gfx::SizeF bounds_size;
- const gfx::Transform transform;
-
const gfx::RectF pixel_frame_rect;
-
bool layer_needs_update;
-
- static bool Compare(const linked_ptr<OverlayPlane>& a,
- const linked_ptr<OverlayPlane>& b) {
- return (a->z_order < b->z_order);
- }
+ base::scoped_nsobject<CALayer> ca_layer;
void TakeCALayerFrom(OverlayPlane* other_plane) {
ca_layer.swap(other_plane->ca_layer);
}
- void UpdateProperties() {
+ void UpdateProperties(float scale_factor) {
if (layer_needs_update) {
[ca_layer setOpaque:YES];
id new_contents = static_cast<id>(io_surface.get());
- if ([ca_layer contents] == new_contents && z_order == 0) {
+ if ([ca_layer contents] == new_contents && z_order == 0)
[ca_layer setContentsChanged];
- } else {
+ else
[ca_layer setContents:new_contents];
- }
[ca_layer setContentsRect:contents_rect.ToCGRect()];
- [ca_layer setOpacity:opacity];
- if (background_color) {
- [ca_layer setBackgroundColor:background_color];
- } else {
- [ca_layer setBackgroundColor:CGColorGetConstantColor(kCGColorClear)];
- }
- [ca_layer setEdgeAntialiasingMask:edge_aa_mask];
-
[ca_layer setAnchorPoint:CGPointZero];
- [ca_layer setBounds:gfx::RectF(bounds_size).ToCGRect()];
- CATransform3D ca_transform;
- transform.matrix().asColMajord(&ca_transform.m11);
- [ca_layer setTransform:ca_transform];
+
+ if ([ca_layer respondsToSelector:(@selector(setContentsScale:))])
+ [ca_layer setContentsScale:scale_factor];
+ gfx::RectF dip_frame_rect = gfx::RectF(pixel_frame_rect);
+ dip_frame_rect.Scale(1 / scale_factor);
+ [ca_layer setBounds:CGRectMake(0, 0, dip_frame_rect.width(),
+ dip_frame_rect.height())];
+ [ca_layer
+ setPosition:CGPointMake(dip_frame_rect.x(), dip_frame_rect.y())];
}
static bool show_borders =
base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -188,9 +154,6 @@ class ImageTransportSurfaceOverlayMac::OverlayPlane {
if (!layer_needs_update) {
// Green represents contents that are unchanged across frames.
color.reset(CGColorCreateGenericRGB(0, 1, 0, 1));
- } else if (z_order != 0) {
- // Pink represents overlay planes
- color.reset(CGColorCreateGenericRGB(1, 0, 1, 1));
} else {
// Red represents damaged contents.
color.reset(CGColorCreateGenericRGB(1, 0, 0, 1));
@@ -201,34 +164,14 @@ class ImageTransportSurfaceOverlayMac::OverlayPlane {
layer_needs_update = false;
}
- void Destroy() {
- if (!ca_layer)
- return;
- [ca_layer setContents:nil];
- [ca_layer removeFromSuperlayer];
- ca_layer.reset();
- }
-
private:
OverlayPlane(int z_order,
- int io_surface_id,
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
const gfx::RectF& contents_rect,
- float opacity,
- base::ScopedCFTypeRef<CGColorRef> background_color,
- unsigned edge_aa_mask,
- const gfx::SizeF& bounds_size,
- const gfx::Transform& transform,
const gfx::RectF& pixel_frame_rect)
: z_order(z_order),
- io_surface_id(io_surface_id),
io_surface(io_surface),
contents_rect(contents_rect),
- opacity(opacity),
- background_color(background_color),
- edge_aa_mask(edge_aa_mask),
- bounds_size(bounds_size),
- transform(transform),
pixel_frame_rect(pixel_frame_rect),
layer_needs_update(true) {}
};
@@ -243,7 +186,7 @@ class ImageTransportSurfaceOverlayMac::PendingSwap {
gfx::Rect pixel_damage_rect;
linked_ptr<OverlayPlane> root_plane;
- std::vector<linked_ptr<OverlayPlane>> overlay_planes;
+ scoped_ptr<CALayerTree> ca_layer_tree;
std::vector<ui::LatencyInfo> latency_info;
// A fence object, and the CGL context it was issued in.
@@ -300,16 +243,8 @@ bool ImageTransportSurfaceOverlayMac::Initialize() {
void ImageTransportSurfaceOverlayMac::Destroy() {
DisplayAndClearAllPendingSwaps();
-
- if (current_root_plane_.get())
- current_root_plane_->Destroy();
- current_root_plane_.reset();
- for (auto& plane : current_partial_damage_planes_)
- plane->Destroy();
current_partial_damage_planes_.clear();
- for (auto& plane : current_overlay_planes_)
- plane->Destroy();
- current_overlay_planes_.clear();
+ current_root_plane_.reset();
}
bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
@@ -352,7 +287,7 @@ gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
new_swap->pixel_damage_rect = pixel_damage_rect;
new_swap->root_plane = pending_root_plane_;
pending_root_plane_ = linked_ptr<OverlayPlane>();
- new_swap->overlay_planes.swap(pending_overlay_planes_);
+ new_swap->ca_layer_tree.swap(pending_ca_layer_tree_);
new_swap->latency_info.swap(latency_info_);
// A flush is required to ensure that all content appears in the layer.
@@ -436,16 +371,10 @@ void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() {
// Sort the input planes by z-index, and remove any overlays from the
// damage rect.
gfx::RectF pixel_damage_rect = gfx::RectF(swap->pixel_damage_rect);
- std::sort(swap->overlay_planes.begin(), swap->overlay_planes.end(),
- OverlayPlane::Compare);
- for (auto& plane : swap->overlay_planes)
- pixel_damage_rect.Subtract(plane->pixel_frame_rect);
-
ScopedCAActionDisabler disabler;
UpdateRootAndPartialDamagePlanes(swap->root_plane, pixel_damage_rect);
- UpdateOverlayPlanes(swap->overlay_planes);
- UpdateCALayerTree();
- swap->overlay_planes.clear();
+ UpdateRootAndPartialDamageCALayers(swap->scale_factor);
+ UpdateCALayerTree(std::move(swap->ca_layer_tree), swap->scale_factor);
}
// Update the latency info to reflect the swap time.
@@ -475,27 +404,6 @@ void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() {
pending_swaps_.pop_front();
}
-void ImageTransportSurfaceOverlayMac::UpdateOverlayPlanes(
- const std::vector<linked_ptr<OverlayPlane>>& new_overlay_planes) {
- std::list<linked_ptr<OverlayPlane>> old_overlay_planes;
- old_overlay_planes.swap(current_overlay_planes_);
-
- // Move the new overlay planes into the |current_overlay_planes_| list,
- // cannibalizing from the old |current_overlay_planes_| as much as possible.
- for (auto& new_plane : new_overlay_planes) {
- if (!old_overlay_planes.empty()) {
- new_plane->TakeCALayerFrom(old_overlay_planes.front().get());
- old_overlay_planes.pop_front();
- }
- current_overlay_planes_.push_back(new_plane);
- }
-
- // Destroy any of the previous |current_overlay_planes_| that we couldn't
- // cannibalize.
- for (auto& old_plane : old_overlay_planes)
- old_plane->Destroy();
-}
-
void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
const linked_ptr<OverlayPlane>& new_root_plane,
const gfx::RectF& pixel_damage_rect) {
@@ -503,12 +411,9 @@ void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
old_partial_damage_planes.swap(current_partial_damage_planes_);
linked_ptr<OverlayPlane> plane_for_swap;
- // If there is no new root plane, destroy the old one.
+ // If there is no new root plane, remove everything.
if (!new_root_plane.get()) {
- for (auto& old_plane : old_partial_damage_planes)
- old_plane->Destroy();
- if (current_root_plane_.get())
- current_root_plane_->Destroy();
+ old_partial_damage_planes.clear();
current_root_plane_.reset();
return;
}
@@ -554,8 +459,8 @@ void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
1. / new_root_plane->pixel_frame_rect.height());
plane_for_swap = OverlayPlane::CreateWithFrameRect(
- 0, new_root_plane->io_surface_id, new_root_plane->io_surface,
- plane_to_reuse_dip_enlarged_rect, enlarged_contents_rect);
+ 0, new_root_plane->io_surface, plane_to_reuse_dip_enlarged_rect,
+ enlarged_contents_rect);
plane_for_swap->TakeCALayerFrom(plane_to_reuse.get());
if (plane_to_reuse != old_partial_damage_planes.back())
@@ -571,8 +476,7 @@ void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
contents_rect.Scale(1. / new_root_plane->pixel_frame_rect.width(),
1. / new_root_plane->pixel_frame_rect.height());
plane_for_swap = OverlayPlane::CreateWithFrameRect(
- 0, new_root_plane->io_surface_id, new_root_plane->io_surface,
- pixel_damage_rect, contents_rect);
+ 0, new_root_plane->io_surface, pixel_damage_rect, contents_rect);
}
// And if we still don't have a layer, use the root layer.
@@ -588,10 +492,12 @@ void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
gfx::RectF old_plane_frame_rect = old_plane->pixel_frame_rect;
old_plane_frame_rect.Intersect(new_root_plane->pixel_frame_rect);
+ bool old_plane_covered_by_swap = false;
if (plane_for_swap.get() &&
plane_for_swap->pixel_frame_rect.Contains(old_plane_frame_rect)) {
- old_plane->Destroy();
- } else {
+ old_plane_covered_by_swap = true;
+ }
+ if (!old_plane_covered_by_swap) {
DCHECK(old_plane->ca_layer);
current_partial_damage_planes_.push_back(old_plane);
}
@@ -599,36 +505,27 @@ void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamagePlanes(
// Finally, add the new swap's plane at the back of the list, if it exists.
if (plane_for_swap == new_root_plane) {
- if (current_root_plane_.get()) {
- plane_for_swap->TakeCALayerFrom(current_root_plane_.get());
- } else {
- plane_for_swap->ca_layer = ca_root_layer_;
- }
current_root_plane_ = new_root_plane;
} else if (plane_for_swap.get()) {
current_partial_damage_planes_.push_back(plane_for_swap);
}
}
-void ImageTransportSurfaceOverlayMac::UpdateCALayerTree() {
+void ImageTransportSurfaceOverlayMac::UpdateRootAndPartialDamageCALayers(
+ float scale_factor) {
if (!use_remote_layer_api_) {
- DCHECK(current_overlay_planes_.empty());
DCHECK(current_partial_damage_planes_.empty());
return;
}
- // Allocate new CALayers as needed. Overlay layers are always added to the
- // back of the list.
- CALayer* first_overlay_ca_layer = nil;
- for (auto& plane : current_overlay_planes_) {
- if (!plane->ca_layer) {
- plane->ca_layer.reset([[CALayer alloc] init]);
- [ca_root_layer_ addSublayer:plane->ca_layer];
+ // Allocate and update CALayers for the backbuffer and partial damage layers.
+ if (current_root_plane_.get()) {
+ if (!current_root_plane_->ca_layer) {
+ current_root_plane_->ca_layer.reset([[CALayer alloc] init]);
+ [ca_root_layer_ setSublayers:nil];
+ [ca_root_layer_ addSublayer:current_root_plane_->ca_layer];
}
- if (!first_overlay_ca_layer)
- first_overlay_ca_layer = plane->ca_layer;
}
- // Partial damage layers are inserted below the overlay layers.
for (auto& plane : current_partial_damage_planes_) {
if (!plane->ca_layer) {
DCHECK(plane == current_partial_damage_planes_.back());
@@ -636,28 +533,26 @@ void ImageTransportSurfaceOverlayMac::UpdateCALayerTree() {
}
if (![plane->ca_layer superlayer]) {
DCHECK(plane == current_partial_damage_planes_.back());
- if (first_overlay_ca_layer) {
- [ca_root_layer_ insertSublayer:plane->ca_layer
- below:first_overlay_ca_layer];
- } else {
- [ca_root_layer_ addSublayer:plane->ca_layer];
- }
+ [ca_root_layer_ addSublayer:plane->ca_layer];
}
}
-
- // Update CALayer contents, frames, and borders.
if (current_root_plane_.get())
- current_root_plane_->UpdateProperties();
+ current_root_plane_->UpdateProperties(scale_factor);
for (auto& plane : current_partial_damage_planes_)
- plane->UpdateProperties();
- for (auto& plane : current_overlay_planes_)
- plane->UpdateProperties();
- [ca_root_layer_ setTransform:CATransform3DMakeScale(1 / scale_factor_,
- 1 / scale_factor_, 1)];
+ plane->UpdateProperties(scale_factor);
+}
- DCHECK_EQ(
- static_cast<size_t>([[ca_root_layer_ sublayers] count]),
- current_partial_damage_planes_.size() + current_overlay_planes_.size());
+void ImageTransportSurfaceOverlayMac::UpdateCALayerTree(
+ scoped_ptr<CALayerTree> ca_layer_tree,
+ float scale_factor) {
+ if (ca_layer_tree) {
+ ca_layer_tree->CommitScheduledCALayers(
+ ca_root_layer_.get(), std::move(current_ca_layer_tree_), scale_factor);
+ current_ca_layer_tree_.swap(ca_layer_tree);
+ ca_layer_tree.reset();
+ } else {
+ current_ca_layer_tree_.reset();
+ }
}
void ImageTransportSurfaceOverlayMac::DisplayAndClearAllPendingSwaps() {
@@ -742,19 +637,18 @@ bool ImageTransportSurfaceOverlayMac::ScheduleOverlayPlane(
gl::GLImage* image,
const gfx::Rect& pixel_frame_rect,
const gfx::RectF& crop_rect) {
- DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
- if (transform != gfx::OVERLAY_TRANSFORM_NONE)
+ if (transform != gfx::OVERLAY_TRANSFORM_NONE) {
+ DLOG(ERROR) << "Invalid overlay plane transform.";
return false;
+ }
+ if (z_order) {
+ DLOG(ERROR) << "Invalid non-zero Z order.";
+ return false;
+ }
- linked_ptr<OverlayPlane> plane = OverlayPlane::CreateWithFrameRect(
- z_order, static_cast<gl::GLImageIOSurface*>(image)->io_surface_id().id,
- static_cast<gl::GLImageIOSurface*>(image)->io_surface(),
+ pending_root_plane_ = OverlayPlane::CreateWithFrameRect(
+ z_order, static_cast<gl::GLImageIOSurface*>(image)->io_surface(),
gfx::RectF(pixel_frame_rect), crop_rect);
- if (z_order == 0)
- pending_root_plane_ = plane;
- else
- pending_overlay_planes_.push_back(plane);
-
return true;
}
@@ -764,35 +658,22 @@ bool ImageTransportSurfaceOverlayMac::ScheduleCALayer(
float opacity,
unsigned background_color,
unsigned edge_aa_mask,
- const gfx::RectF& bounds_rect,
+ const gfx::RectF& rect,
bool is_clipped,
const gfx::RectF& clip_rect,
- const gfx::Transform& transform) {
- // Extract the IOSurface, if this layer is not just a solid color.
- int io_surface_id = 0;
+ const gfx::Transform& transform,
+ int sorting_context_id) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
if (contents_image) {
- io_surface_id =
- static_cast<gl::GLImageIOSurface*>(contents_image)->io_surface_id().id;
io_surface =
static_cast<gl::GLImageIOSurface*>(contents_image)->io_surface();
}
-
- // Convert the RGBA SkColor to an sRGB CGColorRef.
- CGFloat rgba_color_components[4] = {
- SkColorGetR(background_color) / 255.,
- SkColorGetG(background_color) / 255.,
- SkColorGetB(background_color) / 255.,
- SkColorGetA(background_color) / 255.,
- };
- base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate(
- CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components));
-
- pending_overlay_planes_.push_back(OverlayPlane::CreateWithTransform(
- next_ca_layer_z_order_++, io_surface_id, io_surface, contents_rect,
- opacity, srgb_background_color, edge_aa_mask, bounds_rect.size(),
- transform));
- return true;
+ if (!pending_ca_layer_tree_)
+ pending_ca_layer_tree_.reset(new CALayerTree);
+ return pending_ca_layer_tree_->ScheduleCALayer(
+ is_clipped, gfx::ToEnclosingRect(clip_rect), sorting_context_id,
+ transform, io_surface, contents_rect, gfx::ToEnclosingRect(rect),
+ background_color, edge_aa_mask, opacity);
}
bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
diff --git a/content/content_common.gypi b/content/content_common.gypi
index f7cfbdd..f3e8820 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -320,6 +320,8 @@
'common/gpu/client/grcontext_for_webgraphicscontext3d.h',
'common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc',
'common/gpu/client/webgraphicscontext3d_command_buffer_impl.h',
+ 'common/gpu/ca_layer_tree_mac.h',
+ 'common/gpu/ca_layer_tree_mac.mm',
'common/gpu/child_window_surface_win.cc',
'common/gpu/child_window_surface_win.h',
'common/gpu/gpu_channel.cc',
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 0ce1f6d..e4875a4 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -19,3 +19,7 @@ class PixelExpectations(GpuTestExpectations):
['mac'], bug=540039)
self.Fail('Pixel.WebGLGreenTriangleES3',
['mac', ('intel', 0x116)], bug=540531)
+
+ # TODO(ccameron): Remove suppression after rebaseline.
+ self.Fail('Pixel.CSS3DBlueBox', ['mac'], bug=533690)
+ self.Fail('Pixel.CSS3DBlueBoxES3', ['mac'], bug=533690)
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9538614..90d3062 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -9644,7 +9644,7 @@ error::Error GLES2DecoderImpl::HandleScheduleCALayerCHROMIUM(
if (!surface_->ScheduleCALayer(image, contents_rect, c.opacity,
c.background_color, c.edge_aa_mask,
bounds_rect, c.is_clipped ? true : false,
- clip_rect, transform)) {
+ clip_rect, transform, c.sorting_context_id)) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glScheduleCALayerCHROMIUM",
"failed to schedule CALayer");
}
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 768bfa9..a20356e 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -209,10 +209,11 @@ bool GLSurface::ScheduleCALayer(gl::GLImage* contents_image,
float opacity,
unsigned background_color,
unsigned edge_aa_mask,
- const RectF& bounds_rect,
+ const RectF& rect,
bool is_clipped,
const RectF& clip_rect,
- const Transform& transform) {
+ const Transform& transform,
+ int sorting_content_id) {
NOTIMPLEMENTED();
return false;
}
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 066435a..d84f391 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -174,10 +174,11 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> {
float opacity,
unsigned background_color,
unsigned edge_aa_mask,
- const RectF& bounds_rect,
+ const RectF& rect,
bool is_clipped,
const RectF& clip_rect,
- const Transform& transform);
+ const Transform& transform,
+ int sorting_content_id);
virtual bool IsSurfaceless() const;