Skip to content
This repository was archived by the owner on Apr 3, 2020. It is now read-only.

Commit 04f51c6

Browse files
Mac overlays: Clean up partial swap code
Remove use of linked_ptr, because it's not necessary now that we have C++11 support. Separate out functions to be a bit easier to read and follow. Remove unnecessary uses of RectF when Rect would do. BUG=533681 Review URL: https://codereview.chromium.org/1643043002 Cr-Commit-Position: refs/heads/master@{#372707} (cherry picked from commit 4d0aa96) Mac overlays: Move CALayerPartialDamageTree to its own file Direct copy-paste, no changes. BUG=533681 TBR=erikchen Review URL: https://codereview.chromium.org/1647523002 Cr-Commit-Position: refs/heads/master@{#371871} (cherry picked from commit 9a9014a) Mac overlays: Isolate partial swap support The logic to maintain a CALayer tree for partial swap support is complicated and should be removed, but that would compromise battery usage. Once the CoreAniamtion renderer is handling ~99% of the frames, we can remove it. In the mean time, isolate it. Create a CALayerPartialDamageTree to track the layer tree of partially swapped backbuffers. Do this in-place to minimize diffs, so that this patch can be reasonably reviewed. A follow-on patch will move it to a separate file. Slightly reorganize the logic so that CALayerPartialDamageTree matches the general structure of CALayerTree, where this a pending (not swapped) tree, a tree for each pending swap, and a tree for what is currently being displayed. BUG=533681 Review URL: https://codereview.chromium.org/1640093002 Cr-Commit-Position: refs/heads/master@{#371831} (cherry picked from commit 8aa00fc) Review URL: https://codereview.chromium.org/1661453003 . Cr-Commit-Position: refs/branch-heads/2623@{#249} Cr-Branched-From: 92d7753-refs/heads/master@{#369907}
1 parent 1fb5ee6 commit 04f51c6

File tree

5 files changed

+376
-281
lines changed

5 files changed

