Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49b6ab45 authored by Michael Ludwig's avatar Michael Ludwig Committed by Android (Google) Code Review
Browse files

Merge "Update MouriMap to use SkShader::makeWithWorkingColorSpace()" into main

parents f65da232 ba8f28d7
Loading
Loading
Loading
Loading
+37 −15
Original line number Diff line number Diff line
@@ -384,6 +384,9 @@ PaintOptions ImageHWOnlySRGBSrcover() {
    return paintOptions;
}

// TODO(b/426601394): Update this to take an SkColorInfo for the input image.
// The other MouriMap* precompile paint options should use a linear SkColorInfo
// derived from this same input image.
skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16(RuntimeEffectManager& effectManager) {
    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
@@ -403,7 +406,7 @@ skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16(RuntimeEffectManage
}

skgpu::graphite::PaintOptions MouriMapChunk8x8Effect(RuntimeEffectManager& effectManager) {
    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    SkColorInfo ci { kRGBA_F16_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear() };
    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                           { &ci, 1 },
                                                           {});
@@ -420,7 +423,7 @@ skgpu::graphite::PaintOptions MouriMapChunk8x8Effect(RuntimeEffectManager& effec
}

skgpu::graphite::PaintOptions MouriMapBlur(RuntimeEffectManager& effectManager) {
    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    SkColorInfo ci { kRGBA_F16_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear() };
    sk_sp<PrecompileShader> img = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                           { &ci, 1 },
                                                           {});
@@ -438,20 +441,27 @@ skgpu::graphite::PaintOptions MouriMapBlur(RuntimeEffectManager& effectManager)

skgpu::graphite::PaintOptions MouriMapToneMap(RuntimeEffectManager& effectManager) {
    SkColorInfo ci { kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr };
    sk_sp<PrecompileShader> img1 = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
    sk_sp<PrecompileShader> input = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                            { &ci, 1 },
                                                            {});
    sk_sp<PrecompileShader> img2 = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                            { &ci, 1 },

    SkColorInfo luxCI { kRGBA_F16_SkColorType,
                        kPremul_SkAlphaType,
                        SkColorSpace::MakeSRGBLinear() };
    sk_sp<PrecompileShader> lux = PrecompileShaders::Image(ImageShaderFlags::kExcludeCubic,
                                                            { &luxCI, 1 },
                                                            {});

    sk_sp<PrecompileShader> toneMap = PrecompileRuntimeEffects::
            MakePrecompileShader(effectManager.getKnownRuntimeEffect(
                                         RuntimeEffectManager::KnownId::kMouriMap_TonemapEffect),
                                 {{std::move(img1)}, {std::move(img2)}});
                                 {{std::move(input)}, {std::move(lux)}});

    sk_sp<PrecompileShader> inLinear =
            toneMap->makeWithWorkingColorSpace(luxCI.refColorSpace());

    PaintOptions paintOptions;
    paintOptions.setShaders({ std::move(toneMap) });
    paintOptions.setShaders({ std::move(inLinear) });
    paintOptions.setBlendModes({ SkBlendMode::kSrc });
    return paintOptions;
}
@@ -571,7 +581,8 @@ skgpu::graphite::PaintOptions MouriMapCrosstalkAndChunk16x16YCbCr247(RuntimeEffe
            247,
            VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020,
            VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
            VK_CHROMA_LOCATION_COSITED_EVEN);
            VK_CHROMA_LOCATION_COSITED_EVEN,
            /*pqCS=*/true);

    sk_sp<PrecompileShader> crosstalk = PrecompileRuntimeEffects::MakePrecompileShader(
            effectManager.getKnownRuntimeEffect(RuntimeEffectManager::KnownId::kMouriMap_CrossTalkAndChunk16x16Effect),
@@ -723,6 +734,14 @@ const skgpu::graphite::RenderPassProperties kRGBA16F_1_D_SRGB {
    /* fRequiresMSAA= */ false
};

// The same as kRGBA16F_1_D but w/ a linear SRGB colorSpace
const skgpu::graphite::RenderPassProperties kRGBA16F_1_D_Linear {
    skgpu::graphite::DepthStencilFlags::kDepth,
    kRGBA_F16_SkColorType,
    SkColorSpace::MakeSRGBLinear(),
    /* fRequiresMSAA= */ false
};

const RenderPassProperties kRGBA_1D_4DS[2] = { kRGBA_1_D, kRGBA_4_DS };
const RenderPassProperties kRGBA_1D_4DS_SRGB[2] = { kRGBA_1_D_SRGB, kRGBA_4_DS_SRGB };

@@ -856,10 +875,13 @@ void GraphitePipelineManager::PrecompilePipelines(
/* 21 */ { ImagePremulHWOnlySrc(),             DrawTypeFlags::kPerEdgeAAQuad,   kRGBA_1_D },
/* 22 */ { ImagePremulHWOnlySrc(),             DrawTypeFlags::kNonAAFillRect,   kRGBA_4_DS },

/* 23 */ { MouriMapBlur(effectManager),                     DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D },
// TODO(b/426601394): Group these paint option settings into a function that accepts an input
// image color space so that the intermediate linear color spaces adapt correctly.
/* 23 */ { MouriMapBlur(effectManager),                     DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D_Linear },
/* 24 */ { MouriMapToneMap(effectManager),                  DrawTypeFlags::kNonAAFillRect,   kRGBA_1_D_SRGB },
/* 25 */ { MouriMapCrosstalkAndChunk16x16(effectManager),   DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D_SRGB },
/* 26 */ { MouriMapChunk8x8Effect(effectManager),           DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D },
/* 25 */ { MouriMapCrosstalkAndChunk16x16(effectManager),   DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D_Linear },
/* 26 */ { MouriMapChunk8x8Effect(effectManager),           DrawTypeFlags::kNonAAFillRect,   kRGBA16F_1_D_Linear },

/* 27 */ { KawaseBlurLowSrcSrcOver(effectManager),          DrawTypeFlags::kNonAAFillRect,   kRGBA_1_D },
/* 28 */ { KawaseBlurHighSrc(effectManager),                DrawTypeFlags::kNonAAFillRect,   kRGBA_1_D },
/* 29 */ { BlurFilterMix(effectManager),                    kRRectAndNonAARect,              kRGBA_1_D },
+45 −10
Original line number Diff line number Diff line
@@ -25,6 +25,15 @@ namespace android {
namespace renderengine {
namespace skia {
namespace {

// NOTE: These shaders are intended to operate on linear color values, but to
// avoid mapping to/from linear Srgb using the SkSL intrinsics, color space
// management is coordinated with the SkColorSpace of the output surfaces and
// with `SkShader::withWorkingColorSpace`.

// This shader must output to a surface with a linear color space, and relies on
// Skia's automatic colorspace conversion to map from the input `bitmap`'s
// color space to said linear color space.
const SkString kCrosstalkAndChunk16x16String(R"(
    uniform shader bitmap;
    uniform float inputMultiplier;
@@ -32,7 +41,7 @@ const SkString kCrosstalkAndChunk16x16String(R"(
        float maximum = 0.0;
        for (int y = 0; y < 16; y++) {
            for (int x = 0; x < 16; x++) {
                float3 linear = toLinearSrgb(bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb) * inputMultiplier;
                float3 linear = bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb * inputMultiplier;
                float maxRGB = max(linear.r, max(linear.g, linear.b));
                maximum = max(maximum, log2(max(maxRGB, 1.0)));
            }
@@ -40,6 +49,8 @@ const SkString kCrosstalkAndChunk16x16String(R"(
        return float4(float3(maximum), 1.0);
    }
)");
// This shader assumes `bitmap` is already in a linear color space and does not
// perform any color space conversion.
const SkString kChunk8x8String(R"(
    uniform shader bitmap;
    vec4 main(vec2 xy) {
@@ -52,6 +63,8 @@ const SkString kChunk8x8String(R"(
        return float4(float3(maximum), 1.0);
    }
)");
// This shader assumes `bitmap` is already in a linear color space and does not
// perform any color space conversion.
const SkString kBlurString(R"(
    uniform shader bitmap;
    vec4 main(vec2 xy) {
@@ -70,6 +83,11 @@ const SkString kBlurString(R"(
        return float4(float3(exp2(result)), 1.0);
    }
)");
// This shader assumes `image` is in the original color space and `lux` is in a
// linear color space. The shader must be wrapped with `SkShader::makeWithWorkingColorSpace`
// to automatically convert `image` into the linear color space (`lux`'s conversion
// is a no-op). `makeWithWorkingColorSpace` will also automatically convert back to
// the output color space, avoiding the need to call to/fromLinearSrgb per pixel.
const SkString kTonemapString(R"(
    uniform shader image;
    uniform shader lux;
@@ -79,17 +97,17 @@ const SkString kTonemapString(R"(
    vec4 main(vec2 xy) {
        float localMax = lux.eval(xy * scaleFactor).r;
        float4 rgba = image.eval(xy);
        float3 linear = toLinearSrgb(rgba.rgb) * inputMultiplier;
        float3 linear = rgba.rgb * inputMultiplier;

        if (localMax <= targetHdrSdrRatio) {
            return float4(fromLinearSrgb(linear), rgba.a);
            return float4(linear, rgba.a);
        }

        float maxRGB = max(linear.r, max(linear.g, linear.b));
        localMax = max(localMax, maxRGB);
        float gain = (1 + maxRGB * (targetHdrSdrRatio / (localMax * localMax)))
                / (1 + maxRGB / targetHdrSdrRatio);
        return float4(fromLinearSrgb(linear * gain), rgba.a);
        return float4(linear * gain, rgba.a);
    }
)");

@@ -146,18 +164,25 @@ sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> inpu
    // not need to be so precise. So, it's possible that we could use A8 or R8 instead. If we want
    // to be really conservative we can try to use R16 or even RGBA1010102 to fake an R10 surface,
    // which would cut write bandwidth significantly.
    // TODO(b/426601394): Linear sRGB is used currently to preserve behavior of the original
    // implementation calling to/fromLinearSrgb. In follow up work, it should be adjusted to be
    // image->imageInfo().colorSpace()->makeLinearGamma().
    static constexpr auto kFirstDownscaleAmount = 16;
    sk_sp<SkSurface> firstDownsampledSurface = context->createRenderTarget(
            image->imageInfo()
                    .makeWH(std::max(1, image->width() / kFirstDownscaleAmount),
                            std::max(1, image->height() / kFirstDownscaleAmount))
                    .makeColorSpace(SkColorSpace::MakeSRGBLinear())
                    .makeColorType(kRGBA_F16_SkColorType));
    LOG_ALWAYS_FATAL_IF(!firstDownsampledSurface, "%s: Failed to create surface!", __func__);
    auto firstDownsampledImage =
            makeImage(firstDownsampledSurface.get(), crosstalkAndChunk16x16Builder);

    // Since `secondDownsampledSurface` has the same color space as `firstDownsampledImage`, this
    // is equivalent to using makeRawShader(), but preserves the color space on the objects.
    SkRuntimeShaderBuilder chunk8x8Builder(mChunk8x8);
    chunk8x8Builder.child("bitmap") =
            firstDownsampledImage->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp,
            firstDownsampledImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                              SkSamplingOptions());
    static constexpr auto kSecondDownscaleAmount = 8;
    sk_sp<SkSurface> secondDownsampledSurface = context->createRenderTarget(
@@ -168,9 +193,11 @@ sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> inpu
    return makeImage(secondDownsampledSurface.get(), chunk8x8Builder);
}
sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const {
    // Since the `blurSurface` has the same color space as `input`, this will perform no color
    // space conversion (and it is assumed that `input` is already in a linear color space).
    SkRuntimeShaderBuilder blurBuilder(mBlur);
    blurBuilder.child("bitmap") =
            input->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions());
            input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions());
    sk_sp<SkSurface> blurSurface = context->createRenderTarget(input->imageInfo());
    LOG_ALWAYS_FATAL_IF(!blurSurface, "%s: Failed to create surface!", __func__);
    return makeImage(blurSurface.get(), blurBuilder);
@@ -178,15 +205,23 @@ sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const {
sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float inputMultiplier,
                                  float targetHdrSdrRatio) const {
    static constexpr float kScaleFactor = 1.0f / 128.0f;
    // The tonemap shader will work in `localLux`'s color space, so that child shader will not
    // actually perform any color space conversion. Skia will automatically convert `input`
    // into this same linear color space.
    SkRuntimeShaderBuilder tonemapBuilder(mTonemap);
    tonemapBuilder.child("image") = input;
    tonemapBuilder.child("lux") =
            localLux->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp,
            localLux->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone));
    tonemapBuilder.uniform("scaleFactor") = kScaleFactor;
    tonemapBuilder.uniform("inputMultiplier") = inputMultiplier;
    tonemapBuilder.uniform("targetHdrSdrRatio") = targetHdrSdrRatio;
    return tonemapBuilder.makeShader();

    sk_sp<SkShader> tonemapShader = tonemapBuilder.makeShader();
    // Now wrap the shader in a `makeWithWorkingColorSpace` call with lux's color space so `input`
    // is automatically converted at the start, and the output is automatically converted from
    // lux's space to the final destination color space.
    return tonemapShader->makeWithWorkingColorSpace(localLux->imageInfo().refColorSpace());
}
} // namespace skia
} // namespace renderengine