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

Commit 1a4d0649 authored by Alec Mouri's avatar Alec Mouri
Browse files

Support linear color transforms in Skia-RenderEngine.

Per-layer color transforms are defined by the HWC spec to apply in linear
space immediately before OETF. Support that by passing an additional
matrix into LinearEffect.

Note that this probably is not the most efficient way to do this at
runtime; when tone mapping is not required and RGB primaries are the
same, we can remove an additional matrix computation, but the number of
shaders cached on-device is cut down this way.

Bug: 164223050
Test: Hack in a color transform and compare gles vs skiagl.
Change-Id: If01995a90a4381d811c39c68cff5983b04e2971d
parent c16a77dd
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -416,6 +416,11 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin
            sourceTransfer != destTransfer;
}

static bool needsLinearEffect(const mat4& colorTransform, ui::Dataspace sourceDataspace,
                              ui::Dataspace destinationDataspace) {
    return colorTransform != mat4() || needsToneMapping(sourceDataspace, destinationDataspace);
}

void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
    std::lock_guard<std::mutex> lock(mRenderingMutex);
    mTextureCache.erase(bufferId);
@@ -559,10 +564,12 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                                                   false));
                mTextureCache.insert({buffer->getId(), imageTextureRef});
            }

            sk_sp<SkImage> image =
                    imageTextureRef->getTexture()
                            ->makeImage(mUseColorManagement
                                                ? (needsToneMapping(layer->sourceDataspace,
                                                ? (needsLinearEffect(layer->colorTransform,
                                                                     layer->sourceDataspace,
                                                                     display.outputDataspace)
                                                           // If we need to map to linear space,
                                                           // then mark the source image with the
@@ -633,7 +640,8 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
            }

            if (mUseColorManagement &&
                needsToneMapping(layer->sourceDataspace, display.outputDataspace)) {
                needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
                                  display.outputDataspace)) {
                LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
                                                   .outputDataspace = display.outputDataspace,
                                                   .undoPremultipliedAlpha = !item.isOpaque &&
@@ -649,6 +657,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                }

                paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect,
                                                         layer->colorTransform,
                                                         display.maxLuminance,
                                                         layer->source.buffer.maxMasteringLuminance,
                                                         layer->source.buffer.maxContentLuminance));
+3 −3
Original line number Diff line number Diff line
@@ -447,8 +447,8 @@ sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) {

sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect,
                                         sk_sp<SkRuntimeEffect> runtimeEffect,
                                         float maxDisplayLuminance, float maxMasteringLuminance,
                                         float maxContentLuminance) {
                                         const mat4& colorTransform, float maxDisplayLuminance,
                                         float maxMasteringLuminance, float maxContentLuminance) {
    ATRACE_CALL();
    SkRuntimeShaderBuilder effectBuilder(runtimeEffect);

@@ -458,7 +458,7 @@ sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEff
    ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);

    effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
    effectBuilder.uniform("in_xyzToRgb") = mat4(outputColorSpace.getXYZtoRGB());
    effectBuilder.uniform("in_xyzToRgb") = colorTransform * mat4(outputColorSpace.getXYZtoRGB());
    effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
    effectBuilder.uniform("in_inputMaxLuminance") =
            std::min(maxMasteringLuminance, maxContentLuminance);
+8 −5
Original line number Diff line number Diff line
@@ -16,9 +16,10 @@

#pragma once

#include <math/mat4.h>

#include <optional>

#include "SkColorMatrix.h"
#include "SkRuntimeEffect.h"
#include "SkShader.h"
#include "ui/GraphicTypes.h"
@@ -84,8 +85,10 @@ struct LinearEffectHasher {
sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect);

// Generates a shader resulting from applying the a linear effect created from
// LinearEffectARgs::buildEffect to an inputShader. We also provide additional HDR metadata upon
// creating the shader:
// LinearEffectArgs::buildEffect to an inputShader.
// Optionally, a color transform may also be provided, which combines with the
// matrix transforming from linear XYZ to linear RGB immediately before OETF.
// We also provide additional HDR metadata upon creating the shader:
// * The max display luminance is the max luminance of the physical display in nits
// * The max mastering luminance is provided as the max luminance from the SMPTE 2086
// standard.
@@ -94,8 +97,8 @@ sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect);
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
                                         const LinearEffect& linearEffect,
                                         sk_sp<SkRuntimeEffect> runtimeEffect,
                                         float maxDisplayLuminance, float maxMasteringLuminance,
                                         float maxContentLuminance);
                                         const mat4& colorTransform, float maxDisplayLuminance,
                                         float maxMasteringLuminance, float maxContentLuminance);
} // namespace skia
} // namespace renderengine
} // namespace android