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

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: Fix includes 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') | no next file » | 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"
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « ui/accelerated_widget_mac/ca_renderer_layer_tree.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698