Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/common/gpu/ca_layer_tree_mac.h" | 5 #include "content/common/gpu/ca_layer_tree_mac.h" |
| 6 | 6 |
| 7 #include <AVFoundation/AVFoundation.h> | |
| 8 #include <CoreVideo/CoreVideo.h> | |
| 9 | |
| 7 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 8 #include "base/mac/sdk_forward_declarations.h" | 11 #include "base/mac/sdk_forward_declarations.h" |
| 9 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 10 #include "gpu/GLES2/gl2extchromium.h" | 13 #include "gpu/GLES2/gl2extchromium.h" |
| 11 #include "third_party/skia/include/core/SkColor.h" | 14 #include "third_party/skia/include/core/SkColor.h" |
| 12 #include "ui/base/cocoa/animation_utils.h" | 15 #include "ui/base/cocoa/animation_utils.h" |
| 13 #include "ui/base/ui_base_switches.h" | 16 #include "ui/base/ui_base_switches.h" |
| 14 #include "ui/gfx/geometry/dip_util.h" | 17 #include "ui/gfx/geometry/dip_util.h" |
| 15 | 18 |
|
ccameron
2016/03/23 08:57:10
I tried putting this into sdk_forward_declarations
| |
| 19 #if !defined(MAC_OS_X_VERSION_10_8) || \ | |
| 20 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 | |
|
erikchen
2016/03/23 17:44:59
I assume this will no longer be required after we
ccameron
2016/03/23 18:26:21
Exactly.
| |
| 21 BASE_EXPORT extern NSString* const AVLayerVideoGravityResize; | |
|
erikchen
2016/03/23 17:45:00
BASE_EXPORT?
ccameron
2016/03/23 18:26:21
Mmh, should have removed that when I removed these
| |
| 22 BASE_EXPORT extern "C" void NSAccessibilityPostNotificationWithUserInfo( | |
| 23 id object, | |
| 24 NSString* notification, | |
| 25 NSDictionary* user_info); | |
| 26 BASE_EXPORT extern "C" OSStatus CMSampleBufferCreateForImageBuffer( | |
| 27 CFAllocatorRef, | |
| 28 CVImageBufferRef, | |
| 29 Boolean dataReady, | |
| 30 CMSampleBufferMakeDataReadyCallback, | |
| 31 void*, | |
| 32 CMVideoFormatDescriptionRef, | |
| 33 const CMSampleTimingInfo*, | |
| 34 CMSampleBufferRef*); | |
| 35 BASE_EXPORT extern "C" CFArrayRef CMSampleBufferGetSampleAttachmentsArray( | |
| 36 CMSampleBufferRef, | |
| 37 Boolean); | |
| 38 BASE_EXPORT extern "C" OSStatus CMVideoFormatDescriptionCreateForImageBuffer( | |
| 39 CFAllocatorRef, | |
| 40 CVImageBufferRef, | |
| 41 CMVideoFormatDescriptionRef*); | |
| 42 BASE_EXPORT extern "C" CMTime CMTimeMake(int64_t, int32_t); | |
| 43 BASE_EXPORT extern CFStringRef const kCMSampleAttachmentKey_DisplayImmediately; | |
| 44 BASE_EXPORT extern const CMTime kCMTimeInvalid; | |
| 45 #endif // MAC_OS_X_VERSION_10_8 | |
| 46 | |
| 16 namespace content { | 47 namespace content { |
| 17 | 48 |
| 49 namespace { | |
| 50 | |
| 51 bool AVSampleBufferDisplayLayerEnqueueIOSurface( | |
|
erikchen
2016/03/23 17:45:00
Can you add a comment on the ownership semantics o
ccameron
2016/03/23 18:26:21
Added a comment. I just said that the io_surface i
| |
| 52 AVSampleBufferDisplayLayer* av_layer, | |
| 53 IOSurfaceRef io_surface) { | |
| 54 OSStatus os_status = noErr; | |
| 55 CVReturn cv_return = kCVReturnSuccess; | |
| 56 | |
| 57 base::ScopedCFTypeRef<CFDictionaryRef> pixel_buffer_attributes; | |
| 58 base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer; | |
| 59 cv_return = CVPixelBufferCreateWithIOSurface( | |
| 60 kCFAllocatorDefault, io_surface, pixel_buffer_attributes.get(), | |
|
erikchen
2016/03/23 17:44:59
Isn't pixel_buffer_attributes.get() always nullptr
erikchen
2016/03/23 17:45:00
shouldn't we pass null to use the defualt allocato
ccameron
2016/03/23 18:26:20
I spent so long trying to put random things in tha
ccameron
2016/03/23 18:26:21
Changed to nullptr.
| |
| 61 cv_pixel_buffer.InitializeInto()); | |
| 62 if (cv_return) { | |
|
erikchen
2016/03/23 17:45:00
I think you want cv_return != kCVReturnSuccess
ccameron
2016/03/23 18:26:20
Done (kCVReturnSuccess == 0).
| |
| 63 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; | |
| 64 return false; | |
| 65 } | |
| 66 | |
| 67 base::ScopedCFTypeRef<CMVideoFormatDescriptionRef> video_info; | |
| 68 os_status = CMVideoFormatDescriptionCreateForImageBuffer( | |
| 69 NULL, cv_pixel_buffer, video_info.InitializeInto()); | |
| 70 if (os_status) { | |
|
erikchen
2016/03/23 17:45:00
use proper conditional here and later in function.
ccameron
2016/03/23 18:26:21
Done.
| |
| 71 LOG(ERROR) << "CMVideoFormatDescriptionCreateForImageBuffer failed with " | |
| 72 << os_status; | |
| 73 return false; | |
| 74 } | |
| 75 | |
| 76 CMTime frame_time = CMTimeMake(0, 30); | |
|
erikchen
2016/03/23 17:44:59
Where did this number 30 come from?
ccameron
2016/03/23 18:26:21
Added a comment saying that frame time doesn't mat
| |
| 77 CMSampleTimingInfo timing_info = {frame_time, frame_time, kCMTimeInvalid}; | |
| 78 | |
| 79 base::ScopedCFTypeRef<CMSampleBufferRef> sample_buffer = NULL; | |
|
erikchen
2016/03/23 17:45:00
s/NULL/nullptr
ccameron
2016/03/23 18:26:21
Done.
| |
| 80 os_status = CMSampleBufferCreateForImageBuffer( | |
| 81 kCFAllocatorDefault, cv_pixel_buffer, YES, NULL, NULL, video_info, | |
| 82 &timing_info, sample_buffer.InitializeInto()); | |
| 83 if (os_status) { | |
| 84 LOG(ERROR) << "CMSampleBufferCreateForImageBuffer failed with " | |
| 85 << os_status; | |
| 86 return false; | |
| 87 } | |
| 88 | |
| 89 CFArrayRef attachments = | |
| 90 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, YES); | |
| 91 if (!attachments) { | |
| 92 LOG(ERROR) << "CMSampleBufferGetSampleAttachmentsArray failed"; | |
| 93 return false; | |
| 94 } | |
| 95 CFMutableDictionaryRef attachments_dictionary = | |
|
erikchen
2016/03/23 17:45:00
Check that array has size >=1 first
ccameron
2016/03/23 18:26:20
Done.
| |
| 96 reinterpret_cast<CFMutableDictionaryRef>( | |
| 97 const_cast<void*>(CFArrayGetValueAtIndex(attachments, 0))); | |
| 98 if (!attachments_dictionary) { | |
| 99 LOG(ERROR) << "Failed to get attachments dictionary"; | |
| 100 return false; | |
| 101 } | |
| 102 CFDictionarySetValue(attachments_dictionary, | |
| 103 kCMSampleAttachmentKey_DisplayImmediately, | |
| 104 kCFBooleanTrue); | |
| 105 | |
| 106 [av_layer enqueueSampleBuffer:sample_buffer]; | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 } // namespace | |
| 111 | |
| 18 CALayerTree::CALayerTree() {} | 112 CALayerTree::CALayerTree() {} |
| 19 CALayerTree::~CALayerTree() {} | 113 CALayerTree::~CALayerTree() {} |
| 20 | 114 |
| 21 bool CALayerTree::ScheduleCALayer( | 115 bool CALayerTree::ScheduleCALayer( |
| 22 bool is_clipped, | 116 bool is_clipped, |
| 23 const gfx::Rect& clip_rect, | 117 const gfx::Rect& clip_rect, |
| 24 unsigned sorting_context_id, | 118 unsigned sorting_context_id, |
| 25 const gfx::Transform& transform, | 119 const gfx::Transform& transform, |
| 26 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | 120 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, |
| 27 const gfx::RectF& contents_rect, | 121 const gfx::RectF& contents_rect, |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) | 241 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
| 148 ca_edge_aa_mask |= kCALayerBottomEdge; | 242 ca_edge_aa_mask |= kCALayerBottomEdge; |
| 149 } | 243 } |
| 150 | 244 |
| 151 // Ensure that the IOSurface be in use as soon as it is added to a | 245 // Ensure that the IOSurface be in use as soon as it is added to a |
| 152 // ContentLayer, so that, by the time that the call to SwapBuffers completes, | 246 // ContentLayer, so that, by the time that the call to SwapBuffers completes, |
| 153 // all IOSurfaces that can be used as CALayer contents in the future will be | 247 // all IOSurfaces that can be used as CALayer contents in the future will be |
| 154 // marked as InUse. | 248 // marked as InUse. |
| 155 if (io_surface) | 249 if (io_surface) |
| 156 IOSurfaceIncrementUseCount(io_surface); | 250 IOSurfaceIncrementUseCount(io_surface); |
| 251 | |
| 252 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to | |
| 253 // AV layers. | |
| 254 if (IOSurfaceGetPixelFormat(io_surface) == | |
| 255 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && | |
| 256 contents_rect == gfx::RectF(0, 0, 1, 1)) { | |
| 257 use_av_layer = true; | |
| 258 } | |
| 157 } | 259 } |
| 158 | 260 |
| 159 CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) | 261 CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) |
| 160 : io_surface(layer.io_surface), | 262 : io_surface(layer.io_surface), |
| 161 contents_rect(layer.contents_rect), | 263 contents_rect(layer.contents_rect), |
| 162 rect(layer.rect), | 264 rect(layer.rect), |
| 163 background_color(layer.background_color), | 265 background_color(layer.background_color), |
| 164 ca_edge_aa_mask(layer.ca_edge_aa_mask), | 266 ca_edge_aa_mask(layer.ca_edge_aa_mask), |
| 165 opacity(layer.opacity), | 267 opacity(layer.opacity), |
| 166 ca_layer(layer.ca_layer) { | 268 ca_layer(layer.ca_layer), |
| 269 av_layer(layer.av_layer), | |
| 270 use_av_layer(layer.use_av_layer) { | |
| 167 DCHECK(!layer.ca_layer); | 271 DCHECK(!layer.ca_layer); |
| 168 layer.ca_layer.reset(); | 272 layer.ca_layer.reset(); |
| 273 layer.av_layer.reset(); | |
| 169 // See remarks in the non-move constructor. | 274 // See remarks in the non-move constructor. |
| 170 if (io_surface) | 275 if (io_surface) |
| 171 IOSurfaceIncrementUseCount(io_surface); | 276 IOSurfaceIncrementUseCount(io_surface); |
| 172 } | 277 } |
| 173 | 278 |
| 174 CALayerTree::ContentLayer::~ContentLayer() { | 279 CALayerTree::ContentLayer::~ContentLayer() { |
| 175 [ca_layer removeFromSuperlayer]; | 280 [ca_layer removeFromSuperlayer]; |
| 176 // By the time the destructor is called, the IOSurface will have been passed | 281 // By the time the destructor is called, the IOSurface will have been passed |
| 177 // to the WindowServer, and will remain InUse by the WindowServer as long as | 282 // to the WindowServer, and will remain InUse by the WindowServer as long as |
| 178 // is needed to avoid recycling bugs. | 283 // is needed to avoid recycling bugs. |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 | 486 |
| 382 void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer, | 487 void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer, |
| 383 ContentLayer* old_layer, | 488 ContentLayer* old_layer, |
| 384 float scale_factor) { | 489 float scale_factor) { |
| 385 bool update_contents = true; | 490 bool update_contents = true; |
| 386 bool update_contents_rect = true; | 491 bool update_contents_rect = true; |
| 387 bool update_rect = true; | 492 bool update_rect = true; |
| 388 bool update_background_color = true; | 493 bool update_background_color = true; |
| 389 bool update_ca_edge_aa_mask = true; | 494 bool update_ca_edge_aa_mask = true; |
| 390 bool update_opacity = true; | 495 bool update_opacity = true; |
| 391 if (old_layer) { | 496 if (old_layer && old_layer->use_av_layer == use_av_layer) { |
| 392 DCHECK(old_layer->ca_layer); | 497 DCHECK(old_layer->ca_layer); |
| 393 std::swap(ca_layer, old_layer->ca_layer); | 498 std::swap(ca_layer, old_layer->ca_layer); |
| 499 std::swap(av_layer, old_layer->av_layer); | |
| 394 update_contents = old_layer->io_surface != io_surface; | 500 update_contents = old_layer->io_surface != io_surface; |
| 395 update_contents_rect = old_layer->contents_rect != contents_rect; | 501 update_contents_rect = old_layer->contents_rect != contents_rect; |
| 396 update_rect = old_layer->rect != rect; | 502 update_rect = old_layer->rect != rect; |
| 397 update_background_color = old_layer->background_color != background_color; | 503 update_background_color = old_layer->background_color != background_color; |
| 398 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; | 504 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; |
| 399 update_opacity = old_layer->opacity != opacity; | 505 update_opacity = old_layer->opacity != opacity; |
| 400 } else { | 506 } else { |
| 401 ca_layer.reset([[CALayer alloc] init]); | 507 if (use_av_layer) { |
| 508 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); | |
| 509 ca_layer.reset([av_layer retain]); | |
| 510 [av_layer setVideoGravity:AVLayerVideoGravityResize]; | |
| 511 } else { | |
| 512 ca_layer.reset([[CALayer alloc] init]); | |
|
erikchen
2016/03/23 17:44:59
Shouldn't we reset av_layer as well [to release a
ccameron
2016/03/23 18:26:20
We construct a new CALayerTree every frame (yeah,
| |
| 513 } | |
| 402 [ca_layer setAnchorPoint:CGPointZero]; | 514 [ca_layer setAnchorPoint:CGPointZero]; |
| 403 [superlayer addSublayer:ca_layer]; | 515 [superlayer addSublayer:ca_layer]; |
| 404 } | 516 } |
| 405 DCHECK_EQ([ca_layer superlayer], superlayer); | 517 DCHECK_EQ([ca_layer superlayer], superlayer); |
| 406 bool update_anything = update_contents || update_contents_rect || | 518 bool update_anything = update_contents || update_contents_rect || |
| 407 update_rect || update_background_color || | 519 update_rect || update_background_color || |
| 408 update_ca_edge_aa_mask || update_opacity; | 520 update_ca_edge_aa_mask || update_opacity; |
| 409 | 521 if (use_av_layer) { |
| 410 if (update_contents) { | 522 if (update_contents) |
| 411 [ca_layer setContents:static_cast<id>(io_surface.get())]; | 523 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); |
| 412 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | 524 } else { |
| 413 [ca_layer setContentsScale:scale_factor]; | 525 if (update_contents) { |
| 526 [ca_layer setContents:static_cast<id>(io_surface.get())]; | |
| 527 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | |
| 528 [ca_layer setContentsScale:scale_factor]; | |
| 529 } | |
| 530 if (update_contents_rect) | |
|
erikchen
2016/03/23 17:45:00
What if we're using a new av layer and need to upd
ccameron
2016/03/23 18:26:20
We only use_av_layer when the content rect is (0,0
| |
| 531 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | |
| 414 } | 532 } |
| 415 if (update_contents_rect) | |
| 416 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | |
| 417 if (update_rect) { | 533 if (update_rect) { |
| 418 gfx::RectF dip_rect = gfx::RectF(rect); | 534 gfx::RectF dip_rect = gfx::RectF(rect); |
| 419 dip_rect.Scale(1 / scale_factor); | 535 dip_rect.Scale(1 / scale_factor); |
| 420 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; | 536 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; |
| 421 [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())]; | 537 [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())]; |
| 422 } | 538 } |
| 423 if (update_background_color) { | 539 if (update_background_color) { |
| 424 CGFloat rgba_color_components[4] = { | 540 CGFloat rgba_color_components[4] = { |
| 425 SkColorGetR(background_color) / 255., | 541 SkColorGetR(background_color) / 255., |
| 426 SkColorGetG(background_color) / 255., | 542 SkColorGetG(background_color) / 255., |
| 427 SkColorGetB(background_color) / 255., | 543 SkColorGetB(background_color) / 255., |
| 428 SkColorGetA(background_color) / 255., | 544 SkColorGetA(background_color) / 255., |
| 429 }; | 545 }; |
| 430 base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate( | 546 base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate( |
| 431 CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components)); | 547 CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components)); |
| 432 [ca_layer setBackgroundColor:srgb_background_color]; | 548 [ca_layer setBackgroundColor:srgb_background_color]; |
| 433 } | 549 } |
| 434 if (update_ca_edge_aa_mask) | 550 if (update_ca_edge_aa_mask) |
| 435 [ca_layer setEdgeAntialiasingMask:ca_edge_aa_mask]; | 551 [ca_layer setEdgeAntialiasingMask:ca_edge_aa_mask]; |
| 436 if (update_opacity) | 552 if (update_opacity) |
| 437 [ca_layer setOpacity:opacity]; | 553 [ca_layer setOpacity:opacity]; |
| 438 | 554 |
| 439 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( | 555 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 440 switches::kShowMacOverlayBorders); | 556 switches::kShowMacOverlayBorders); |
| 441 if (show_borders) { | 557 if (show_borders) { |
| 442 base::ScopedCFTypeRef<CGColorRef> color; | 558 base::ScopedCFTypeRef<CGColorRef> color; |
| 443 if (update_anything) { | 559 if (update_anything) { |
| 444 // Pink represents a CALayer that changed this frame. | 560 if (use_av_layer) { |
| 445 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); | 561 // Green represents an AV layer that changed this frame. |
| 562 color.reset(CGColorCreateGenericRGB(0, 1, 0, 1)); | |
| 563 } else { | |
| 564 // Pink represents a CALayer that changed this frame. | |
| 565 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); | |
| 566 } | |
| 446 } else { | 567 } else { |
| 447 // Grey represents a CALayer that has not changed. | 568 // Grey represents a CALayer that has not changed. |
| 448 color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1)); | 569 color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1)); |
| 449 } | 570 } |
| 450 [ca_layer setBorderWidth:1]; | 571 [ca_layer setBorderWidth:1]; |
| 451 [ca_layer setBorderColor:color]; | 572 [ca_layer setBorderColor:color]; |
| 452 } | 573 } |
| 453 } | 574 } |
| 454 | 575 |
| 455 } // namespace content | 576 } // namespace content |
| OLD | NEW |