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_view_mac.h"
7 #include "base/debug/trace_event.h"
8 #include "base/mac/scoped_cftyperef.h"
9 #include "content/browser/compositor/gpu_process_transport_factory.h"
10 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
11 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
12 #include "content/browser/renderer_host/software_layer_mac.h"
13 #include "content/public/browser/context_factory.h"
14 #include "ui/base/cocoa/animation_utils.h"
15 #include "ui/gl/scoped_cgl.h"
17 @interface BrowserCompositorViewMac (Private)
18 - (void)layerDidDrawFrame;
19 - (void)gotAcceleratedLayerError;
20 @end // BrowserCompositorViewMac (Private)
24 // The CompositingIOSurfaceLayerClient interface needs to be implemented as a
25 // C++ class to operate on, rather than Objective C class. This helper class
26 // provides a bridge between the two.
27 class BrowserCompositorViewMacHelper : public CompositingIOSurfaceLayerClient {
29 BrowserCompositorViewMacHelper(BrowserCompositorViewMac* view)
31 virtual ~BrowserCompositorViewMacHelper() {}
34 // CompositingIOSurfaceLayerClient implementation:
35 virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE {
36 [view_ layerDidDrawFrame];
38 [view_ gotAcceleratedLayerError];
41 BrowserCompositorViewMac* view_;
44 } // namespace content
47 // The default implementation of additions to the NSView interface for browser
48 // compositing should never be called. Log an error if they are.
49 @implementation NSView (BrowserCompositorView)
51 - (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
52 withOutputSurfaceID:(int)surface_id
53 withPixelSize:(gfx::Size)pixel_size
54 withScaleFactor:(float)scale_factor {
55 DLOG(ERROR) << "-[NSView gotAcceleratedIOSurfaceFrame] called on "
56 << "non-overriden class.";
59 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
60 withScaleFactor:(float)scale_factor
61 withCanvas:(SkCanvas*)canvas {
62 DLOG(ERROR) << "-[NSView gotSoftwareFrame] called on non-overridden class.";
65 @end // NSView (BrowserCompositorView)
67 @implementation BrowserCompositorViewMac : NSView
69 - (id)initWithSuperview:(NSView*)view {
70 if (self = [super init]) {
71 accelerated_layer_output_surface_id_ = 0;
72 helper_.reset(new content::BrowserCompositorViewMacHelper(self));
74 // Disable the fade-in animation as the layer and view are added.
75 ScopedCAActionDisabler disabler;
77 // Make this view host a transparent layer.
78 background_layer_.reset([[CALayer alloc] init]);
79 [background_layer_ setContentsGravity:kCAGravityTopLeft];
80 [self setLayer:background_layer_];
81 [self setWantsLayer:YES];
83 compositor_.reset(new ui::Compositor(self, content::GetContextFactory()));
84 [view addSubview:self];
89 - (void)gotAcceleratedLayerError {
90 if (!accelerated_layer_)
93 [accelerated_layer_ context]->PoisonContextAndSharegroup();
94 compositor_->ScheduleFullRedraw();
97 // This function closely mirrors RenderWidgetHostViewMac::LayoutLayers. When
98 // only delegated rendering is supported, only one copy of this code will
100 - (void)layoutLayers {
101 // Disable animation of the layers' resizing or repositioning.
102 ScopedCAActionDisabler disabler;
104 NSSize superview_frame_size = [[self superview] frame].size;
105 [self setFrame:NSMakeRect(
106 0, 0, superview_frame_size.width, superview_frame_size.height)];
108 CGRect new_background_frame = CGRectMake(
111 superview_frame_size.width,
112 superview_frame_size.height);
113 [background_layer_ setFrame:new_background_frame];
115 // The bounds of the accelerated layer determine the size of the GL surface
116 // that will be drawn to. Make sure that this is big enough to draw the
118 if (accelerated_layer_) {
119 CGRect layer_bounds = CGRectMake(
122 [accelerated_layer_ iosurface]->dip_io_surface_size().width(),
123 [accelerated_layer_ iosurface]->dip_io_surface_size().height());
124 CGPoint layer_position = CGPointMake(
126 CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
127 bool bounds_changed = !CGRectEqualToRect(
128 layer_bounds, [accelerated_layer_ bounds]);
129 [accelerated_layer_ setBounds:layer_bounds];
130 [accelerated_layer_ setPosition:layer_position];
131 if (bounds_changed) {
132 [accelerated_layer_ setNeedsDisplay];
133 [accelerated_layer_ displayIfNeeded];
137 // The content area of the software layer is the size of the image provided.
138 // Make the bounds of the layer match the superview's bounds, to ensure that
139 // the visible contents are drawn.
140 [software_layer_ setBounds:new_background_frame];
143 - (void)resetClient {
144 [accelerated_layer_ resetClient];
147 - (ui::Compositor*)compositor {
148 return compositor_.get();
151 - (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
152 withOutputSurfaceID:(int)surface_id
153 withPixelSize:(gfx::Size)pixel_size
154 withScaleFactor:(float)scale_factor {
155 DCHECK(!accelerated_layer_output_surface_id_);
156 accelerated_layer_output_surface_id_ = surface_id;
158 ScopedCAActionDisabler disabler;
160 // If there is already an accelerated layer, but it has the wrong scale
161 // factor or it was poisoned, remove the old layer and replace it.
162 base::scoped_nsobject<CompositingIOSurfaceLayer> old_accelerated_layer;
163 if (accelerated_layer_ && (
164 [accelerated_layer_ context]->HasBeenPoisoned() ||
165 [accelerated_layer_ iosurface]->scale_factor() != scale_factor)) {
166 old_accelerated_layer = accelerated_layer_;
167 accelerated_layer_.reset();
170 // If there is not a layer for accelerated frames, create one.
171 if (!accelerated_layer_) {
172 // Disable the fade-in animation as the layer is added.
173 ScopedCAActionDisabler disabler;
174 scoped_refptr<content::CompositingIOSurfaceMac> iosurface =
175 content::CompositingIOSurfaceMac::Create();
176 accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc]
177 initWithIOSurface:iosurface
178 withScaleFactor:scale_factor
179 withClient:helper_.get()]);
180 [[self layer] addSublayer:accelerated_layer_];
185 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
186 [accelerated_layer_ context]->cgl_context());
187 result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent(
188 [accelerated_layer_ context], surface_handle, pixel_size, scale_factor);
190 LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
192 [accelerated_layer_ gotNewFrame];
195 // If there was a software layer or an old accelerated layer, remove it.
196 // Disable the fade-out animation as the layer is removed.
198 ScopedCAActionDisabler disabler;
199 [software_layer_ removeFromSuperlayer];
200 software_layer_.reset();
201 [old_accelerated_layer resetClient];
202 [old_accelerated_layer removeFromSuperlayer];
203 old_accelerated_layer.reset();
207 - (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
208 withScaleFactor:(float)scale_factor
209 withCanvas:(SkCanvas*)canvas {
210 if (!frame_data || !canvas)
213 // If there is not a layer for software frames, create one.
214 if (!software_layer_) {
215 // Disable the fade-in animation as the layer is added.
216 ScopedCAActionDisabler disabler;
217 software_layer_.reset([[SoftwareLayer alloc] init]);
218 [[self layer] addSublayer:software_layer_];
223 const void* pixels = canvas->peekPixels(&info, &row_bytes);
224 [software_layer_ setContentsToData:pixels
225 withRowBytes:row_bytes
226 withPixelSize:gfx::Size(info.fWidth, info.fHeight)
227 withScaleFactor:scale_factor];
230 // If there was an accelerated layer, remove it.
231 // Disable the fade-out animation as the layer is removed.
233 ScopedCAActionDisabler disabler;
234 [accelerated_layer_ resetClient];
235 [accelerated_layer_ removeFromSuperlayer];
236 accelerated_layer_.reset();
239 // This call can be nested insider ui::Compositor commit calls, and can also
240 // make additional ui::Compositor commit calls. Avoid the potential recursion
241 // by acknowledging the frame asynchronously.
242 [self performSelector:@selector(layerDidDrawFrame)
247 - (void)layerDidDrawFrame {
248 if (!accelerated_layer_output_surface_id_)
251 content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
252 accelerated_layer_output_surface_id_);
253 accelerated_layer_output_surface_id_ = 0;
256 @end // BrowserCompositorViewMac