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

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

Powered by Google App Engine
This is Rietveld 408576698