| 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 <CoreMedia/CoreMedia.h> |
| 9 #include <CoreVideo/CoreVideo.h> |
| 10 |
| 7 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 8 #include "base/mac/sdk_forward_declarations.h" | 12 #include "base/mac/sdk_forward_declarations.h" |
| 9 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 10 #include "gpu/GLES2/gl2extchromium.h" | 14 #include "gpu/GLES2/gl2extchromium.h" |
| 11 #include "third_party/skia/include/core/SkColor.h" | 15 #include "third_party/skia/include/core/SkColor.h" |
| 12 #include "ui/base/cocoa/animation_utils.h" | 16 #include "ui/base/cocoa/animation_utils.h" |
| 13 #include "ui/base/ui_base_switches.h" | 17 #include "ui/base/ui_base_switches.h" |
| 14 #include "ui/gfx/geometry/dip_util.h" | 18 #include "ui/gfx/geometry/dip_util.h" |
| 15 | 19 |
| 20 #if !defined(MAC_OS_X_VERSION_10_8) || \ |
| 21 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 |
| 22 extern NSString* const AVLayerVideoGravityResize; |
| 23 extern "C" void NSAccessibilityPostNotificationWithUserInfo( |
| 24 id object, |
| 25 NSString* notification, |
| 26 NSDictionary* user_info); |
| 27 extern "C" OSStatus CMSampleBufferCreateForImageBuffer( |
| 28 CFAllocatorRef, |
| 29 CVImageBufferRef, |
| 30 Boolean dataReady, |
| 31 CMSampleBufferMakeDataReadyCallback, |
| 32 void*, |
| 33 CMVideoFormatDescriptionRef, |
| 34 const CMSampleTimingInfo*, |
| 35 CMSampleBufferRef*); |
| 36 extern "C" CFArrayRef CMSampleBufferGetSampleAttachmentsArray(CMSampleBufferRef, |
| 37 Boolean); |
| 38 extern "C" OSStatus CMVideoFormatDescriptionCreateForImageBuffer( |
| 39 CFAllocatorRef, |
| 40 CVImageBufferRef, |
| 41 CMVideoFormatDescriptionRef*); |
| 42 extern "C" CMTime CMTimeMake(int64_t, int32_t); |
| 43 extern CFStringRef const kCMSampleAttachmentKey_DisplayImmediately; |
| 44 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 // This will enqueue |io_surface| to be drawn by |av_layer| by wrapping |
| 52 // |io_surface| in a CVPixelBuffer. This will increase the in-use count |
| 53 // of and retain |io_surface| until it is no longer being displayed. |
| 54 bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
| 55 AVSampleBufferDisplayLayer* av_layer, |
| 56 IOSurfaceRef io_surface) { |
| 57 OSStatus os_status = noErr; |
| 58 CVReturn cv_return = kCVReturnSuccess; |
| 59 |
| 60 base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer; |
| 61 cv_return = CVPixelBufferCreateWithIOSurface( |
| 62 nullptr, io_surface, nullptr, cv_pixel_buffer.InitializeInto()); |
| 63 if (cv_return != kCVReturnSuccess) { |
| 64 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; |
| 65 return false; |
| 66 } |
| 67 |
| 68 base::ScopedCFTypeRef<CMVideoFormatDescriptionRef> video_info; |
| 69 os_status = CMVideoFormatDescriptionCreateForImageBuffer( |
| 70 nullptr, cv_pixel_buffer, video_info.InitializeInto()); |
| 71 if (os_status != noErr) { |
| 72 LOG(ERROR) << "CMVideoFormatDescriptionCreateForImageBuffer failed with " |
| 73 << os_status; |
| 74 return false; |
| 75 } |
| 76 |
| 77 // The frame time doesn't matter because we will specify to display |
| 78 // immediately. |
| 79 CMTime frame_time = CMTimeMake(0, 1); |
| 80 CMSampleTimingInfo timing_info = {frame_time, frame_time, kCMTimeInvalid}; |
| 81 |
| 82 base::ScopedCFTypeRef<CMSampleBufferRef> sample_buffer; |
| 83 os_status = CMSampleBufferCreateForImageBuffer( |
| 84 nullptr, cv_pixel_buffer, YES, nullptr, nullptr, video_info, &timing_info, |
| 85 sample_buffer.InitializeInto()); |
| 86 if (os_status != noErr) { |
| 87 LOG(ERROR) << "CMSampleBufferCreateForImageBuffer failed with " |
| 88 << os_status; |
| 89 return false; |
| 90 } |
| 91 |
| 92 // Specify to display immediately via the sample buffer attachments. |
| 93 CFArrayRef attachments = |
| 94 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, YES); |
| 95 if (!attachments) { |
| 96 LOG(ERROR) << "CMSampleBufferGetSampleAttachmentsArray failed"; |
| 97 return false; |
| 98 } |
| 99 if (CFArrayGetCount(attachments) < 1) { |
| 100 LOG(ERROR) << "CMSampleBufferGetSampleAttachmentsArray result was empty"; |
| 101 return false; |
| 102 } |
| 103 CFMutableDictionaryRef attachments_dictionary = |
| 104 reinterpret_cast<CFMutableDictionaryRef>( |
| 105 const_cast<void*>(CFArrayGetValueAtIndex(attachments, 0))); |
| 106 if (!attachments_dictionary) { |
| 107 LOG(ERROR) << "Failed to get attachments dictionary"; |
| 108 return false; |
| 109 } |
| 110 CFDictionarySetValue(attachments_dictionary, |
| 111 kCMSampleAttachmentKey_DisplayImmediately, |
| 112 kCFBooleanTrue); |
| 113 |
| 114 [av_layer enqueueSampleBuffer:sample_buffer]; |
| 115 return true; |
| 116 } |
| 117 |
| 118 } // namespace |
| 119 |
| 18 CALayerTree::CALayerTree() {} | 120 CALayerTree::CALayerTree() {} |
| 19 CALayerTree::~CALayerTree() {} | 121 CALayerTree::~CALayerTree() {} |
| 20 | 122 |
| 21 bool CALayerTree::ScheduleCALayer( | 123 bool CALayerTree::ScheduleCALayer( |
| 22 bool is_clipped, | 124 bool is_clipped, |
| 23 const gfx::Rect& clip_rect, | 125 const gfx::Rect& clip_rect, |
| 24 unsigned sorting_context_id, | 126 unsigned sorting_context_id, |
| 25 const gfx::Transform& transform, | 127 const gfx::Transform& transform, |
| 26 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, | 128 base::ScopedCFTypeRef<IOSurfaceRef> io_surface, |
| 27 const gfx::RectF& contents_rect, | 129 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) | 249 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
| 148 ca_edge_aa_mask |= kCALayerBottomEdge; | 250 ca_edge_aa_mask |= kCALayerBottomEdge; |
| 149 } | 251 } |
| 150 | 252 |
| 151 // Ensure that the IOSurface be in use as soon as it is added to a | 253 // 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, | 254 // 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 | 255 // all IOSurfaces that can be used as CALayer contents in the future will be |
| 154 // marked as InUse. | 256 // marked as InUse. |
| 155 if (io_surface) | 257 if (io_surface) |
| 156 IOSurfaceIncrementUseCount(io_surface); | 258 IOSurfaceIncrementUseCount(io_surface); |
| 259 |
| 260 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to |
| 261 // AV layers. |
| 262 if (IOSurfaceGetPixelFormat(io_surface) == |
| 263 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && |
| 264 contents_rect == gfx::RectF(0, 0, 1, 1)) { |
| 265 use_av_layer = true; |
| 266 } |
| 157 } | 267 } |
| 158 | 268 |
| 159 CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) | 269 CALayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) |
| 160 : io_surface(layer.io_surface), | 270 : io_surface(layer.io_surface), |
| 161 contents_rect(layer.contents_rect), | 271 contents_rect(layer.contents_rect), |
| 162 rect(layer.rect), | 272 rect(layer.rect), |
| 163 background_color(layer.background_color), | 273 background_color(layer.background_color), |
| 164 ca_edge_aa_mask(layer.ca_edge_aa_mask), | 274 ca_edge_aa_mask(layer.ca_edge_aa_mask), |
| 165 opacity(layer.opacity), | 275 opacity(layer.opacity), |
| 166 ca_layer(layer.ca_layer) { | 276 ca_layer(layer.ca_layer), |
| 277 av_layer(layer.av_layer), |
| 278 use_av_layer(layer.use_av_layer) { |
| 167 DCHECK(!layer.ca_layer); | 279 DCHECK(!layer.ca_layer); |
| 168 layer.ca_layer.reset(); | 280 layer.ca_layer.reset(); |
| 281 layer.av_layer.reset(); |
| 169 // See remarks in the non-move constructor. | 282 // See remarks in the non-move constructor. |
| 170 if (io_surface) | 283 if (io_surface) |
| 171 IOSurfaceIncrementUseCount(io_surface); | 284 IOSurfaceIncrementUseCount(io_surface); |
| 172 } | 285 } |
| 173 | 286 |
| 174 CALayerTree::ContentLayer::~ContentLayer() { | 287 CALayerTree::ContentLayer::~ContentLayer() { |
| 175 [ca_layer removeFromSuperlayer]; | 288 [ca_layer removeFromSuperlayer]; |
| 176 // By the time the destructor is called, the IOSurface will have been passed | 289 // 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 | 290 // to the WindowServer, and will remain InUse by the WindowServer as long as |
| 178 // is needed to avoid recycling bugs. | 291 // is needed to avoid recycling bugs. |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 | 494 |
| 382 void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer, | 495 void CALayerTree::ContentLayer::CommitToCA(CALayer* superlayer, |
| 383 ContentLayer* old_layer, | 496 ContentLayer* old_layer, |
| 384 float scale_factor) { | 497 float scale_factor) { |
| 385 bool update_contents = true; | 498 bool update_contents = true; |
| 386 bool update_contents_rect = true; | 499 bool update_contents_rect = true; |
| 387 bool update_rect = true; | 500 bool update_rect = true; |
| 388 bool update_background_color = true; | 501 bool update_background_color = true; |
| 389 bool update_ca_edge_aa_mask = true; | 502 bool update_ca_edge_aa_mask = true; |
| 390 bool update_opacity = true; | 503 bool update_opacity = true; |
| 391 if (old_layer) { | 504 if (old_layer && old_layer->use_av_layer == use_av_layer) { |
| 392 DCHECK(old_layer->ca_layer); | 505 DCHECK(old_layer->ca_layer); |
| 393 std::swap(ca_layer, old_layer->ca_layer); | 506 std::swap(ca_layer, old_layer->ca_layer); |
| 507 std::swap(av_layer, old_layer->av_layer); |
| 394 update_contents = old_layer->io_surface != io_surface; | 508 update_contents = old_layer->io_surface != io_surface; |
| 395 update_contents_rect = old_layer->contents_rect != contents_rect; | 509 update_contents_rect = old_layer->contents_rect != contents_rect; |
| 396 update_rect = old_layer->rect != rect; | 510 update_rect = old_layer->rect != rect; |
| 397 update_background_color = old_layer->background_color != background_color; | 511 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; | 512 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; |
| 399 update_opacity = old_layer->opacity != opacity; | 513 update_opacity = old_layer->opacity != opacity; |
| 400 } else { | 514 } else { |
| 401 ca_layer.reset([[CALayer alloc] init]); | 515 if (use_av_layer) { |
| 516 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); |
| 517 ca_layer.reset([av_layer retain]); |
| 518 [av_layer setVideoGravity:AVLayerVideoGravityResize]; |
| 519 } else { |
| 520 ca_layer.reset([[CALayer alloc] init]); |
| 521 } |
| 402 [ca_layer setAnchorPoint:CGPointZero]; | 522 [ca_layer setAnchorPoint:CGPointZero]; |
| 403 [superlayer addSublayer:ca_layer]; | 523 [superlayer addSublayer:ca_layer]; |
| 404 } | 524 } |
| 405 DCHECK_EQ([ca_layer superlayer], superlayer); | 525 DCHECK_EQ([ca_layer superlayer], superlayer); |
| 406 bool update_anything = update_contents || update_contents_rect || | 526 bool update_anything = update_contents || update_contents_rect || |
| 407 update_rect || update_background_color || | 527 update_rect || update_background_color || |
| 408 update_ca_edge_aa_mask || update_opacity; | 528 update_ca_edge_aa_mask || update_opacity; |
| 409 | 529 if (use_av_layer) { |
| 410 if (update_contents) { | 530 if (update_contents) |
| 411 [ca_layer setContents:static_cast<id>(io_surface.get())]; | 531 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); |
| 412 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | 532 } else { |
| 413 [ca_layer setContentsScale:scale_factor]; | 533 if (update_contents) { |
| 534 [ca_layer setContents:static_cast<id>(io_surface.get())]; |
| 535 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) |
| 536 [ca_layer setContentsScale:scale_factor]; |
| 537 } |
| 538 if (update_contents_rect) |
| 539 [ca_layer setContentsRect:contents_rect.ToCGRect()]; |
| 414 } | 540 } |
| 415 if (update_contents_rect) | |
| 416 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | |
| 417 if (update_rect) { | 541 if (update_rect) { |
| 418 gfx::RectF dip_rect = gfx::RectF(rect); | 542 gfx::RectF dip_rect = gfx::RectF(rect); |
| 419 dip_rect.Scale(1 / scale_factor); | 543 dip_rect.Scale(1 / scale_factor); |
| 420 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; | 544 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; |
| 421 [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())]; | 545 [ca_layer setBounds:CGRectMake(0, 0, dip_rect.width(), dip_rect.height())]; |
| 422 } | 546 } |
| 423 if (update_background_color) { | 547 if (update_background_color) { |
| 424 CGFloat rgba_color_components[4] = { | 548 CGFloat rgba_color_components[4] = { |
| 425 SkColorGetR(background_color) / 255., | 549 SkColorGetR(background_color) / 255., |
| 426 SkColorGetG(background_color) / 255., | 550 SkColorGetG(background_color) / 255., |
| 427 SkColorGetB(background_color) / 255., | 551 SkColorGetB(background_color) / 255., |
| 428 SkColorGetA(background_color) / 255., | 552 SkColorGetA(background_color) / 255., |
| 429 }; | 553 }; |
| 430 base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate( | 554 base::ScopedCFTypeRef<CGColorRef> srgb_background_color(CGColorCreate( |
| 431 CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components)); | 555 CGColorSpaceCreateWithName(kCGColorSpaceSRGB), rgba_color_components)); |
| 432 [ca_layer setBackgroundColor:srgb_background_color]; | 556 [ca_layer setBackgroundColor:srgb_background_color]; |
| 433 } | 557 } |
| 434 if (update_ca_edge_aa_mask) | 558 if (update_ca_edge_aa_mask) |
| 435 [ca_layer setEdgeAntialiasingMask:ca_edge_aa_mask]; | 559 [ca_layer setEdgeAntialiasingMask:ca_edge_aa_mask]; |
| 436 if (update_opacity) | 560 if (update_opacity) |
| 437 [ca_layer setOpacity:opacity]; | 561 [ca_layer setOpacity:opacity]; |
| 438 | 562 |
| 439 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( | 563 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 440 switches::kShowMacOverlayBorders); | 564 switches::kShowMacOverlayBorders); |
| 441 if (show_borders) { | 565 if (show_borders) { |
| 442 base::ScopedCFTypeRef<CGColorRef> color; | 566 base::ScopedCFTypeRef<CGColorRef> color; |
| 443 if (update_anything) { | 567 if (update_anything) { |
| 444 // Pink represents a CALayer that changed this frame. | 568 if (use_av_layer) { |
| 445 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); | 569 // Green represents an AV layer that changed this frame. |
| 570 color.reset(CGColorCreateGenericRGB(0, 1, 0, 1)); |
| 571 } else { |
| 572 // Pink represents a CALayer that changed this frame. |
| 573 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); |
| 574 } |
| 446 } else { | 575 } else { |
| 447 // Grey represents a CALayer that has not changed. | 576 // Grey represents a CALayer that has not changed. |
| 448 color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1)); | 577 color.reset(CGColorCreateGenericRGB(0, 0, 0, 0.1)); |
| 449 } | 578 } |
| 450 [ca_layer setBorderWidth:1]; | 579 [ca_layer setBorderWidth:1]; |
| 451 [ca_layer setBorderColor:color]; | 580 [ca_layer setBorderColor:color]; |
| 452 } | 581 } |
| 453 } | 582 } |
| 454 | 583 |
| 455 } // namespace content | 584 } // namespace content |
| OLD | NEW |