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