Index: ui/accelerated_widget_mac/ca_renderer_layer_tree.mm |
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm |
index 985b06e9401fbe9c2589a89627b9f8de49d64ee5..a139dc7d073b8da3a68b78e593dce4d946774f1f 100644 |
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm |
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm |
@@ -10,6 +10,7 @@ |
#include <GLES2/gl2extchromium.h> |
#include "base/command_line.h" |
+#include "base/lazy_instance.h" |
#include "base/mac/sdk_forward_declarations.h" |
#include "base/trace_event/trace_event.h" |
#include "third_party/skia/include/core/SkColor.h" |
@@ -129,10 +130,81 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
} // namespace |
+class CARendererLayerTree::SolidColorContents |
+ : public base::RefCounted<CARendererLayerTree::SolidColorContents> { |
+ public: |
+ static scoped_refptr<SolidColorContents> Get(SkColor color); |
+ id GetContents() const; |
+ |
+ private: |
+ friend class base::RefCounted<SolidColorContents>; |
+ |
+ SolidColorContents(SkColor color, IOSurfaceRef io_surface); |
+ ~SolidColorContents(); |
+ |
+ SkColor color_ = 0; |
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; |
+ static base::LazyInstance<std::map<SkColor, SolidColorContents*>> map_; |
+}; |
+ |
+base::LazyInstance<std::map<SkColor, CARendererLayerTree::SolidColorContents*>> |
+ CARendererLayerTree::SolidColorContents::map_; |
+ |
+// static |
+scoped_refptr<CARendererLayerTree::SolidColorContents> |
+CARendererLayerTree::SolidColorContents::Get(SkColor color) { |
+ const int kSolidColorContentsSize = 16; |
+ |
+ auto found = map_.Get().find(color); |
+ if (found != map_.Get().end()) |
+ return found->second; |
+ |
+ IOSurfaceRef io_surface = CreateIOSurface( |
+ gfx::Size(kSolidColorContentsSize, kSolidColorContentsSize), |
+ gfx::BufferFormat::BGRA_8888); |
+ if (!io_surface) |
+ return nullptr; |
+ |
+ size_t bytes_per_row = IOSurfaceGetBytesPerRowOfPlane(io_surface, 0); |
+ IOSurfaceLock(io_surface, 0, NULL); |
+ char* row_base_address = |
+ reinterpret_cast<char*>(IOSurfaceGetBaseAddress(io_surface)); |
+ for (int i = 0; i < kSolidColorContentsSize; ++i) { |
+ unsigned int* pixel = reinterpret_cast<unsigned int*>(row_base_address); |
+ for (int j = 0; j < kSolidColorContentsSize; ++j) |
+ *(pixel++) = color; |
+ row_base_address += bytes_per_row; |
+ } |
+ IOSurfaceUnlock(io_surface, 0, NULL); |
+ |
+ return new SolidColorContents(color, io_surface); |
+} |
+ |
+id CARendererLayerTree::SolidColorContents::GetContents() const { |
+ return static_cast<id>(io_surface_.get()); |
+} |
+ |
+CARendererLayerTree::SolidColorContents::SolidColorContents( |
+ SkColor color, |
+ IOSurfaceRef io_surface) |
+ : color_(color), io_surface_(io_surface) { |
+ DCHECK(map_.Get().find(color_) == map_.Get().end()); |
+ map_.Get()[color_] = this; |
+} |
+ |
+CARendererLayerTree::SolidColorContents::~SolidColorContents() { |
+ auto found = map_.Get().find(color_); |
+ DCHECK(found != map_.Get().end()); |
+ DCHECK(found->second == this); |
+ map_.Get().erase(color_); |
+} |
+ |
CARendererLayerTree::CARendererLayerTree( |
- bool allow_av_sample_buffer_display_layer) |
+ bool allow_av_sample_buffer_display_layer, |
+ bool allow_solid_color_layers) |
: allow_av_sample_buffer_display_layer_( |
- allow_av_sample_buffer_display_layer) {} |
+ allow_av_sample_buffer_display_layer), |
+ allow_solid_color_layers_(allow_solid_color_layers) {} |
CARendererLayerTree::~CARendererLayerTree() {} |
bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) { |
@@ -216,6 +288,9 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
return true; |
} |
+id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) { |
+ return SolidColorContents::Get(color)->GetContents(); |
+} |
CARendererLayerTree::RootLayer::RootLayer() {} |
@@ -289,6 +364,17 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { |
DCHECK(filter == GL_LINEAR || filter == GL_NEAREST); |
+ // On Mac OS Sierra, solid color layers are not color color corrected to the |
+ // output monitor color space, but IOSurface-backed layers are color |
+ // corrected. Note that this is only the case when the CALayers are shared |
+ // across processes. To make colors consistent across both solid color and |
+ // IOSurface-backed layers, use a cache of solid-color IOSurfaces as contents. |
+ // https://crbug.com/633805 |
+ if (!io_surface && !tree->allow_solid_color_layers_) { |
+ solid_color_contents = SolidColorContents::Get(background_color); |
+ ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1); |
+ } |
+ |
// Because the root layer has setGeometryFlipped:YES, there is some ambiguity |
// about what exactly top and bottom mean. This ambiguity is resolved in |
// different ways for solid color CALayers and for CALayers that have content |
@@ -301,7 +387,7 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
ca_edge_aa_mask |= kCALayerLeftEdge; |
if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM) |
ca_edge_aa_mask |= kCALayerRightEdge; |
- if (io_surface) { |
+ if (io_surface || solid_color_contents) { |
if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM) |
ca_edge_aa_mask |= kCALayerBottomEdge; |
if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM) |
@@ -326,6 +412,7 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) |
: io_surface(layer.io_surface), |
cv_pixel_buffer(layer.cv_pixel_buffer), |
+ solid_color_contents(layer.solid_color_contents), |
contents_rect(layer.contents_rect), |
rect(layer.rect), |
background_color(layer.background_color), |
@@ -548,7 +635,8 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
std::swap(ca_layer, old_layer->ca_layer); |
std::swap(av_layer, old_layer->av_layer); |
update_contents = old_layer->io_surface != io_surface || |
- old_layer->cv_pixel_buffer != cv_pixel_buffer; |
+ old_layer->cv_pixel_buffer != cv_pixel_buffer || |
+ old_layer->solid_color_contents != solid_color_contents; |
update_contents_rect = old_layer->contents_rect != contents_rect; |
update_rect = old_layer->rect != rect; |
update_background_color = old_layer->background_color != background_color; |
@@ -585,7 +673,13 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
} |
} else { |
if (update_contents) { |
- [ca_layer setContents:static_cast<id>(io_surface.get())]; |
+ if (io_surface) { |
+ [ca_layer setContents:static_cast<id>(io_surface.get())]; |
+ } else if (solid_color_contents) { |
+ [ca_layer setContents:solid_color_contents->GetContents()]; |
+ } else { |
+ [ca_layer setContents:nil]; |
+ } |
if ([ca_layer respondsToSelector:(@selector(setContentsScale:))]) |
[ca_layer setContentsScale:scale_factor]; |
} |
@@ -626,9 +720,15 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface( |
if (use_av_layer) { |
// Yellow represents an AV layer that changed this frame. |
color.reset(CGColorCreateGenericRGB(1, 1, 0, 1)); |
- } else { |
- // Pink represents a CALayer that changed this frame. |
+ } else if (io_surface) { |
+ // Magenta represents a CALayer that changed this frame. |
color.reset(CGColorCreateGenericRGB(1, 0, 1, 1)); |
+ } else if (solid_color_contents) { |
+ // Cyan represents a solid color IOSurface-backed layer. |
+ color.reset(CGColorCreateGenericRGB(0, 1, 1, 1)); |
+ } else { |
+ // Red represents a solid color layer. |
+ color.reset(CGColorCreateGenericRGB(1, 0, 0, 1)); |
} |
} else { |
// Grey represents a CALayer that has not changed. |