Commit ca242391 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

HDR/macOS Tonemapping: Plumb color space

Add plumbing to send the gfx::ColorSpace of the GLImage through to the
HDRCopierLayer.

Bug: 1101041
Change-Id: Ia41022d068b6daea5f1fd17191468cf89c463e37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352618
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798469}
parent 29289e6c
...@@ -27,6 +27,7 @@ component("metal_util") { ...@@ -27,6 +27,7 @@ component("metal_util") {
deps = [ deps = [
"//base", "//base",
"//components/crash/core/common:crash_key", "//components/crash/core/common:crash_key",
"//ui/gfx",
] ]
frameworks = [ frameworks = [
......
include_rules = [ include_rules = [
"+components/crash/core/common/crash_key.h", "+components/crash/core/common/crash_key.h",
"+ui/gfx",
] ]
...@@ -7,19 +7,29 @@ ...@@ -7,19 +7,29 @@
#include "components/metal_util/metal_util_export.h" #include "components/metal_util/metal_util_export.h"
#include <IOSurface/IOSurface.h>
namespace gfx {
class ColorSpace;
} // namespace gfx
@class CALayer; @class CALayer;
namespace metal { namespace metal {
// Return true if we should use the HDRCopier for the specified content.
bool METAL_UTIL_EXPORT ShouldUseHDRCopier(IOSurfaceRef buffer,
const gfx::ColorSpace& color_space);
// Create a layer which may have its contents set an HDR IOSurface via // Create a layer which may have its contents set an HDR IOSurface via
// the -[CALayer setContents:] method. // UpdateHDRCopierLayer.
// - The IOSurface specified to setContents must have pixel format
// kCVPixelFormatType_64RGBAHalf or kCVPixelFormatType_ARGB2101010LEPacked,
// any other pixel formats will be NOTREACHED.
// - This layer will, in setContents, blit the contents of the specified
// IOSurface to an HDR-capable CAMetalLayer.
CALayer* METAL_UTIL_EXPORT CreateHDRCopierLayer(); CALayer* METAL_UTIL_EXPORT CreateHDRCopierLayer();
// Update the contents of |layer| to the specified IOSurface and color space.
void METAL_UTIL_EXPORT UpdateHDRCopierLayer(CALayer* layer,
IOSurfaceRef buffer,
const gfx::ColorSpace& color_space);
} // namespace metal } // namespace metal
#endif // COMPONENTS_METAL_UTIL_HDR_COPIER_LAYER_H_ #endif // COMPONENTS_METAL_UTIL_HDR_COPIER_LAYER_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/notreached.h" #include "base/notreached.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/metal_util/device.h" #include "components/metal_util/device.h"
#include "ui/gfx/color_space.h"
namespace { namespace {
...@@ -67,7 +68,6 @@ MTLPixelFormat IOSurfaceGetMTLPixelFormat(IOSurfaceRef buffer) ...@@ -67,7 +68,6 @@ MTLPixelFormat IOSurfaceGetMTLPixelFormat(IOSurfaceRef buffer)
default: default:
break; break;
} }
NOTREACHED();
return MTLPixelFormatInvalid; return MTLPixelFormatInvalid;
} }
...@@ -146,7 +146,8 @@ API_AVAILABLE(macos(10.15)) ...@@ -146,7 +146,8 @@ API_AVAILABLE(macos(10.15))
base::scoped_nsprotocol<id<MTLRenderPipelineState>> _render_pipeline_state; base::scoped_nsprotocol<id<MTLRenderPipelineState>> _render_pipeline_state;
} }
- (id)init; - (id)init;
- (void)setContents:(id)contents; - (void)setHDRContents:(IOSurfaceRef)buffer
withColorSpace:(gfx::ColorSpace)color_space;
@end @end
@implementation HDRCopierLayer @implementation HDRCopierLayer
...@@ -161,9 +162,8 @@ API_AVAILABLE(macos(10.15)) ...@@ -161,9 +162,8 @@ API_AVAILABLE(macos(10.15))
return self; return self;
} }
- (void)setContents:(id)contents { - (void)setHDRContents:(IOSurfaceRef)buffer
IOSurfaceRef buffer = reinterpret_cast<IOSurfaceRef>(contents); withColorSpace:(gfx::ColorSpace)color_space {
// Retrieve information about the IOSurface. // Retrieve information about the IOSurface.
size_t width = IOSurfaceGetWidth(buffer); size_t width = IOSurfaceGetWidth(buffer);
size_t height = IOSurfaceGetHeight(buffer); size_t height = IOSurfaceGetHeight(buffer);
...@@ -277,8 +277,29 @@ CALayer* CreateHDRCopierLayer() { ...@@ -277,8 +277,29 @@ CALayer* CreateHDRCopierLayer() {
// (HDR content will be clipped, but that would have happened anyway). // (HDR content will be clipped, but that would have happened anyway).
if (@available(macos 10.15, *)) if (@available(macos 10.15, *))
return [[HDRCopierLayer alloc] init]; return [[HDRCopierLayer alloc] init];
else NOTREACHED();
return [[CALayer alloc] init]; return nil;
}
void UpdateHDRCopierLayer(CALayer* layer,
IOSurfaceRef buffer,
const gfx::ColorSpace& color_space) {
if (@available(macos 10.15, *)) {
if (auto* hdr_copier_layer = base::mac::ObjCCast<HDRCopierLayer>(layer)) {
[hdr_copier_layer setHDRContents:buffer withColorSpace:color_space];
return;
}
}
NOTREACHED();
}
bool ShouldUseHDRCopier(IOSurfaceRef buffer,
const gfx::ColorSpace& color_space) {
if (@available(macos 10.15, *)) {
return color_space.IsHDR() &&
IOSurfaceGetMTLPixelFormat(buffer) != MTLPixelFormatInvalid;
}
return false;
} }
} // namespace metal } // namespace metal
...@@ -169,7 +169,7 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree { ...@@ -169,7 +169,7 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
const gfx::RectF& contents_rect, const gfx::RectF& contents_rect,
const gfx::Rect& rect, const gfx::Rect& rect,
unsigned background_color, unsigned background_color,
bool has_hdr_color_space, const gfx::ColorSpace& color_space,
unsigned edge_aa_mask, unsigned edge_aa_mask,
float opacity, float opacity,
unsigned filter); unsigned filter);
...@@ -191,6 +191,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree { ...@@ -191,6 +191,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
gfx::RectF contents_rect; gfx::RectF contents_rect;
gfx::RectF rect; gfx::RectF rect;
unsigned background_color = 0; unsigned background_color = 0;
// The color space of |io_surface|. Used for HDR tonemapping.
gfx::ColorSpace io_surface_color_space;
// Note that the CoreAnimation edge antialiasing mask is not the same as // Note that the CoreAnimation edge antialiasing mask is not the same as
// the edge antialiasing mask passed to the constructor. // the edge antialiasing mask passed to the constructor.
CAEdgeAntialiasingMask ca_edge_aa_mask = 0; CAEdgeAntialiasingMask ca_edge_aa_mask = 0;
......
...@@ -385,7 +385,7 @@ CARendererLayerTree::ContentLayer::ContentLayer( ...@@ -385,7 +385,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(
const gfx::RectF& contents_rect, const gfx::RectF& contents_rect,
const gfx::Rect& rect_in, const gfx::Rect& rect_in,
unsigned background_color, unsigned background_color,
bool has_hdr_color_space, const gfx::ColorSpace& io_surface_color_space,
unsigned edge_aa_mask, unsigned edge_aa_mask,
float opacity, float opacity,
unsigned filter) unsigned filter)
...@@ -394,6 +394,7 @@ CARendererLayerTree::ContentLayer::ContentLayer( ...@@ -394,6 +394,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(
contents_rect(contents_rect), contents_rect(contents_rect),
rect(rect_in), rect(rect_in),
background_color(background_color), background_color(background_color),
io_surface_color_space(io_surface_color_space),
ca_edge_aa_mask(0), ca_edge_aa_mask(0),
opacity(opacity), opacity(opacity),
ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) { ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) {
...@@ -439,14 +440,10 @@ CARendererLayerTree::ContentLayer::ContentLayer( ...@@ -439,14 +440,10 @@ CARendererLayerTree::ContentLayer::ContentLayer(
} }
// Determine which type of CALayer subclass we should use. // Determine which type of CALayer subclass we should use.
if (io_surface) { if (metal::ShouldUseHDRCopier(io_surface, io_surface_color_space)) {
type = CALayerType::kHDRCopier;
} else if (io_surface) {
switch (IOSurfaceGetPixelFormat(io_surface)) { switch (IOSurfaceGetPixelFormat(io_surface)) {
case kCVPixelFormatType_64RGBAHalf:
case kCVPixelFormatType_ARGB2101010LEPacked:
// HDR content can come in either as half-float or as 10-10-10-2.
if (has_hdr_color_space)
type = CALayerType::kHDRCopier;
break;
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange: case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
// Only allow 4:2:0 frames which fill the layer's contents to be // Only allow 4:2:0 frames which fill the layer's contents to be
...@@ -496,6 +493,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer) ...@@ -496,6 +493,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer)
contents_rect(layer.contents_rect), contents_rect(layer.contents_rect),
rect(layer.rect), rect(layer.rect),
background_color(layer.background_color), background_color(layer.background_color),
io_surface_color_space(layer.io_surface_color_space),
ca_edge_aa_mask(layer.ca_edge_aa_mask), ca_edge_aa_mask(layer.ca_edge_aa_mask),
opacity(layer.opacity), opacity(layer.opacity),
ca_filter(layer.ca_filter), ca_filter(layer.ca_filter),
...@@ -571,7 +569,7 @@ void CARendererLayerTree::TransformLayer::AddContentLayer( ...@@ -571,7 +569,7 @@ void CARendererLayerTree::TransformLayer::AddContentLayer(
const CARendererLayerParams& params) { const CARendererLayerParams& params) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface; base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer; base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
bool has_hdr_color_space = false; gfx::ColorSpace io_surface_color_space;
if (params.image) { if (params.image) {
gl::GLImageIOSurface* io_surface_image = gl::GLImageIOSurface* io_surface_image =
gl::GLImageIOSurface::FromGLImage(params.image); gl::GLImageIOSurface::FromGLImage(params.image);
...@@ -585,11 +583,11 @@ void CARendererLayerTree::TransformLayer::AddContentLayer( ...@@ -585,11 +583,11 @@ void CARendererLayerTree::TransformLayer::AddContentLayer(
// TODO(ccameron): If this indeed causes the bug to disappear, then // TODO(ccameron): If this indeed causes the bug to disappear, then
// extirpate the CVPixelBufferRef path. // extirpate the CVPixelBufferRef path.
// cv_pixel_buffer = io_surface_image->cv_pixel_buffer(); // cv_pixel_buffer = io_surface_image->cv_pixel_buffer();
has_hdr_color_space = params.image->color_space().IsHDR(); io_surface_color_space = params.image->color_space();
} }
content_layers.push_back( content_layers.push_back(
ContentLayer(tree, io_surface, cv_pixel_buffer, params.contents_rect, ContentLayer(tree, io_surface, cv_pixel_buffer, params.contents_rect,
params.rect, params.background_color, has_hdr_color_space, params.rect, params.background_color, io_surface_color_space,
params.edge_aa_mask, params.opacity, params.filter)); params.edge_aa_mask, params.opacity, params.filter));
} }
...@@ -809,7 +807,10 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer, ...@@ -809,7 +807,10 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
switch (type) { switch (type) {
case CALayerType::kHDRCopier: case CALayerType::kHDRCopier:
[ca_layer setContents:static_cast<id>(io_surface.get())]; if (update_contents) {
metal::UpdateHDRCopierLayer(ca_layer.get(), io_surface.get(),
io_surface_color_space);
}
break; break;
case CALayerType::kVideo: case CALayerType::kVideo:
if (update_contents) { if (update_contents) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment