From 99677208ff3b216fdfec551fbe548da5520cd6fb Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 29 Oct 2020 10:46:47 +0100 Subject: BASELINE: Update Chromium to 86.0.4240.124 Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen --- chromium/components/metal_util/BUILD.gn | 2 + chromium/components/metal_util/DEPS | 1 + chromium/components/metal_util/OWNERS | 2 +- chromium/components/metal_util/hdr_copier_layer.h | 22 +- chromium/components/metal_util/hdr_copier_layer.mm | 298 ++++++++++++++++++--- 5 files changed, 277 insertions(+), 48 deletions(-) (limited to 'chromium/components/metal_util') 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 + +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 \n" + "#include \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 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 color_space_value( - IOSurfaceCopyValue(buffer, CFSTR("IOSurfaceColorSpace"))); - if (!color_space_value) - return nullptr; - CFStringRef color_space_string = - base::mac::CFCast(color_space_value); - if (!color_space_string) - return nullptr; - base::ScopedCFTypeRef color_space( - CGColorSpaceCreateWithName(color_space_string)); - if (!color_space) - return nullptr; - return color_space.release(); +base::scoped_nsprotocol> CreateRenderPipelineState( + id device) API_AVAILABLE(macos(10.13)) { + base::scoped_nsprotocol> render_pipeline_state; + + base::scoped_nsprotocol> library; + { + NSError* error = nil; + base::scoped_nsobject source([[NSString alloc] + initWithCString:tonemapping_shader_source + encoding:NSASCIIStringEncoding]); + base::scoped_nsobject 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> vertex_function( + [library newFunctionWithName:@"vertexShader"]); + base::scoped_nsprotocol> fragment_function( + [library newFunctionWithName:@"fragmentShader"]); + NSError* error = nil; + base::scoped_nsobject 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> _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(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 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 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> buffer_texture; @@ -138,16 +285,64 @@ API_AVAILABLE(macos(10.15)) base::scoped_nsprotocol> command_queue( [device newCommandQueue]); id command_buffer = [command_queue commandBuffer]; - id 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 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(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 -- cgit v1.2.1