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 "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" | 5 #include "ui/accelerated_widget_mac/ca_renderer_layer_tree.h" |
6 | 6 |
7 #include <AVFoundation/AVFoundation.h> | 7 #include <AVFoundation/AVFoundation.h> |
8 #include <CoreMedia/CoreMedia.h> | 8 #include <CoreMedia/CoreMedia.h> |
9 #include <CoreVideo/CoreVideo.h> | 9 #include <CoreVideo/CoreVideo.h> |
10 #include <GLES2/gl2extchromium.h> | 10 #include <GLES2/gl2extchromium.h> |
11 | 11 |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/lazy_instance.h" |
| 14 #include "base/mac/mac_util.h" |
13 #include "base/mac/sdk_forward_declarations.h" | 15 #include "base/mac/sdk_forward_declarations.h" |
14 #include "base/trace_event/trace_event.h" | 16 #include "base/trace_event/trace_event.h" |
15 #include "third_party/skia/include/core/SkColor.h" | 17 #include "third_party/skia/include/core/SkColor.h" |
16 #include "ui/base/cocoa/animation_utils.h" | 18 #include "ui/base/cocoa/animation_utils.h" |
17 #include "ui/base/ui_base_switches.h" | 19 #include "ui/base/ui_base_switches.h" |
18 #include "ui/gfx/geometry/dip_util.h" | 20 #include "ui/gfx/geometry/dip_util.h" |
19 #include "ui/gl/ca_renderer_layer_params.h" | 21 #include "ui/gl/ca_renderer_layer_params.h" |
20 #include "ui/gl/gl_image_io_surface.h" | 22 #include "ui/gl/gl_image_io_surface.h" |
21 | 23 |
22 #if !defined(MAC_OS_X_VERSION_10_8) || \ | 24 #if !defined(MAC_OS_X_VERSION_10_8) || \ |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; | 124 LOG(ERROR) << "CVPixelBufferCreateWithIOSurface failed with " << cv_return; |
123 return false; | 125 return false; |
124 } | 126 } |
125 | 127 |
126 return AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, | 128 return AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, |
127 cv_pixel_buffer); | 129 cv_pixel_buffer); |
128 } | 130 } |
129 | 131 |
130 } // namespace | 132 } // namespace |
131 | 133 |
| 134 class CARendererLayerTree::SolidColorContents |
| 135 : public base::RefCounted<CARendererLayerTree::SolidColorContents> { |
| 136 public: |
| 137 static scoped_refptr<SolidColorContents> Get(SkColor color); |
| 138 id GetContents() const; |
| 139 |
| 140 private: |
| 141 friend class base::RefCounted<SolidColorContents>; |
| 142 |
| 143 SolidColorContents(SkColor color, IOSurfaceRef io_surface); |
| 144 ~SolidColorContents(); |
| 145 |
| 146 SkColor color_ = 0; |
| 147 base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; |
| 148 static base::LazyInstance<std::map<SkColor, SolidColorContents*>> map_; |
| 149 }; |
| 150 |
| 151 base::LazyInstance<std::map<SkColor, CARendererLayerTree::SolidColorContents*>> |
| 152 CARendererLayerTree::SolidColorContents::map_; |
| 153 |
| 154 // static |
| 155 scoped_refptr<CARendererLayerTree::SolidColorContents> |
| 156 CARendererLayerTree::SolidColorContents::Get(SkColor color) { |
| 157 const int kSolidColorContentsSize = 16; |
| 158 |
| 159 auto found = map_.Get().find(color); |
| 160 if (found != map_.Get().end()) |
| 161 return found->second; |
| 162 |
| 163 IOSurfaceRef io_surface = CreateIOSurface( |
| 164 gfx::Size(kSolidColorContentsSize, kSolidColorContentsSize), |
| 165 gfx::BufferFormat::BGRA_8888); |
| 166 if (!io_surface) |
| 167 return nullptr; |
| 168 |
| 169 size_t bytes_per_row = IOSurfaceGetBytesPerRowOfPlane(io_surface, 0); |
| 170 IOSurfaceLock(io_surface, 0, NULL); |
| 171 char* row_base_address = |
| 172 reinterpret_cast<char*>(IOSurfaceGetBaseAddress(io_surface)); |
| 173 for (int i = 0; i < kSolidColorContentsSize; ++i) { |
| 174 unsigned int* pixel = reinterpret_cast<unsigned int*>(row_base_address); |
| 175 for (int j = 0; j < kSolidColorContentsSize; ++j) |
| 176 *(pixel++) = color; |
| 177 row_base_address += bytes_per_row; |
| 178 } |
| 179 IOSurfaceUnlock(io_surface, 0, NULL); |
| 180 |
| 181 return new SolidColorContents(color, io_surface); |
| 182 } |
| 183 |
| 184 id CARendererLayerTree::SolidColorContents::GetContents() const { |
| 185 return static_cast<id>(io_surface_.get()); |
| 186 } |
| 187 |
| 188 CARendererLayerTree::SolidColorContents::SolidColorContents( |
| 189 SkColor color, |
| 190 IOSurfaceRef io_surface) |
| 191 : color_(color), io_surface_(io_surface) { |
| 192 DCHECK(map_.Get().find(color_) == map_.Get().end()); |
| 193 map_.Get()[color_] = this; |
| 194 } |
| 195 |
| 196 CARendererLayerTree::SolidColorContents::~SolidColorContents() { |
| 197 auto found = map_.Get().find(color_); |
| 198 DCHECK(found != map_.Get().end()); |
| 199 DCHECK(found->second == this); |
| 200 map_.Get().erase(color_); |
| 201 } |
| 202 |
132 CARendererLayerTree::CARendererLayerTree( | 203 CARendererLayerTree::CARendererLayerTree( |
133 bool allow_av_sample_buffer_display_layer) | 204 bool allow_av_sample_buffer_display_layer) |
134 : allow_av_sample_buffer_display_layer_( | 205 : allow_av_sample_buffer_display_layer_( |
135 allow_av_sample_buffer_display_layer) {} | 206 allow_av_sample_buffer_display_layer) {} |
136 CARendererLayerTree::~CARendererLayerTree() {} | 207 CARendererLayerTree::~CARendererLayerTree() {} |
137 | 208 |
138 bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { | 209 bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { |
139 // Excessive logging to debug white screens (crbug.com/583805). | 210 // Excessive logging to debug white screens (crbug.com/583805). |
140 // TODO(ccameron): change this back to a DLOG. | 211 // TODO(ccameron): change this back to a DLOG. |
141 if (has_committed_) { | 212 if (has_committed_) { |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 : io_surface(io_surface), | 353 : io_surface(io_surface), |
283 cv_pixel_buffer(cv_pixel_buffer), | 354 cv_pixel_buffer(cv_pixel_buffer), |
284 contents_rect(contents_rect), | 355 contents_rect(contents_rect), |
285 rect(rect), | 356 rect(rect), |
286 background_color(background_color), | 357 background_color(background_color), |
287 ca_edge_aa_mask(0), | 358 ca_edge_aa_mask(0), |
288 opacity(opacity), | 359 opacity(opacity), |
289 ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { | 360 ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { |
290 DCHECK(filter == GL_LINEAR || filter == GL_NEAREST); | 361 DCHECK(filter == GL_LINEAR || filter == GL_NEAREST); |
291 | 362 |
| 363 // On Mac OS Sierra, solid color layers are not color color corrected to the |
| 364 // output monitor color space, but IOSurface-backed layers are color |
| 365 // corrected. Note that this is only the case when the CALayers are shared |
| 366 // across processes. To make colors consistent across both solid color and |
| 367 // IOSurface-backed layers, use a cache of solid-color IOSurfaces as contents. |
| 368 // https://crbug.com/633805 |
| 369 if (base::mac::IsAtLeastOS10_12()) { |
| 370 solid_color_contents = SolidColorContents::Get(background_color); |
| 371 ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1); |
| 372 } |
| 373 |
292 // Because the root layer has setGeometryFlipped:YES, there is some ambiguity | 374 // Because the root layer has setGeometryFlipped:YES, there is some ambiguity |
293 // about what exactly top and bottom mean. This ambiguity is resolved in | 375 // about what exactly top and bottom mean. This ambiguity is resolved in |
294 // different ways for solid color CALayers and for CALayers that have content | 376 // different ways for solid color CALayers and for CALayers that have content |
295 // (surprise!). For CALayers with IOSurface content, the top edge in the AA | 377 // (surprise!). For CALayers with IOSurface content, the top edge in the AA |
296 // mask refers to what appears as the bottom edge on-screen. For CALayers | 378 // mask refers to what appears as the bottom edge on-screen. For CALayers |
297 // without content (solid color layers), the top edge in the AA mask is the | 379 // without content (solid color layers), the top edge in the AA mask is the |
298 // top edge on-screen. | 380 // top edge on-screen. |
299 // https://crbug.com/567946 | 381 // https://crbug.com/567946 |
300 if (edge_aa_mask & GL_CA_LAYER_EDGE_LEFT_CHROMIUM) | 382 if (edge_aa_mask & GL_CA_LAYER_EDGE_LEFT_CHROMIUM) |
301 ca_edge_aa_mask |= kCALayerLeftEdge; | 383 ca_edge_aa_mask |= kCALayerLeftEdge; |
302 if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) | 384 if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) |
303 ca_edge_aa_mask |= kCALayerRightEdge; | 385 ca_edge_aa_mask |= kCALayerRightEdge; |
304 if (io_surface) { | 386 if (io_surface || solid_color_contents) { |
305 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) | 387 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) |
306 ca_edge_aa_mask |= kCALayerBottomEdge; | 388 ca_edge_aa_mask |= kCALayerBottomEdge; |
307 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) | 389 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
308 ca_edge_aa_mask |= kCALayerTopEdge; | 390 ca_edge_aa_mask |= kCALayerTopEdge; |
309 } else { | 391 } else { |
310 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) | 392 if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) |
311 ca_edge_aa_mask |= kCALayerTopEdge; | 393 ca_edge_aa_mask |= kCALayerTopEdge; |
312 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) | 394 if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
313 ca_edge_aa_mask |= kCALayerBottomEdge; | 395 ca_edge_aa_mask |= kCALayerBottomEdge; |
314 } | 396 } |
315 | 397 |
316 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to | 398 // Only allow 4:2:0 frames which fill the layer's contents to be promoted to |
317 // AV layers. | 399 // AV layers. |
318 if (tree->allow_av_sample_buffer_display_layer_ && | 400 if (tree->allow_av_sample_buffer_display_layer_ && |
319 IOSurfaceGetPixelFormat(io_surface) == | 401 IOSurfaceGetPixelFormat(io_surface) == |
320 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && | 402 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange && |
321 contents_rect == gfx::RectF(0, 0, 1, 1)) { | 403 contents_rect == gfx::RectF(0, 0, 1, 1)) { |
322 use_av_layer = true; | 404 use_av_layer = true; |
323 } | 405 } |
324 } | 406 } |
325 | 407 |
326 CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) | 408 CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) |
327 : io_surface(layer.io_surface), | 409 : io_surface(layer.io_surface), |
328 cv_pixel_buffer(layer.cv_pixel_buffer), | 410 cv_pixel_buffer(layer.cv_pixel_buffer), |
| 411 solid_color_contents(layer.solid_color_contents), |
329 contents_rect(layer.contents_rect), | 412 contents_rect(layer.contents_rect), |
330 rect(layer.rect), | 413 rect(layer.rect), |
331 background_color(layer.background_color), | 414 background_color(layer.background_color), |
332 ca_edge_aa_mask(layer.ca_edge_aa_mask), | 415 ca_edge_aa_mask(layer.ca_edge_aa_mask), |
333 opacity(layer.opacity), | 416 opacity(layer.opacity), |
334 ca_filter(layer.ca_filter), | 417 ca_filter(layer.ca_filter), |
335 ca_layer(std::move(layer.ca_layer)), | 418 ca_layer(std::move(layer.ca_layer)), |
336 av_layer(std::move(layer.av_layer)), | 419 av_layer(std::move(layer.av_layer)), |
337 use_av_layer(layer.use_av_layer) { | 420 use_av_layer(layer.use_av_layer) { |
338 DCHECK(!layer.ca_layer); | 421 DCHECK(!layer.ca_layer); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 bool update_rect = true; | 624 bool update_rect = true; |
542 bool update_background_color = true; | 625 bool update_background_color = true; |
543 bool update_ca_edge_aa_mask = true; | 626 bool update_ca_edge_aa_mask = true; |
544 bool update_opacity = true; | 627 bool update_opacity = true; |
545 bool update_ca_filter = true; | 628 bool update_ca_filter = true; |
546 if (old_layer && old_layer->use_av_layer == use_av_layer) { | 629 if (old_layer && old_layer->use_av_layer == use_av_layer) { |
547 DCHECK(old_layer->ca_layer); | 630 DCHECK(old_layer->ca_layer); |
548 std::swap(ca_layer, old_layer->ca_layer); | 631 std::swap(ca_layer, old_layer->ca_layer); |
549 std::swap(av_layer, old_layer->av_layer); | 632 std::swap(av_layer, old_layer->av_layer); |
550 update_contents = old_layer->io_surface != io_surface || | 633 update_contents = old_layer->io_surface != io_surface || |
551 old_layer->cv_pixel_buffer != cv_pixel_buffer; | 634 old_layer->cv_pixel_buffer != cv_pixel_buffer || |
| 635 old_layer->solid_color_contents != solid_color_contents; |
552 update_contents_rect = old_layer->contents_rect != contents_rect; | 636 update_contents_rect = old_layer->contents_rect != contents_rect; |
553 update_rect = old_layer->rect != rect; | 637 update_rect = old_layer->rect != rect; |
554 update_background_color = old_layer->background_color != background_color; | 638 update_background_color = old_layer->background_color != background_color; |
555 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; | 639 update_ca_edge_aa_mask = old_layer->ca_edge_aa_mask != ca_edge_aa_mask; |
556 update_opacity = old_layer->opacity != opacity; | 640 update_opacity = old_layer->opacity != opacity; |
557 update_ca_filter = old_layer->ca_filter != ca_filter; | 641 update_ca_filter = old_layer->ca_filter != ca_filter; |
558 } else { | 642 } else { |
559 if (use_av_layer) { | 643 if (use_av_layer) { |
560 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); | 644 av_layer.reset([[AVSampleBufferDisplayLayer alloc] init]); |
561 ca_layer.reset([av_layer retain]); | 645 ca_layer.reset([av_layer retain]); |
(...skipping 16 matching lines...) Expand all Loading... |
578 if (update_contents) { | 662 if (update_contents) { |
579 if (cv_pixel_buffer) { | 663 if (cv_pixel_buffer) { |
580 AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, | 664 AVSampleBufferDisplayLayerEnqueueCVPixelBuffer(av_layer, |
581 cv_pixel_buffer); | 665 cv_pixel_buffer); |
582 } else { | 666 } else { |
583 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); | 667 AVSampleBufferDisplayLayerEnqueueIOSurface(av_layer, io_surface); |
584 } | 668 } |
585 } | 669 } |
586 } else { | 670 } else { |
587 if (update_contents) { | 671 if (update_contents) { |
588 [ca_layer setContents:static_cast<id>(io_surface.get())]; | 672 if (io_surface) { |
| 673 [ca_layer setContents:static_cast<id>(io_surface.get())]; |
| 674 } else if (solid_color_contents) { |
| 675 [ca_layer setContents:solid_color_contents->GetContents()]; |
| 676 } |
589 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) | 677 if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) |
590 [ca_layer setContentsScale:scale_factor]; | 678 [ca_layer setContentsScale:scale_factor]; |
591 } | 679 } |
592 if (update_contents_rect) | 680 if (update_contents_rect) |
593 [ca_layer setContentsRect:contents_rect.ToCGRect()]; | 681 [ca_layer setContentsRect:contents_rect.ToCGRect()]; |
594 } | 682 } |
595 if (update_rect) { | 683 if (update_rect) { |
596 gfx::RectF dip_rect = gfx::RectF(rect); | 684 gfx::RectF dip_rect = gfx::RectF(rect); |
597 dip_rect.Scale(1 / scale_factor); | 685 dip_rect.Scale(1 / scale_factor); |
598 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; | 686 [ca_layer setPosition:CGPointMake(dip_rect.x(), dip_rect.y())]; |
(...skipping 20 matching lines...) Expand all Loading... |
619 } | 707 } |
620 | 708 |
621 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( | 709 static bool show_borders = base::CommandLine::ForCurrentProcess()->HasSwitch( |
622 switches::kShowMacOverlayBorders); | 710 switches::kShowMacOverlayBorders); |
623 if (show_borders) { | 711 if (show_borders) { |
624 base::ScopedCFTypeRef<CGColorRef> color; | 712 base::ScopedCFTypeRef<CGColorRef> color; |
625 if (update_anything) { | 713 if (update_anything) { |
626 if (use_av_layer) { | 714 if (use_av_layer) { |
627 // Yellow represents an AV layer that changed this frame. | 715 // Yellow represents an AV layer that changed this frame. |
628 color.reset(CGColorCreateGenericRGB(1, 1, 0, 1)); | 716 color.reset(CGColorCreateGenericRGB(1, 1, 0, 1)); |
629 } else { | 717 } else if (io_surface) { |
630 // Pink represents a CALayer that changed this frame. | 718 // Pink represents a CALayer that changed this frame. |
631 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); | 719 color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); |
| 720 } else if (solid_color_contents) { |
| 721 // Cyan represents a solid color IOSurface-backed layer. |
| 722 color.reset(CGColorCreateGenericRGB(0, 1, 1, 1)); |
| 723 } else { |
| 724 // Red represents a solid color layer. |
| 725 color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); |
632 } | 726 } |
633 } else { | 727 } else { |
634 // Grey represents a CALayer that has not changed. | 728 // Grey represents a CALayer that has not changed. |
635 color.reset(CGColorCreateGenericRGB(0.5, 0.5, 0.5, 1)); | 729 color.reset(CGColorCreateGenericRGB(0.5, 0.5, 0.5, 1)); |
636 } | 730 } |
637 [ca_layer setBorderWidth:1]; | 731 [ca_layer setBorderWidth:1]; |
638 [ca_layer setBorderColor:color]; | 732 [ca_layer setBorderColor:color]; |
639 } | 733 } |
640 } | 734 } |
641 | 735 |
642 } // namespace ui | 736 } // namespace ui |
OLD | NEW |