browser_compositor_view_private_mac.mm revision 116680a4aac90f2aa7413d9095a592090648e557
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_view_private_mac.h" 6 7#include "base/debug/trace_event.h" 8#include "content/browser/compositor/gpu_process_transport_factory.h" 9#include "content/browser/renderer_host/compositing_iosurface_context_mac.h" 10#include "content/browser/renderer_host/compositing_iosurface_mac.h" 11#include "content/browser/renderer_host/software_layer_mac.h" 12#include "content/public/browser/context_factory.h" 13#include "ui/base/cocoa/animation_utils.h" 14#include "ui/gl/scoped_cgl.h" 15 16//////////////////////////////////////////////////////////////////////////////// 17// BrowserCompositorViewMacInternal 18 19namespace content { 20 21BrowserCompositorViewMacInternal::BrowserCompositorViewMacInternal() 22 : client_(NULL), 23 accelerated_layer_output_surface_id_(0) { 24 // Disable the fade-in animation as the layers are added. 25 ScopedCAActionDisabler disabler; 26 27 // Add a flipped transparent layer as a child, so that we don't need to 28 // fiddle with the position of sub-layers -- they will always be at the 29 // origin. 30 flipped_layer_.reset([[CALayer alloc] init]); 31 [flipped_layer_ setGeometryFlipped:YES]; 32 [flipped_layer_ setAnchorPoint:CGPointMake(0, 0)]; 33 [flipped_layer_ 34 setAutoresizingMask:kCALayerWidthSizable|kCALayerHeightSizable]; 35 36 // Set the Cocoa view to be hosting the un-flipped background layer (hosting 37 // a flipped layer results in unpredictable behavior). 38 cocoa_view_.reset([[BrowserCompositorViewCocoa alloc] initWithClient:this]); 39 40 // Create a compositor to draw the contents of |cocoa_view_|. 41 compositor_.reset(new ui::Compositor( 42 cocoa_view_, content::GetContextFactory())); 43} 44 45BrowserCompositorViewMacInternal::~BrowserCompositorViewMacInternal() { 46 DCHECK(!client_); 47 [cocoa_view_ resetClient]; 48} 49 50void BrowserCompositorViewMacInternal::SetClient( 51 BrowserCompositorViewMacClient* client) { 52 // Disable the fade-in animation as the view is added. 53 ScopedCAActionDisabler disabler; 54 55 DCHECK(client && !client_); 56 client_ = client; 57 compositor_->SetRootLayer(client_->BrowserCompositorRootLayer()); 58 59 CALayer* background_layer = [client_->BrowserCompositorSuperview() layer]; 60 DCHECK(background_layer); 61 [flipped_layer_ setBounds:[background_layer bounds]]; 62 [background_layer addSublayer:flipped_layer_]; 63} 64 65void BrowserCompositorViewMacInternal::ResetClient() { 66 if (!client_) 67 return; 68 69 // Disable the fade-out animation as the view is removed. 70 ScopedCAActionDisabler disabler; 71 72 [flipped_layer_ removeFromSuperlayer]; 73 74 [accelerated_layer_ removeFromSuperlayer]; 75 [accelerated_layer_ resetClient]; 76 accelerated_layer_.reset(); 77 accelerated_layer_output_surface_id_ = 0; 78 79 [software_layer_ removeFromSuperlayer]; 80 software_layer_.reset(); 81 82 compositor_->SetScaleAndSize(1.0, gfx::Size(0, 0)); 83 compositor_->SetRootLayer(NULL); 84 client_ = NULL; 85} 86 87void BrowserCompositorViewMacInternal::GotAcceleratedIOSurfaceFrame( 88 IOSurfaceID io_surface_id, 89 int output_surface_id, 90 const std::vector<ui::LatencyInfo>& latency_info, 91 gfx::Size pixel_size, 92 float scale_factor) { 93 DCHECK(!accelerated_layer_output_surface_id_); 94 accelerated_layer_output_surface_id_ = output_surface_id; 95 accelerated_latency_info_.insert(accelerated_latency_info_.end(), 96 latency_info.begin(), latency_info.end()); 97 98 // If there is no client and therefore no superview to draw into, early-out. 99 if (!client_) { 100 AcceleratedLayerDidDrawFrame(true); 101 return; 102 } 103 104 // Disable the fade-in or fade-out effect if we create or remove layers. 105 ScopedCAActionDisabler disabler; 106 107 // If there is already an accelerated layer, but it has the wrong scale 108 // factor or it was poisoned, remove the old layer and replace it. 109 base::scoped_nsobject<CompositingIOSurfaceLayer> old_accelerated_layer; 110 if (accelerated_layer_ && ( 111 [accelerated_layer_ context]->HasBeenPoisoned() || 112 [accelerated_layer_ iosurface]->scale_factor() != scale_factor)) { 113 old_accelerated_layer = accelerated_layer_; 114 accelerated_layer_.reset(); 115 } 116 117 // If there is not a layer for accelerated frames, create one. 118 if (!accelerated_layer_) { 119 scoped_refptr<content::CompositingIOSurfaceMac> iosurface = 120 content::CompositingIOSurfaceMac::Create(); 121 accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc] 122 initWithIOSurface:iosurface 123 withScaleFactor:scale_factor 124 withClient:this]); 125 [flipped_layer_ addSublayer:accelerated_layer_]; 126 } 127 128 // Open the provided IOSurface. 129 { 130 bool result = true; 131 gfx::ScopedCGLSetCurrentContext scoped_set_current_context( 132 [accelerated_layer_ context]->cgl_context()); 133 result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent( 134 [accelerated_layer_ context], io_surface_id, pixel_size, scale_factor); 135 if (!result) 136 LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac"; 137 } 138 [accelerated_layer_ gotNewFrame]; 139 140 // Set the bounds of the accelerated layer to match the size of the frame. 141 // If the bounds changed, force the content to be displayed immediately. 142 CGRect new_layer_bounds = CGRectMake( 143 0, 144 0, 145 [accelerated_layer_ iosurface]->dip_io_surface_size().width(), 146 [accelerated_layer_ iosurface]->dip_io_surface_size().height()); 147 bool bounds_changed = !CGRectEqualToRect( 148 new_layer_bounds, [accelerated_layer_ bounds]); 149 [accelerated_layer_ setBounds:new_layer_bounds]; 150 if (bounds_changed) { 151 [accelerated_layer_ setNeedsDisplay]; 152 [accelerated_layer_ displayIfNeeded]; 153 } 154 155 // If there was a software layer or an old accelerated layer, remove it. 156 // Disable the fade-out animation as the layer is removed. 157 { 158 [software_layer_ removeFromSuperlayer]; 159 software_layer_.reset(); 160 [old_accelerated_layer resetClient]; 161 [old_accelerated_layer removeFromSuperlayer]; 162 old_accelerated_layer.reset(); 163 } 164} 165 166void BrowserCompositorViewMacInternal::GotSoftwareFrame( 167 cc::SoftwareFrameData* frame_data, 168 float scale_factor, 169 SkCanvas* canvas) { 170 if (!frame_data || !canvas || !client_) 171 return; 172 173 // Disable the fade-in or fade-out effect if we create or remove layers. 174 ScopedCAActionDisabler disabler; 175 176 // If there is not a layer for software frames, create one. 177 if (!software_layer_) { 178 software_layer_.reset([[SoftwareLayer alloc] init]); 179 [flipped_layer_ addSublayer:software_layer_]; 180 } 181 182 // Set the software layer to draw the provided canvas. 183 SkImageInfo info; 184 size_t row_bytes; 185 const void* pixels = canvas->peekPixels(&info, &row_bytes); 186 [software_layer_ setContentsToData:pixels 187 withRowBytes:row_bytes 188 withPixelSize:gfx::Size(info.fWidth, info.fHeight) 189 withScaleFactor:scale_factor]; 190 191 // If there was an accelerated layer, remove it. 192 { 193 [accelerated_layer_ resetClient]; 194 [accelerated_layer_ removeFromSuperlayer]; 195 accelerated_layer_.reset(); 196 } 197} 198 199void BrowserCompositorViewMacInternal::AcceleratedLayerDidDrawFrame( 200 bool succeeded) { 201 if (accelerated_layer_output_surface_id_) { 202 content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed( 203 accelerated_layer_output_surface_id_); 204 accelerated_layer_output_surface_id_ = 0; 205 } 206 207 if (client_) 208 client_->BrowserCompositorViewFrameSwapped(accelerated_latency_info_); 209 210 accelerated_latency_info_.clear(); 211 212 if (!succeeded) { 213 if (accelerated_layer_) 214 [accelerated_layer_ context]->PoisonContextAndSharegroup(); 215 compositor_->ScheduleFullRedraw(); 216 } 217} 218 219} // namespace content 220 221//////////////////////////////////////////////////////////////////////////////// 222// BrowserCompositorViewCocoa 223 224@implementation BrowserCompositorViewCocoa 225 226- (id)initWithClient:(content::BrowserCompositorViewCocoaClient*)client { 227 if (self = [super init]) { 228 client_ = client; 229 } 230 return self; 231} 232 233- (void)dealloc { 234 DCHECK(!client_); 235 [super dealloc]; 236} 237 238- (void)resetClient { 239 client_ = NULL; 240} 241 242- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle 243 withOutputSurfaceID:(int)surface_id 244 withLatencyInfo:(std::vector<ui::LatencyInfo>)latency_info 245 withPixelSize:(gfx::Size)pixel_size 246 withScaleFactor:(float)scale_factor { 247 if (!client_) 248 return; 249 client_->GotAcceleratedIOSurfaceFrame( 250 surface_handle, surface_id, latency_info, pixel_size, scale_factor); 251} 252 253- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data 254 withScaleFactor:(float)scale_factor 255 withCanvas:(SkCanvas*)canvas { 256 if (!client_) 257 return; 258 client_->GotSoftwareFrame(frame_data, scale_factor, canvas); 259} 260 261@end // BrowserCompositorViewCocoa 262 263