| 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 |