Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / content / browser / compositor / browser_compositor_ca_layer_tree_mac.mm
blobe173cd5e111d6310347d29e7895808a7e08c5944
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.
5 #include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
7 #include <map>
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/browser/renderer_host/dip_util.h"
16 #include "content/common/gpu/surface_handle_types_mac.h"
17 #include "content/public/browser/context_factory.h"
18 #include "ui/base/cocoa/animation_utils.h"
19 #include "ui/gl/scoped_cgl.h"
21 namespace content {
22 namespace {
24 typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*>
25     WidgetToHelperMap;
26 base::LazyInstance<WidgetToHelperMap> g_widget_to_helper_map;
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;
42 ////////////////////////////////////////////////////////////////////////////////
43 // AcceleratedWidgetMac
45 AcceleratedWidgetMac::AcceleratedWidgetMac()
46     : view_(NULL) {
47   // Disable the fade-in animation as the layers are added.
48   ScopedCAActionDisabler disabler;
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];
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));
69 AcceleratedWidgetMac::~AcceleratedWidgetMac() {
70   DCHECK(!view_);
71   g_widget_to_helper_map.Pointer()->erase(native_widget_);
74 void AcceleratedWidgetMac::SetNSView(AcceleratedWidgetMacNSView* view) {
75   // Disable the fade-in animation as the view is added.
76   ScopedCAActionDisabler disabler;
78   DCHECK(view && !view_);
79   view_ = view;
81   CALayer* background_layer = [view_->AcceleratedWidgetGetNSView() layer];
82   DCHECK(background_layer);
83   [flipped_layer_ setBounds:[background_layer bounds]];
84   [background_layer addSublayer:flipped_layer_];
87 void AcceleratedWidgetMac::ResetNSView() {
88   if (!view_)
89     return;
91   // Disable the fade-out animation as the view is removed.
92   ScopedCAActionDisabler disabler;
94   [flipped_layer_ removeFromSuperlayer];
95   DestroyIOSurfaceLayer(io_surface_layer_);
96   DestroyCAContextLayer(ca_context_layer_);
97   DestroySoftwareLayer();
99   last_swap_size_dip_ = gfx::Size();
100   view_ = NULL;
103 bool AcceleratedWidgetMac::HasFrameOfSize(
104     const gfx::Size& dip_size) const {
105   return last_swap_size_dip_ == dip_size;
108 int AcceleratedWidgetMac::GetRendererID() const {
109   if (io_surface_layer_)
110     return [io_surface_layer_ rendererID];
111   return 0;
114 bool AcceleratedWidgetMac::IsRendererThrottlingDisabled() const {
115   if (view_)
116     return view_->AcceleratedWidgetShouldIgnoreBackpressure();
117   return false;
120 void AcceleratedWidgetMac::BeginPumpingFrames() {
121   [io_surface_layer_ beginPumpingFrames];
124 void AcceleratedWidgetMac::EndPumpingFrames() {
125   [io_surface_layer_ endPumpingFrames];
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());
139   // If there is no view and therefore no superview to draw into, early-out.
140   if (!view_) {
141     AcknowledgeAcceleratedFrame();
142     return;
143   }
145   // Disable the fade-in or fade-out effect if we create or remove layers.
146   ScopedCAActionDisabler disabler;
148   last_swap_size_dip_ = 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   }
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_;
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   }
185   // Acknowledge the frame to unblock the compositor immediately (the GPU
186   // process will do any required throttling).
187   AcknowledgeAcceleratedFrame();
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);
194   // Remove any different-type layers that this is replacing.
195   DestroyIOSurfaceLayer(io_surface_layer_);
196   DestroySoftwareLayer();
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_;
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   }
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   }
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   }
244   // Make the CALayer draw and set its size appropriately.
245   if (io_surface_layer_) {
246     [io_surface_layer_ gotNewFrame];
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   }
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);
264   // Remove any different-type layers that this is replacing.
265   DestroyCAContextLayer(ca_context_layer_);
266   DestroySoftwareLayer();
269 void AcceleratedWidgetMac::GotSoftwareFrame(
270     cc::SoftwareFrameData* frame_data,
271     float scale_factor,
272     SkCanvas* canvas) {
273   if (!frame_data || !canvas || !view_)
274     return;
276   // Disable the fade-in or fade-out effect if we create or remove layers.
277   ScopedCAActionDisabler disabler;
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   }
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_ = ConvertSizeToDIP(scale_factor, pixel_size);
296   // Remove any different-type layers that this is replacing.
297   DestroyCAContextLayer(ca_context_layer_);
298   DestroyIOSurfaceLayer(io_surface_layer_);
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();
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();
320 void AcceleratedWidgetMac::DestroySoftwareLayer() {
321   if (!software_layer_)
322     return;
323   [software_layer_ removeFromSuperlayer];
324   software_layer_.reset();
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();
335 void AcceleratedWidgetMac::IOSurfaceLayerDidDrawFrame() {
336   AcknowledgeAcceleratedFrame();
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();
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();
354   // Poison the context being used and request a mulligan.
355   [io_surface_layer_ poisonContextAndSharegroup];
357   if (view_)
358     view_->AcceleratedWidgetHitError();
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   }
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);
390 }  // namespace content