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

Side by Side Diff: ui/accelerated_widget_mac/ca_renderer_layer_tree.mm

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

Powered by Google App Engine
This is Rietveld 408576698