+376
-281
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2016 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_
6+
#define CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_
7+
8+
#include <IOSurface/IOSurface.h>
9+
#include <QuartzCore/QuartzCore.h>
10+
#include <deque>
11+
12+
#include "base/mac/scoped_cftyperef.h"
13+
#include "base/memory/scoped_ptr.h"
14+
#include "ui/gfx/geometry/rect.h"
15+
#include "ui/gfx/geometry/rect_f.h"
16+
17+
namespace content {
18+
19+
class CALayerPartialDamageTree {
20+
public:
21+
CALayerPartialDamageTree(bool allow_partial_swap,
22+
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
23+
const gfx::Rect& pixel_frame_rect);
24+
~CALayerPartialDamageTree();
25+
26+
base::ScopedCFTypeRef<IOSurfaceRef> RootLayerIOSurface();
27+
void CommitCALayers(CALayer* superlayer,
28+
scoped_ptr<CALayerPartialDamageTree> old_tree,
29+
float scale_factor,
30+
const gfx::Rect& pixel_damage_rect);
31+
32+
private:
33+
class OverlayPlane;
34+
35+
// This will populate |partial_damage_planes_|, potentially re-using the
36+
// CALayers and |partial_damage_planes_| from |old_tree|. After this function
37+
// completes, the back() of |partial_damage_planes_| is the plane that will
38+
// be updated this frame (and if it is empty, then the root plane will be
39+
// updated).
40+
void UpdatePartialDamagePlanes(CALayerPartialDamageTree* old_tree,
41+
const gfx::Rect& pixel_damage_rect);
42+
43+
void UpdateRootAndPartialDamagePlanes(
44+
scoped_ptr<CALayerPartialDamageTree> old_tree,
45+
const gfx::Rect& pixel_damage_rect);
46+
47+
void UpdateCALayers(CALayer* superlayer, float scale_factor);
48+
49+
const bool allow_partial_swap_;
50+
scoped_ptr<OverlayPlane> root_plane_;
51+
std::deque<scoped_ptr<OverlayPlane>> partial_damage_planes_;
52+
};
53+
54+
} // content
55+
56+
#endif // CONTENT_COMMON_GPU_CA_LAYER_PARTIAL_DAMAGE_TREE_MAC_H_
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
// Copyright 2016 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "content/common/gpu/ca_layer_partial_damage_tree_mac.h"
6+
7+
#include "base/command_line.h"
8+
#include "base/mac/scoped_nsobject.h"
9+
#include "base/mac/sdk_forward_declarations.h"
10+
#include "ui/base/ui_base_switches.h"
11+
#include "ui/gfx/transform.h"
12+
13+
@interface CALayer(Private)
14+
-(void)setContentsChanged;
15+
@end
16+
17+
namespace content {
18+
namespace {
19+
20+
// When selecting a CALayer to re-use for partial damage, this is the maximum
21+
// fraction of the merged layer's pixels that may be not-updated by the swap
22+
// before we consider the CALayer to not be a good enough match, and create a
23+
// new one.
24+
const float kMaximumPartialDamageWasteFraction = 1.2f;
25+
26+
// The maximum number of partial damage layers that may be created before we
27+
// give up and remove them all (doing full damage in the process).
28+
const size_t kMaximumPartialDamageLayers = 8;
29+
30+
} // namespace
31+
32+
class CALayerPartialDamageTree::OverlayPlane {
33+
public:
34+
OverlayPlane(base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
35+
const gfx::Rect& pixel_frame_rect,
36+
const gfx::RectF& contents_rect)
37+
: io_surface(io_surface),
38+
contents_rect(contents_rect),
39+
pixel_frame_rect(pixel_frame_rect),
40+
layer_needs_update(true) {}
41+
42+
~OverlayPlane() {
43+
[ca_layer setContents:nil];
44+
[ca_layer removeFromSuperlayer];
45+
ca_layer.reset();
46+
}
47+
48+
const base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
49+
const gfx::RectF contents_rect;
50+
const gfx::Rect pixel_frame_rect;
51+
bool layer_needs_update;
52+
base::scoped_nsobject<CALayer> ca_layer;
53+
54+
void TakeCALayerFrom(OverlayPlane* other_plane) {
55+
ca_layer.swap(other_plane->ca_layer);
56+
}
57+
58+
void UpdateProperties(float scale_factor) {
59+
if (layer_needs_update) {
60+
[ca_layer setOpaque:YES];
61+
62+
id new_contents = static_cast<id>(io_surface.get());
63+
if ([ca_layer contents] == new_contents)
64+
[ca_layer setContentsChanged];
65+
else
66+
[ca_layer setContents:new_contents];
67+
[ca_layer setContentsRect:contents_rect.ToCGRect()];
68+
69+
[ca_layer setAnchorPoint:CGPointZero];
70+
71+
if ([ca_layer respondsToSelector:(@selector(setContentsScale:))])
72+
[ca_layer setContentsScale:scale_factor];
73+
gfx::RectF dip_frame_rect = gfx::RectF(pixel_frame_rect);
74+
dip_frame_rect.Scale(1 / scale_factor);
75+
[ca_layer setBounds:CGRectMake(0, 0, dip_frame_rect.width(),
76+
dip_frame_rect.height())];
77+
[ca_layer
78+
setPosition:CGPointMake(dip_frame_rect.x(), dip_frame_rect.y())];
79+
}
80+
static bool show_borders =
81+
base::CommandLine::ForCurrentProcess()->HasSwitch(
82+
switches::kShowMacOverlayBorders);
83+
if (show_borders) {
84+
base::ScopedCFTypeRef<CGColorRef> color;
85+
if (!layer_needs_update) {
86+
// Green represents contents that are unchanged across frames.
87+
color.reset(CGColorCreateGenericRGB(0, 1, 0, 1));
88+
} else {
89+
// Red represents damaged contents.
90+
color.reset(CGColorCreateGenericRGB(1, 0, 0, 1));
91+
}
92+
[ca_layer setBorderWidth:1];
93+
[ca_layer setBorderColor:color];
94+
}
95+
layer_needs_update = false;
96+
}
97+
98+
private:
99+
};
100+
101+
void CALayerPartialDamageTree::UpdatePartialDamagePlanes(
102+
CALayerPartialDamageTree* old_tree,
103+
const gfx::Rect& pixel_damage_rect) {
104+
// Don't create partial damage layers if partial swap is disabled.
105+
if (!allow_partial_swap_)
106+
return;
107+
// Only create partial damage layers when building on top of an existing tree.
108+
if (!old_tree)
109+
return;
110+
// If the frame size has changed, discard all of the old partial damage
111+
// layers.
112+
if (old_tree->root_plane_->pixel_frame_rect != root_plane_->pixel_frame_rect)
113+
return;
114+
// If there is full damage, discard all of the old partial damage layers.
115+
if (pixel_damage_rect == root_plane_->pixel_frame_rect)
116+
return;
117+
118+
// If there is no damage, don't change anything.
119+
if (pixel_damage_rect.IsEmpty()) {
120+
std::swap(partial_damage_planes_, old_tree->partial_damage_planes_);
121+
return;
122+
}
123+
124+
// Find the last partial damage plane to re-use the CALayer from. Grow the
125+
// new rect for this layer to include this damage, and all nearby partial
126+
// damage layers.
127+
scoped_ptr<OverlayPlane> plane_for_swap;
128+
{
129+
auto plane_to_reuse_iter = old_tree->partial_damage_planes_.end();
130+
gfx::Rect plane_to_reuse_enlarged_pixel_damage_rect;
131+
132+
for (auto old_plane_iter = old_tree->partial_damage_planes_.begin();
133+
old_plane_iter != old_tree->partial_damage_planes_.end();
134+
++old_plane_iter) {
135+
gfx::Rect enlarged_pixel_damage_rect =
136+
(*old_plane_iter)->pixel_frame_rect;
137+
enlarged_pixel_damage_rect.Union(pixel_damage_rect);
138+
139+
// Compute the fraction of the pixels that would not be updated by this
140+
// swap. If it is too big, try another layer.
141+
float waste_fraction = enlarged_pixel_damage_rect.size().GetArea() * 1.f /
142+
pixel_damage_rect.size().GetArea();
143+
if (waste_fraction > kMaximumPartialDamageWasteFraction)
144+
continue;
145+
146+
plane_to_reuse_iter = old_plane_iter;
147+
plane_to_reuse_enlarged_pixel_damage_rect.Union(
148+
enlarged_pixel_damage_rect);
149+
}
150+
if (plane_to_reuse_iter != old_tree->partial_damage_planes_.end()) {
151+
gfx::RectF enlarged_contents_rect =
152+
gfx::RectF(plane_to_reuse_enlarged_pixel_damage_rect);
153+
enlarged_contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(),
154+
1. / root_plane_->pixel_frame_rect.height());
155+
156+
plane_for_swap.reset(new OverlayPlane(
157+
root_plane_->io_surface, plane_to_reuse_enlarged_pixel_damage_rect,
158+
enlarged_contents_rect));
159+
160+
plane_for_swap->TakeCALayerFrom((*plane_to_reuse_iter).get());
161+
if (*plane_to_reuse_iter != old_tree->partial_damage_planes_.back()) {
162+
CALayer* superlayer = [plane_for_swap->ca_layer superlayer];
163+
[plane_for_swap->ca_layer removeFromSuperlayer];
164+
[superlayer addSublayer:plane_for_swap->ca_layer];
165+
}
166+
}
167+
}
168+
169+
// If we haven't found an appropriate layer to re-use, create a new one, if
170+
// we haven't already created too many.
171+
if (!plane_for_swap.get() &&
172+
old_tree->partial_damage_planes_.size() < kMaximumPartialDamageLayers) {
173+
gfx::RectF contents_rect = gfx::RectF(pixel_damage_rect);
174+
contents_rect.Scale(1. / root_plane_->pixel_frame_rect.width(),
175+
1. / root_plane_->pixel_frame_rect.height());
176+
plane_for_swap.reset(new OverlayPlane(root_plane_->io_surface,
177+
pixel_damage_rect, contents_rect));
178+
}
179+
180+
// And if we still don't have a layer, do full damage.
181+
if (!plane_for_swap.get())
182+
return;
183+
184+
// Walk all old partial damage planes. Remove anything that is now completely
185+
// covered, and move everything else into the new |partial_damage_planes_|.
186+
for (auto& old_plane : old_tree->partial_damage_planes_) {
187+
if (!old_plane.get())
188+
continue;
189+
// Intersect the planes' frames with the new root plane to ensure that
190+
// they don't get kept alive inappropriately.
191+
gfx::Rect old_plane_frame_rect = old_plane->pixel_frame_rect;
192+
old_plane_frame_rect.Intersect(root_plane_->pixel_frame_rect);
193+
194+
bool old_plane_covered_by_swap = false;
195+
if (plane_for_swap.get() &&
196+
plane_for_swap->pixel_frame_rect.Contains(old_plane_frame_rect)) {
197+
old_plane_covered_by_swap = true;
198+
}
199+
if (!old_plane_covered_by_swap) {
200+
DCHECK(old_plane->ca_layer);
201+
partial_damage_planes_.push_back(std::move(old_plane));
202+
}
203+
}
204+
205+
partial_damage_planes_.push_back(std::move(plane_for_swap));
206+
}
207+
208+
void CALayerPartialDamageTree::UpdateRootAndPartialDamagePlanes(
209+
scoped_ptr<CALayerPartialDamageTree> old_tree,
210+
const gfx::Rect& pixel_damage_rect) {
211+
// First update the partial damage tree.
212+
UpdatePartialDamagePlanes(old_tree.get(), pixel_damage_rect);
213+
if (old_tree) {
214+
if (partial_damage_planes_.empty()) {
215+
// If there are no partial damage planes, then we will be updating the
216+
// root layer. Take the CALayer from the old tree.
217+
root_plane_->TakeCALayerFrom(old_tree->root_plane_.get());
218+
} else {
219+
// If there is a partial damage tree, then just take the old plane
220+
// from the previous frame, so that there is no update to it.
221+
root_plane_.swap(old_tree->root_plane_);
222+
}
223+
}
224+
}
225+
226+
void CALayerPartialDamageTree::UpdateCALayers(CALayer* superlayer,
227+
float scale_factor) {
228+
if (!allow_partial_swap_) {
229+
DCHECK(partial_damage_planes_.empty());
230+
return;
231+
}
232+
233+
// Allocate and update CALayers for the backbuffer and partial damage layers.
234+
if (!root_plane_->ca_layer) {
235+
DCHECK(partial_damage_planes_.empty());
236+
root_plane_->ca_layer.reset([[CALayer alloc] init]);
237+
[superlayer setSublayers:nil];
238+
[superlayer addSublayer:root_plane_->ca_layer];
239+
}
240+
for (auto& plane : partial_damage_planes_) {
241+
if (!plane->ca_layer) {
242+
DCHECK(plane == partial_damage_planes_.back());
243+
plane->ca_layer.reset([[CALayer alloc] init]);
244+
}
245+
if (![plane->ca_layer superlayer]) {
246+
DCHECK(plane == partial_damage_planes_.back());
247+
[superlayer addSublayer:plane->ca_layer];
248+
}
249+
}
250+
root_plane_->UpdateProperties(scale_factor);
251+
for (auto& plane : partial_damage_planes_)
252+
plane->UpdateProperties(scale_factor);
253+
}
254+
255+
CALayerPartialDamageTree::CALayerPartialDamageTree(
256+
bool allow_partial_swap,
257+
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
258+
const gfx::Rect& pixel_frame_rect)
259+
: allow_partial_swap_(allow_partial_swap) {
260+
root_plane_.reset(
261+
new OverlayPlane(io_surface, pixel_frame_rect, gfx::RectF(0, 0, 1, 1)));
262+
}
263+
264+
CALayerPartialDamageTree::~CALayerPartialDamageTree() {}
265+
266+
base::ScopedCFTypeRef<IOSurfaceRef>
267+
CALayerPartialDamageTree::RootLayerIOSurface() {
268+
return root_plane_->io_surface;
269+
}
270+
271+
void CALayerPartialDamageTree::CommitCALayers(
272+
CALayer* superlayer,
273+
scoped_ptr<CALayerPartialDamageTree> old_tree,
274+
float scale_factor,
275+
const gfx::Rect& pixel_damage_rect) {
276+
UpdateRootAndPartialDamagePlanes(std::move(old_tree), pixel_damage_rect);
277+
UpdateCALayers(superlayer, scale_factor);
278+
}
279+
280+
} // namespace content

