Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: content/common/gpu/ca_layer_partial_damage_tree_mac.mm

Issue 1661453003: Mac overlays: Clean up partial swap code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2623
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
OLDNEW
« no previous file with comments | « content/common/gpu/ca_layer_partial_damage_tree_mac.h ('k') | content/common/gpu/image_transport_surface_overlay_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698