Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: content/common/gpu/ca_layer_tree_mac.mm

Issue 1828523003: Mac: Use AVSampleBufferDisplayLayer for 4:2:0 surfaces (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Formatting Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « content/common/gpu/ca_layer_tree_mac.h ('k') | content/common/gpu/ca_layer_tree_unittest_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698