summaryrefslogtreecommitdiff
path: root/chromium/components/metal_util
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-29 10:46:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-02 12:02:10 +0000
commit99677208ff3b216fdfec551fbe548da5520cd6fb (patch)
tree476a4865c10320249360e859d8fdd3e01833b03a /chromium/components/metal_util
parentc30a6232df03e1efbd9f3b226777b07e087a1122 (diff)
downloadqtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/metal_util')
-rw-r--r--chromium/components/metal_util/BUILD.gn2
-rw-r--r--chromium/components/metal_util/DEPS1
-rw-r--r--chromium/components/metal_util/OWNERS2
-rw-r--r--chromium/components/metal_util/hdr_copier_layer.h22
-rw-r--r--chromium/components/metal_util/hdr_copier_layer.mm298
5 files changed, 277 insertions, 48 deletions
diff --git a/chromium/components/metal_util/BUILD.gn b/chromium/components/metal_util/BUILD.gn
index 86b8df42472..303a77c32bb 100644
--- a/chromium/components/metal_util/BUILD.gn
+++ b/chromium/components/metal_util/BUILD.gn
@@ -27,6 +27,8 @@ component("metal_util") {
deps = [
"//base",
"//components/crash/core/common:crash_key",
+ "//skia:skcms",
+ "//ui/gfx",
]
frameworks = [
diff --git a/chromium/components/metal_util/DEPS b/chromium/components/metal_util/DEPS
index 90e574cf755..54bf698ab3c 100644
--- a/chromium/components/metal_util/DEPS
+++ b/chromium/components/metal_util/DEPS
@@ -1,3 +1,4 @@
include_rules = [
"+components/crash/core/common/crash_key.h",
+ "+ui/gfx",
]
diff --git a/chromium/components/metal_util/OWNERS b/chromium/components/metal_util/OWNERS
index f82eef2402e..6d0eed7867b 100644
--- a/chromium/components/metal_util/OWNERS
+++ b/chromium/components/metal_util/OWNERS
@@ -1,5 +1,5 @@
ccameron@chromium.org
-jvanverth@google.org
+jvanverth@google.com
# TEAM: graphics-dev@chromium.org
# COMPONENT: Internals>Compositing
diff --git a/chromium/components/metal_util/hdr_copier_layer.h b/chromium/components/metal_util/hdr_copier_layer.h
index f1cf0be7476..98bda007328 100644
--- a/chromium/components/metal_util/hdr_copier_layer.h
+++ b/chromium/components/metal_util/hdr_copier_layer.h
@@ -7,19 +7,29 @@
#include "components/metal_util/metal_util_export.h"
+#include <IOSurface/IOSurface.h>
+
+namespace gfx {
+class ColorSpace;
+} // namespace gfx
+
@class CALayer;
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
-// the -[CALayer setContents:] method.
-// - 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.
+// UpdateHDRCopierLayer.
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
#endif // COMPONENTS_METAL_UTIL_HDR_COPIER_LAYER_H_
diff --git a/chromium/components/metal_util/hdr_copier_layer.mm b/chromium/components/metal_util/hdr_copier_layer.mm
index 0feab83ca6f..13598a1929e 100644
--- a/chromium/components/metal_util/hdr_copier_layer.mm
+++ b/chromium/components/metal_util/hdr_copier_layer.mm
@@ -14,9 +14,128 @@
#include "base/notreached.h"
#include "base/strings/sys_string_conversions.h"
#include "components/metal_util/device.h"
+#include "ui/gfx/color_space.h"
namespace {
+// Source of the shader to perform tonemapping. Note that the functions
+// ToLinearSRGB, ToLinearPQ, and ToLinearHLG are copy-pasted from the GLSL
+// shader source in gfx::ColorTransform.
+// TODO(https://crbug.com/1101041): Add non-identity tonemapping to the shader.
+const char* tonemapping_shader_source =
+ "#include <metal_stdlib>\n"
+ "#include <simd/simd.h>\n"
+ "using metal::float2;\n"
+ "using metal::float3;\n"
+ "using metal::float3x3;\n"
+ "using metal::float4;\n"
+ "using metal::sampler;\n"
+ "using metal::texture2d;\n"
+ "using metal::abs;\n"
+ "using metal::exp;\n"
+ "using metal::max;\n"
+ "using metal::pow;\n"
+ "using metal::sign;\n"
+ "\n"
+ "typedef struct {\n"
+ " float4 clipSpacePosition [[position]];\n"
+ " float2 texcoord;\n"
+ "} RasterizerData;\n"
+ "\n"
+ "float ToLinearSRGB(float v) {\n"
+ " float abs_v = abs(v);\n"
+ " float sgn_v = sign(v);\n"
+ " if (abs_v < 0.0404482362771082f)\n"
+ " return v/12.92f;\n"
+ " else\n"
+ " return sgn_v*pow((abs_v+0.055f)/1.055f, 2.4f);\n"
+ "}\n"
+ "\n"
+ "float ToLinearPQ(float v) {\n"
+ " v = max(0.0f, v);\n"
+ " constexpr float m1 = (2610.0 / 4096.0) / 4.0;\n"
+ " constexpr float m2 = (2523.0 / 4096.0) * 128.0;\n"
+ " constexpr float c1 = 3424.0 / 4096.0;\n"
+ " constexpr float c2 = (2413.0 / 4096.0) * 32.0;\n"
+ " constexpr float c3 = (2392.0 / 4096.0) * 32.0;\n"
+ " float p = pow(v, 1.f / m2);\n"
+ " v = pow(max(p - c1, 0.f) / (c2 - c3 * p), 1.f / m1);\n"
+ " float sdr_white_level = 100.f;\n"
+ " v *= 10000.f / sdr_white_level;\n"
+ " return v;\n"
+ "}\n"
+ "\n"
+ "float ToLinearHLG(float v) {\n"
+ " constexpr float a = 0.17883277;\n"
+ " constexpr float b = 0.28466892;\n"
+ " constexpr float c = 0.55991073;\n"
+ " v = max(0.f, v);\n"
+ " if (v <= 0.5f)\n"
+ " return (v * 2.f) * (v * 2.f);\n"
+ " return exp((v - c) / a) + b;\n"
+ "}\n"
+ "\n"
+ "vertex RasterizerData vertexShader(\n"
+ " uint vertexID [[vertex_id]],\n"
+ " constant float2 *positions[[buffer(0)]]) {\n"
+ " RasterizerData out;\n"
+ " out.clipSpacePosition = vector_float4(0.f, 0.f, 0.f, 1.f);\n"
+ " out.clipSpacePosition.x = 2.f * positions[vertexID].x - 1.f;\n"
+ " out.clipSpacePosition.y = -2.f * positions[vertexID].y + 1.f;\n"
+ " out.texcoord = positions[vertexID];\n"
+ " return out;\n"
+ "}\n"
+ "\n"
+ "float3 ToneMap(float3 v) {\n"
+ " return v;\n"
+ "}\n"
+ "\n"
+ "fragment float4 fragmentShader(RasterizerData in [[stage_in]],\n"
+ " texture2d<float> t [[texture(0)]],\n"
+ " constant float3x3& m [[buffer(0)]],\n"
+ " constant uint32_t& f [[buffer(1)]]) {\n"
+ " constexpr sampler s(metal::mag_filter::nearest,\n"
+ " metal::min_filter::nearest);\n"
+ " float4 color = t.sample(s, in.texcoord);\n"
+ " switch (f) {\n"
+ " case 1:\n"
+ " color.x = ToLinearSRGB(color.x);\n"
+ " color.y = ToLinearSRGB(color.y);\n"
+ " color.z = ToLinearSRGB(color.z);\n"
+ " break;\n"
+ " case 2:\n"
+ " color.x = ToLinearPQ(color.x);\n"
+ " color.y = ToLinearPQ(color.y);\n"
+ " color.z = ToLinearPQ(color.z);\n"
+ " break;\n"
+ " case 3:\n"
+ " color.x = ToLinearHLG(color.x);\n"
+ " color.y = ToLinearHLG(color.y);\n"
+ " color.z = ToLinearHLG(color.z);\n"
+ " break;\n"
+ " default:\n"
+ " break;\n"
+ " }\n"
+ " color.xyz = ToneMap(m * color.xyz);\n"
+ " return color;\n"
+ "}\n";
+
+// Return the integer to use to specify a transfer function to the shader
+// defined in the above source. Return 0 if the transfer function is
+// unsupported.
+uint32_t GetTransferFunctionIndex(const gfx::ColorSpace& color_space) {
+ switch (color_space.GetTransferID()) {
+ case gfx::ColorSpace::TransferID::IEC61966_2_1_HDR:
+ return 1;
+ case gfx::ColorSpace::TransferID::SMPTEST2084:
+ return 2;
+ case gfx::ColorSpace::TransferID::ARIB_STD_B67:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
// Convert from an IOSurface's pixel format to a MTLPixelFormat. Crash on any
// unsupported formats.
MTLPixelFormat IOSurfaceGetMTLPixelFormat(IOSurfaceRef buffer)
@@ -30,26 +149,50 @@ MTLPixelFormat IOSurfaceGetMTLPixelFormat(IOSurfaceRef buffer)
default:
break;
}
- NOTREACHED();
return MTLPixelFormatInvalid;
}
-// Retrieve the named color space from an IOSurface and convert it to a
-// CGColorSpace. Return nullptr on failure.
-CGColorSpaceRef IOSurfaceCopyCGColorSpace(IOSurfaceRef buffer) {
- base::ScopedCFTypeRef<CFTypeRef> color_space_value(
- IOSurfaceCopyValue(buffer, CFSTR("IOSurfaceColorSpace")));
- if (!color_space_value)
- return nullptr;
- CFStringRef color_space_string =
- base::mac::CFCast<CFStringRef>(color_space_value);
- if (!color_space_string)
- return nullptr;
- base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
- CGColorSpaceCreateWithName(color_space_string));
- if (!color_space)
- return nullptr;
- return color_space.release();
+base::scoped_nsprotocol<id<MTLRenderPipelineState>> CreateRenderPipelineState(
+ id<MTLDevice> device) API_AVAILABLE(macos(10.13)) {
+ base::scoped_nsprotocol<id<MTLRenderPipelineState>> render_pipeline_state;
+
+ base::scoped_nsprotocol<id<MTLLibrary>> library;
+ {
+ NSError* error = nil;
+ base::scoped_nsobject<NSString> source([[NSString alloc]
+ initWithCString:tonemapping_shader_source
+ encoding:NSASCIIStringEncoding]);
+ base::scoped_nsobject<MTLCompileOptions> options(
+ [[MTLCompileOptions alloc] init]);
+ library.reset([device newLibraryWithSource:source
+ options:options
+ error:&error]);
+ if (error) {
+ NSLog(@"Failed to compile shader: %@", error);
+ return render_pipeline_state;
+ }
+ }
+
+ {
+ base::scoped_nsprotocol<id<MTLFunction>> vertex_function(
+ [library newFunctionWithName:@"vertexShader"]);
+ base::scoped_nsprotocol<id<MTLFunction>> fragment_function(
+ [library newFunctionWithName:@"fragmentShader"]);
+ NSError* error = nil;
+ base::scoped_nsobject<MTLRenderPipelineDescriptor> desc(
+ [[MTLRenderPipelineDescriptor alloc] init]);
+ [desc setVertexFunction:vertex_function];
+ [desc setFragmentFunction:fragment_function];
+ [[desc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA16Float];
+ render_pipeline_state.reset(
+ [device newRenderPipelineStateWithDescriptor:desc error:&error]);
+ if (error) {
+ NSLog(@"Failed to create render pipeline state: %@", error);
+ return render_pipeline_state;
+ }
+ }
+
+ return render_pipeline_state;
}
} // namespace
@@ -62,9 +205,12 @@ API_AVAILABLE(macos(10.15))
#endif
API_AVAILABLE(macos(10.15))
-@interface HDRCopierLayer : CAMetalLayer
+@interface HDRCopierLayer : CAMetalLayer {
+ base::scoped_nsprotocol<id<MTLRenderPipelineState>> _render_pipeline_state;
+}
- (id)init;
-- (void)setContents:(id)contents;
+- (void)setHDRContents:(IOSurfaceRef)buffer
+ withColorSpace:(gfx::ColorSpace)color_space;
@end
@implementation HDRCopierLayer
@@ -75,13 +221,15 @@ API_AVAILABLE(macos(10.15))
[self setDevice:device];
[self setOpaque:NO];
[self setPresentsWithTransaction:YES];
+ [self setPixelFormat:MTLPixelFormatRGBA16Float];
+ [self setColorspace:CGColorSpaceCreateWithName(
+ kCGColorSpaceExtendedLinearSRGB)];
}
return self;
}
-- (void)setContents:(id)contents {
- IOSurfaceRef buffer = reinterpret_cast<IOSurfaceRef>(contents);
-
+- (void)setHDRContents:(IOSurfaceRef)buffer
+ withColorSpace:(gfx::ColorSpace)color_space {
// Retrieve information about the IOSurface.
size_t width = IOSurfaceGetWidth(buffer);
size_t height = IOSurfaceGetHeight(buffer);
@@ -90,11 +238,6 @@ API_AVAILABLE(macos(10.15))
DLOG(ERROR) << "Unsupported IOSurface format.";
return;
}
- base::ScopedCFTypeRef<CGColorSpaceRef> cg_color_space(
- IOSurfaceCopyCGColorSpace(buffer));
- if (!cg_color_space) {
- DLOG(ERROR) << "Unsupported IOSurface color space.";
- }
// Migrate to the MTLDevice on which the CAMetalLayer is being composited, if
// known.
@@ -105,10 +248,14 @@ API_AVAILABLE(macos(10.15))
}
id<MTLDevice> device = [self device];
+ // When the device changes, rebuild the RenderPipelineState.
+ if (device != [_render_pipeline_state device])
+ _render_pipeline_state = CreateRenderPipelineState(device);
+ if (!_render_pipeline_state)
+ return;
+
// Update the layer's properties to match the IOSurface.
[self setDrawableSize:CGSizeMake(width, height)];
- [self setPixelFormat:mtl_format];
- [self setColorspace:cg_color_space];
// Create a texture to wrap the IOSurface.
base::scoped_nsprotocol<id<MTLTexture>> buffer_texture;
@@ -138,16 +285,64 @@ API_AVAILABLE(macos(10.15))
base::scoped_nsprotocol<id<MTLCommandQueue>> command_queue(
[device newCommandQueue]);
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
- id<MTLBlitCommandEncoder> encoder = [command_buffer blitCommandEncoder];
- [encoder copyFromTexture:buffer_texture
- sourceSlice:0
- sourceLevel:0
- sourceOrigin:MTLOriginMake(0, 0, 0)
- sourceSize:MTLSizeMake(width, height, 1)
- toTexture:drawable_texture
- destinationSlice:0
- destinationLevel:0
- destinationOrigin:MTLOriginMake(0, 0, 0)];
+ id<MTLRenderCommandEncoder> encoder = nil;
+ {
+ MTLRenderPassDescriptor* desc =
+ [MTLRenderPassDescriptor renderPassDescriptor];
+ desc.colorAttachments[0].texture = drawable_texture;
+ desc.colorAttachments[0].loadAction = MTLLoadActionClear;
+ desc.colorAttachments[0].storeAction = MTLStoreActionStore;
+ desc.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
+ encoder = [command_buffer renderCommandEncoderWithDescriptor:desc];
+
+ MTLViewport viewport;
+ viewport.originX = 0;
+ viewport.originY = 0;
+ viewport.width = width;
+ viewport.height = height;
+ viewport.znear = -1.0;
+ viewport.zfar = 1.0;
+ [encoder setViewport:viewport];
+ [encoder setRenderPipelineState:_render_pipeline_state];
+ [encoder setFragmentTexture:buffer_texture atIndex:0];
+ }
+ {
+ simd::float2 positions[6] = {
+ simd::make_float2(0, 0), simd::make_float2(0, 1),
+ simd::make_float2(1, 1), simd::make_float2(1, 1),
+ simd::make_float2(1, 0), simd::make_float2(0, 0),
+ };
+
+ // The value of |transfer_function| corresponds to the value as used in
+ // the above shader source.
+ uint32_t transfer_function_index = GetTransferFunctionIndex(color_space);
+ DCHECK(transfer_function_index);
+
+ // Matrix is the primary transform matrix from |color_space| to sRGB.
+ simd::float3x3 matrix;
+ {
+ skcms_Matrix3x3 src_to_xyz;
+ skcms_Matrix3x3 srgb_to_xyz;
+ skcms_Matrix3x3 xyz_to_srgb;
+ color_space.GetPrimaryMatrix(&src_to_xyz);
+ gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&srgb_to_xyz);
+ skcms_Matrix3x3_invert(&srgb_to_xyz, &xyz_to_srgb);
+ skcms_Matrix3x3 m = skcms_Matrix3x3_concat(&xyz_to_srgb, &src_to_xyz);
+ matrix = simd::float3x3(
+ simd::make_float3(m.vals[0][0], m.vals[1][0], m.vals[2][0]),
+ simd::make_float3(m.vals[0][1], m.vals[1][1], m.vals[2][1]),
+ simd::make_float3(m.vals[0][2], m.vals[1][2], m.vals[2][2]));
+ }
+
+ [encoder setFragmentBytes:&transfer_function_index
+ length:sizeof(transfer_function_index)
+ atIndex:1];
+ [encoder setVertexBytes:positions length:sizeof(positions) atIndex:0];
+ [encoder setFragmentBytes:&matrix length:sizeof(matrix) atIndex:0];
+ [encoder drawPrimitives:MTLPrimitiveTypeTriangle
+ vertexStart:0
+ vertexCount:6];
+ }
[encoder endEncoding];
[command_buffer commit];
[command_buffer waitUntilScheduled];
@@ -163,8 +358,29 @@ CALayer* CreateHDRCopierLayer() {
// (HDR content will be clipped, but that would have happened anyway).
if (@available(macos 10.15, *))
return [[HDRCopierLayer alloc] init];
- else
- return [[CALayer alloc] init];
+ NOTREACHED();
+ 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 GetTransferFunctionIndex(color_space) &&
+ IOSurfaceGetMTLPixelFormat(buffer) != MTLPixelFormatInvalid;
+ }
+ return false;
}
} // namespace metal