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

Side by Side Diff: content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm

Issue 753933002: MacViews: Move content::AcceleratedWidget to new component, ui/accelerated_widget_mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@20141124-MacViews-MoveSoftwareLayerMac-fromcl
Patch Set: nit DEPS, deps and gn Created 6 years 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 2014 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/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
6
7 #include <map>
8
9 #include "cc/output/software_frame_data.h"
10 #include "base/debug/trace_event.h"
11 #include "base/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "content/browser/compositor/io_surface_layer_mac.h"
14 #include "content/browser/renderer_host/dip_util.h"
15 #include "content/common/gpu/surface_handle_types_mac.h"
16 #include "content/public/browser/context_factory.h"
17 #include "ui/base/cocoa/animation_utils.h"
18 #include "ui/gl/scoped_cgl.h"
19
20 namespace content {
21 namespace {
22
23 typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*>
24 WidgetToHelperMap;
25 base::LazyInstance<WidgetToHelperMap> g_widget_to_helper_map;
26
27 AcceleratedWidgetMac* GetHelperFromAcceleratedWidget(
28 gfx::AcceleratedWidget widget) {
29 WidgetToHelperMap::const_iterator found =
30 g_widget_to_helper_map.Pointer()->find(widget);
31 // This can end up being accessed after the underlying widget has been
32 // destroyed, but while the ui::Compositor is still being destroyed.
33 // Return NULL in these cases.
34 if (found == g_widget_to_helper_map.Pointer()->end())
35 return NULL;
36 return found->second;
37 }
38
39 }
40
41 ////////////////////////////////////////////////////////////////////////////////
42 // AcceleratedWidgetMac
43
44 AcceleratedWidgetMac::AcceleratedWidgetMac()
45 : view_(NULL) {
46 // Disable the fade-in animation as the layers are added.
47 ScopedCAActionDisabler disabler;
48
49 // Add a flipped transparent layer as a child, so that we don't need to
50 // fiddle with the position of sub-layers -- they will always be at the
51 // origin.
52 flipped_layer_.reset([[CALayer alloc] init]);
53 [flipped_layer_ setGeometryFlipped:YES];
54 [flipped_layer_ setAnchorPoint:CGPointMake(0, 0)];
55 [flipped_layer_
56 setAutoresizingMask:kCALayerWidthSizable|kCALayerHeightSizable];
57
58 // Use a sequence number as the accelerated widget handle that we can use
59 // to look up the internals structure.
60 static uintptr_t last_sequence_number = 0;
61 last_sequence_number += 1;
62 native_widget_ = reinterpret_cast<gfx::AcceleratedWidget>(
63 last_sequence_number);
64 g_widget_to_helper_map.Pointer()->insert(
65 std::make_pair(native_widget_, this));
66 }
67
68 AcceleratedWidgetMac::~AcceleratedWidgetMac() {
69 DCHECK(!view_);
70 g_widget_to_helper_map.Pointer()->erase(native_widget_);
71 }
72
73 void AcceleratedWidgetMac::SetNSView(AcceleratedWidgetMacNSView* view) {
74 // Disable the fade-in animation as the view is added.
75 ScopedCAActionDisabler disabler;
76
77 DCHECK(view && !view_);
78 view_ = view;
79
80 CALayer* background_layer = [view_->AcceleratedWidgetGetNSView() layer];
81 DCHECK(background_layer);
82 [flipped_layer_ setBounds:[background_layer bounds]];
83 [background_layer addSublayer:flipped_layer_];
84 }
85
86 void AcceleratedWidgetMac::ResetNSView() {
87 if (!view_)
88 return;
89
90 // Disable the fade-out animation as the view is removed.
91 ScopedCAActionDisabler disabler;
92
93 [flipped_layer_ removeFromSuperlayer];
94 DestroyIOSurfaceLayer(io_surface_layer_);
95 DestroyCAContextLayer(ca_context_layer_);
96 DestroySoftwareLayer();
97
98 last_swap_size_dip_ = gfx::Size();
99 view_ = NULL;
100 }
101
102 bool AcceleratedWidgetMac::HasFrameOfSize(
103 const gfx::Size& dip_size) const {
104 return last_swap_size_dip_ == dip_size;
105 }
106
107 int AcceleratedWidgetMac::GetRendererID() const {
108 if (io_surface_layer_)
109 return [io_surface_layer_ rendererID];
110 return 0;
111 }
112
113 bool AcceleratedWidgetMac::IsRendererThrottlingDisabled() const {
114 if (view_)
115 return view_->AcceleratedWidgetShouldIgnoreBackpressure();
116 return false;
117 }
118
119 void AcceleratedWidgetMac::BeginPumpingFrames() {
120 [io_surface_layer_ beginPumpingFrames];
121 }
122
123 void AcceleratedWidgetMac::EndPumpingFrames() {
124 [io_surface_layer_ endPumpingFrames];
125 }
126
127 void AcceleratedWidgetMac::GotAcceleratedFrame(
128 uint64 surface_handle,
129 const std::vector<ui::LatencyInfo>& latency_info,
130 gfx::Size pixel_size, float scale_factor,
131 const base::Closure& drawn_callback) {
132 // Record the surface and latency info to use when acknowledging this frame.
133 DCHECK(accelerated_frame_drawn_callback_.is_null());
134 accelerated_frame_drawn_callback_ = drawn_callback;
135 accelerated_latency_info_.insert(accelerated_latency_info_.end(),
136 latency_info.begin(), latency_info.end());
137
138 // If there is no view and therefore no superview to draw into, early-out.
139 if (!view_) {
140 AcknowledgeAcceleratedFrame();
141 return;
142 }
143
144 // Disable the fade-in or fade-out effect if we create or remove layers.
145 ScopedCAActionDisabler disabler;
146
147 last_swap_size_dip_ = ConvertSizeToDIP(scale_factor, pixel_size);
148 switch (GetSurfaceHandleType(surface_handle)) {
149 case kSurfaceHandleTypeIOSurface: {
150 IOSurfaceID io_surface_id = IOSurfaceIDFromSurfaceHandle(surface_handle);
151 GotAcceleratedIOSurfaceFrame(io_surface_id, pixel_size, scale_factor);
152 break;
153 }
154 case kSurfaceHandleTypeCAContext: {
155 CAContextID ca_context_id = CAContextIDFromSurfaceHandle(surface_handle);
156 GotAcceleratedCAContextFrame(ca_context_id, pixel_size, scale_factor);
157 break;
158 }
159 default:
160 LOG(ERROR) << "Unrecognized accelerated frame type.";
161 return;
162 }
163 }
164
165 void AcceleratedWidgetMac::GotAcceleratedCAContextFrame(
166 CAContextID ca_context_id,
167 gfx::Size pixel_size,
168 float scale_factor) {
169 // In the layer is replaced, keep the old one around until after the new one
170 // is installed to avoid flashes.
171 base::scoped_nsobject<CALayerHost> old_ca_context_layer =
172 ca_context_layer_;
173
174 // Create the layer to host the layer exported by the GPU process with this
175 // particular CAContext ID.
176 if ([ca_context_layer_ contextId] != ca_context_id) {
177 ca_context_layer_.reset([[CALayerHost alloc] init]);
178 [ca_context_layer_ setContextId:ca_context_id];
179 [ca_context_layer_
180 setAutoresizingMask:kCALayerMaxXMargin|kCALayerMaxYMargin];
181 [flipped_layer_ addSublayer:ca_context_layer_];
182 }
183
184 // Acknowledge the frame to unblock the compositor immediately (the GPU
185 // process will do any required throttling).
186 AcknowledgeAcceleratedFrame();
187
188 // If this replacing a same-type layer, remove it now that the new layer is
189 // in the hierarchy.
190 if (old_ca_context_layer != ca_context_layer_)
191 DestroyCAContextLayer(old_ca_context_layer);
192
193 // Remove any different-type layers that this is replacing.
194 DestroyIOSurfaceLayer(io_surface_layer_);
195 DestroySoftwareLayer();
196 }
197
198 void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrame(
199 IOSurfaceID io_surface_id,
200 gfx::Size pixel_size,
201 float scale_factor) {
202 // In the layer is replaced, keep the old one around until after the new one
203 // is installed to avoid flashes.
204 base::scoped_nsobject<IOSurfaceLayer> old_io_surface_layer =
205 io_surface_layer_;
206
207 // Create or re-create an IOSurface layer if needed. If there already exists
208 // a layer but it has the wrong scale factor or it was poisoned, re-create the
209 // layer.
210 bool needs_new_layer =
211 !io_surface_layer_ ||
212 [io_surface_layer_ hasBeenPoisoned] ||
213 [io_surface_layer_ scaleFactor] != scale_factor;
214 if (needs_new_layer) {
215 io_surface_layer_.reset(
216 [[IOSurfaceLayer alloc] initWithClient:this
217 withScaleFactor:scale_factor]);
218 if (io_surface_layer_)
219 [flipped_layer_ addSublayer:io_surface_layer_];
220 else
221 LOG(ERROR) << "Failed to create IOSurfaceLayer";
222 }
223
224 // Open the provided IOSurface.
225 if (io_surface_layer_) {
226 bool result = [io_surface_layer_ gotFrameWithIOSurface:io_surface_id
227 withPixelSize:pixel_size
228 withScaleFactor:scale_factor];
229 if (!result) {
230 DestroyIOSurfaceLayer(io_surface_layer_);
231 LOG(ERROR) << "Failed open IOSurface in IOSurfaceLayer";
232 }
233 }
234
235 // Give a final complaint if anything with the layer's creation went wrong.
236 // This frame will appear blank, the compositor will try to create another,
237 // and maybe that will go better.
238 if (!io_surface_layer_) {
239 LOG(ERROR) << "IOSurfaceLayer is nil, tab will be blank";
240 IOSurfaceLayerHitError();
241 }
242
243 // Make the CALayer draw and set its size appropriately.
244 if (io_surface_layer_) {
245 [io_surface_layer_ gotNewFrame];
246
247 // Set the bounds of the accelerated layer to match the size of the frame.
248 // If the bounds changed, force the content to be displayed immediately.
249 CGRect new_layer_bounds = CGRectMake(
250 0, 0, last_swap_size_dip_.width(), last_swap_size_dip_.height());
251 bool bounds_changed = !CGRectEqualToRect(
252 new_layer_bounds, [io_surface_layer_ bounds]);
253 [io_surface_layer_ setBounds:new_layer_bounds];
254 if (bounds_changed)
255 [io_surface_layer_ setNeedsDisplayAndDisplayAndAck];
256 }
257
258 // If this replacing a same-type layer, remove it now that the new layer is
259 // in the hierarchy.
260 if (old_io_surface_layer != io_surface_layer_)
261 DestroyIOSurfaceLayer(old_io_surface_layer);
262
263 // Remove any different-type layers that this is replacing.
264 DestroyCAContextLayer(ca_context_layer_);
265 DestroySoftwareLayer();
266 }
267
268 void AcceleratedWidgetMac::GotSoftwareFrame(
269 cc::SoftwareFrameData* frame_data,
270 float scale_factor,
271 SkCanvas* canvas) {
272 if (!frame_data || !canvas || !view_)
273 return;
274
275 // Disable the fade-in or fade-out effect if we create or remove layers.
276 ScopedCAActionDisabler disabler;
277
278 // If there is not a layer for software frames, create one.
279 if (!software_layer_) {
280 software_layer_.reset([[SoftwareLayer alloc] init]);
281 [flipped_layer_ addSublayer:software_layer_];
282 }
283
284 // Set the software layer to draw the provided canvas.
285 SkImageInfo info;
286 size_t row_bytes;
287 const void* pixels = canvas->peekPixels(&info, &row_bytes);
288 gfx::Size pixel_size(info.fWidth, info.fHeight);
289 [software_layer_ setContentsToData:pixels
290 withRowBytes:row_bytes
291 withPixelSize:pixel_size
292 withScaleFactor:scale_factor];
293 last_swap_size_dip_ = ConvertSizeToDIP(scale_factor, pixel_size);
294
295 // Remove any different-type layers that this is replacing.
296 DestroyCAContextLayer(ca_context_layer_);
297 DestroyIOSurfaceLayer(io_surface_layer_);
298 }
299
300 void AcceleratedWidgetMac::DestroyCAContextLayer(
301 base::scoped_nsobject<CALayerHost> ca_context_layer) {
302 if (!ca_context_layer)
303 return;
304 [ca_context_layer removeFromSuperlayer];
305 if (ca_context_layer == ca_context_layer_)
306 ca_context_layer_.reset();
307 }
308
309 void AcceleratedWidgetMac::DestroyIOSurfaceLayer(
310 base::scoped_nsobject<IOSurfaceLayer> io_surface_layer) {
311 if (!io_surface_layer)
312 return;
313 [io_surface_layer resetClient];
314 [io_surface_layer removeFromSuperlayer];
315 if (io_surface_layer == io_surface_layer_)
316 io_surface_layer_.reset();
317 }
318
319 void AcceleratedWidgetMac::DestroySoftwareLayer() {
320 if (!software_layer_)
321 return;
322 [software_layer_ removeFromSuperlayer];
323 software_layer_.reset();
324 }
325
326 bool AcceleratedWidgetMac::IOSurfaceLayerShouldAckImmediately() const {
327 // If there is no view then the accelerated layer is not in the view
328 // hierarchy and will never draw.
329 if (!view_)
330 return true;
331 return view_->AcceleratedWidgetShouldIgnoreBackpressure();
332 }
333
334 void AcceleratedWidgetMac::IOSurfaceLayerDidDrawFrame() {
335 AcknowledgeAcceleratedFrame();
336 }
337
338 void AcceleratedWidgetMac::AcknowledgeAcceleratedFrame() {
339 if (accelerated_frame_drawn_callback_.is_null())
340 return;
341 accelerated_frame_drawn_callback_.Run();
342 accelerated_frame_drawn_callback_.Reset();
343 if (view_)
344 view_->AcceleratedWidgetSwapCompleted(accelerated_latency_info_);
345 accelerated_latency_info_.clear();
346 }
347
348 void AcceleratedWidgetMac::IOSurfaceLayerHitError() {
349 // Perform all acks that would have been done if the frame had succeeded, to
350 // un-block the compositor and renderer.
351 AcknowledgeAcceleratedFrame();
352
353 // Poison the context being used and request a mulligan.
354 [io_surface_layer_ poisonContextAndSharegroup];
355
356 if (view_)
357 view_->AcceleratedWidgetHitError();
358 }
359
360 void AcceleratedWidgetMacGotAcceleratedFrame(
361 gfx::AcceleratedWidget widget, uint64 surface_handle,
362 const std::vector<ui::LatencyInfo>& latency_info,
363 gfx::Size pixel_size, float scale_factor,
364 const base::Closure& drawn_callback,
365 bool* disable_throttling, int* renderer_id) {
366 AcceleratedWidgetMac* accelerated_widget_mac =
367 GetHelperFromAcceleratedWidget(widget);
368 if (accelerated_widget_mac) {
369 accelerated_widget_mac->GotAcceleratedFrame(
370 surface_handle, latency_info, pixel_size, scale_factor, drawn_callback);
371 *disable_throttling =
372 accelerated_widget_mac->IsRendererThrottlingDisabled();
373 *renderer_id = accelerated_widget_mac->GetRendererID();
374 } else {
375 *disable_throttling = false;
376 *renderer_id = 0;
377 }
378 }
379
380 void AcceleratedWidgetMacGotSoftwareFrame(
381 gfx::AcceleratedWidget widget,
382 cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas) {
383 AcceleratedWidgetMac* accelerated_widget_mac =
384 GetHelperFromAcceleratedWidget(widget);
385 if (accelerated_widget_mac)
386 accelerated_widget_mac->GotSoftwareFrame(frame_data, scale_factor, canvas);
387 }
388
389 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698