OLD | NEW |
| (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 | |
OLD | NEW |