content/common/gpu/image_transport_surface_overlay_mac.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <list>
99
#include <vector>
1010

11-
#include "base/memory/linked_ptr.h"
1211
#import "base/mac/scoped_nsobject.h"
1312
#include "base/timer/timer.h"
1413
#include "content/common/gpu/gpu_command_buffer_stub.h"
@@ -22,6 +21,7 @@
2221
namespace content {
2322

2423
class CALayerTree;
24+
class CALayerPartialDamageTree;
2525

2626
class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
2727
public ImageTransportSurface,
@@ -78,13 +78,6 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
7878

7979
gfx::SwapResult SwapBuffersInternal(const gfx::Rect& pixel_damage_rect);
8080

81-
void UpdateRootAndPartialDamagePlanes(
82-
const linked_ptr<OverlayPlane>& new_root_plane,
83-
const gfx::RectF& pixel_damage_rect);
84-
void UpdateRootAndPartialDamageCALayers(float scale_factor);
85-
void UpdateCALayerTree(scoped_ptr<CALayerTree> ca_layer_tree,
86-
float scale_factor);
87-
8881
// Returns true if the front of |pending_swaps_| has completed, or has timed
8982
// out by |now|.
9083
bool IsFirstPendingSwapReadyToDisplay(
@@ -125,7 +118,7 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
125118

126119
// Planes that have been scheduled, but have not had a subsequent SwapBuffers
127120
// call made yet.
128-
linked_ptr<OverlayPlane> pending_root_plane_;
121+
scoped_ptr<CALayerPartialDamageTree> pending_partial_damage_tree_;
129122
scoped_ptr<CALayerTree> pending_ca_layer_tree_;
130123

131124
// A queue of all frames that have been created by SwapBuffersInternal but
@@ -134,8 +127,7 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
134127
std::deque<linked_ptr<PendingSwap>> pending_swaps_;
135128

136129
// The planes that are currently being displayed on the screen.
137-
linked_ptr<OverlayPlane> current_root_plane_;
138-
std::list<linked_ptr<OverlayPlane>> current_partial_damage_planes_;
130+
scoped_ptr<CALayerPartialDamageTree> current_partial_damage_tree_;
139131
scoped_ptr<CALayerTree> current_ca_layer_tree_;
140132

141133
// The time of the last swap was issued. If this is more than two vsyncs, then
@@ -147,10 +139,6 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
147139
base::TimeTicks vsync_timebase_;
148140
base::TimeDelta vsync_interval_;
149141

150-
// Calls to ScheduleCALayer come in back-to-front. This is reset to 1 at each
151-
// swap and increments with each call to ScheduleCALayer.
152-
int next_ca_layer_z_order_;
153-
154142
base::Timer display_pending_swap_timer_;
155143
base::WeakPtrFactory<ImageTransportSurfaceOverlayMac> weak_factory_;
156144
};

0 commit comments

Comments
 (0)