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

Commit 2cb384b1 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "Convert bitmaps to sRGB/scRGB when they have a color profile"...

Merge "Merge "Convert bitmaps to sRGB/scRGB when they have a color profile" into oc-dev am: 33813bd4 am: 6869c551"
parents ca1fc880 427bb80e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ hwui_src_files := \
    service/GraphicsStatsService.cpp \
    thread/TaskManager.cpp \
    utils/Blur.cpp \
    utils/Color.cpp \
    utils/GLUtils.cpp \
    utils/LinearAllocator.cpp \
    utils/StringUtils.cpp \
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ public:
    }

    void setSize(uint32_t width, uint32_t height) override {
        texture.updateSize(width, height, texture.internalFormat(), texture.format(),
        texture.updateLayout(width, height, texture.internalFormat(), texture.format(),
                texture.target());
    }

+5 −1
Original line number Diff line number Diff line
@@ -605,7 +605,11 @@ void GlopBuilder::build() {
        } else {
            mDescription.hasExternalTexture = true;
        }
        mDescription.hasLinearTexture = mOutGlop->fill.texture.texture->isLinear();
        Texture* texture = mOutGlop->fill.texture.texture;
        mDescription.hasLinearTexture = texture->isLinear();
        mDescription.hasColorSpaceConversion = texture->hasColorSpaceConversion();
        mDescription.transferFunction = texture->getTransferFunctionType();
        mDescription.hasTranslucentConversion = texture->blend;
    }

    mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color;
+35 −18
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "FloatColor.h"
#include "Matrix.h"
#include "Properties.h"
#include "utils/Color.h"

namespace android {
namespace uirenderer {
@@ -56,11 +57,11 @@ namespace uirenderer {
#define PROGRAM_KEY_BITMAP_NPOT         0x80
#define PROGRAM_KEY_BITMAP_EXTERNAL    0x100

#define PROGRAM_KEY_SWAP_SRC_DST      0x2000

#define PROGRAM_KEY_BITMAP_WRAPS_MASK  0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800

#define PROGRAM_KEY_SWAP_SRC_DST_SHIFT 13

// Encode the xfermodes on 6 bits
#define PROGRAM_MAX_XFERMODE 0x1f
#define PROGRAM_XFERMODE_SHADER_SHIFT 26
@@ -89,6 +90,10 @@ namespace uirenderer {
#define PROGRAM_HAS_GAMMA_CORRECTION 44
#define PROGRAM_HAS_LINEAR_TEXTURE 45

#define PROGRAM_HAS_COLOR_SPACE_CONVERSION 46
#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
#define PROGRAM_HAS_TRANSLUCENT_CONVERSION 49

///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -105,13 +110,13 @@ typedef uint64_t programid;
 * A ProgramDescription must be used in conjunction with a ProgramCache.
 */
struct ProgramDescription {
    enum class ColorFilterMode {
    enum class ColorFilterMode : int8_t {
        None = 0,
        Matrix,
        Blend
    };

    enum Gradient {
    enum Gradient : int8_t {
        kGradientLinear = 0,
        kGradientCircular,
        kGradientSweep
@@ -168,6 +173,11 @@ struct ProgramDescription {
    // Set when sampling an image in linear space
    bool hasLinearTexture;

    bool hasColorSpaceConversion;
    TransferFunctionType transferFunction;
    // Indicates whether the bitmap to convert between color spaces is translucent
    bool hasTranslucentConversion;

    /**
     * Resets this description. All fields are reset back to the default
     * values they hold after building a new instance.
@@ -210,6 +220,10 @@ struct ProgramDescription {

        hasGammaCorrection = false;
        hasLinearTexture = false;

        hasColorSpaceConversion = false;
        transferFunction = TransferFunctionType::None;
        hasTranslucentConversion = false;
    }

    /**
@@ -269,18 +283,21 @@ struct ProgramDescription {
                break;
        }
        key |= ((int) framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
        if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
        if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
        if (hasVertexAlpha) key |= programid(0x1) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
        if (useShadowAlphaInterp) key |= programid(0x1) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT;
        if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
        if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
        if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
        if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
        if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
        if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
        if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
        if (hasLinearTexture) key |= programid(0x1) << PROGRAM_HAS_LINEAR_TEXTURE;
        key |= programid(swapSrcDst) << PROGRAM_KEY_SWAP_SRC_DST_SHIFT;
        key |= programid(modulate) << PROGRAM_MODULATE_SHIFT;
        key |= programid(hasVertexAlpha) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
        key |= programid(useShadowAlphaInterp) << PROGRAM_USE_SHADOW_ALPHA_INTERP_SHIFT;
        key |= programid(hasExternalTexture) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
        key |= programid(hasTextureTransform) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
        key |= programid(isSimpleGradient) << PROGRAM_IS_SIMPLE_GRADIENT;
        key |= programid(hasColors) << PROGRAM_HAS_COLORS;
        key |= programid(hasDebugHighlight) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
        key |= programid(hasRoundRectClip) << PROGRAM_HAS_ROUND_RECT_CLIP;
        key |= programid(hasGammaCorrection) << PROGRAM_HAS_GAMMA_CORRECTION;
        key |= programid(hasLinearTexture) << PROGRAM_HAS_LINEAR_TEXTURE;
        key |= programid(hasColorSpaceConversion) << PROGRAM_HAS_COLOR_SPACE_CONVERSION;
        key |= programid(transferFunction) << PROGRAM_TRANSFER_FUNCTION;
        key |= programid(hasTranslucentConversion) << PROGRAM_HAS_TRANSLUCENT_CONVERSION;
        return key;
    }

+118 −19
Original line number Diff line number Diff line
@@ -161,17 +161,61 @@ const char* gFS_Uniforms_HasRoundRectClip =
        "uniform vec4 roundRectInnerRectLTRB;\n"
        "uniform float roundRectRadius;\n";

const char* gFS_Uniforms_ColorSpaceConversion =
        // TODO: Should we use a 3D LUT to combine the matrix and transfer functions?
        // 32x32x32 fp16 LUTs (for scRGB output) are large and heavy to generate...
        "uniform mat3 colorSpaceMatrix;\n";

const char* gFS_Uniforms_TransferFunction[4] = {
        // In this order: g, a, b, c, d, e, f
        // See ColorSpace::TransferParameters
        // We'll use hardware sRGB conversion as much as possible
        "",
        "uniform float transferFunction[7];\n",
        "uniform float transferFunction[5];\n",
        "uniform float transferFunctionGamma;\n"
};

const char* gFS_OETF[2] = {
         "\nvec4 OETF(const vec4 linear) {\n"
         "    return linear;\n"
         "}\n",
        R"__SHADER__(
        vec4 OETF(const vec4 linear) {
            return linear;
        }
        )__SHADER__",
        // We expect linear data to be scRGB so we mirror the gamma function
         "\nvec4 OETF(const vec4 linear) {"
          "    return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);\n"
          "}\n",
        R"__SHADER__(
        vec4 OETF(const vec4 linear) {
            return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
        }
        )__SHADER__"
};

const char* gFS_ColorConvert[3] = {
        // Just OETF
        R"__SHADER__(
        vec4 colorConvert(const vec4 color) {
            return OETF(color);
        }
        )__SHADER__",
        // Full color conversion for opaque bitmaps
        R"__SHADER__(
        vec4 colorConvert(const vec4 color) {
            return OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
        }
        )__SHADER__",
        // Full color conversion for translucent bitmaps
        // Note: 0.5/256=0.0019
        R"__SHADER__(
        vec4 colorConvert(in vec4 color) {
            color.rgb /= color.a + 0.0019;
            color = OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
            color.rgb *= color.a + 0.0019;
            return color;
        }
        )__SHADER__",
};

const char* gFS_Transfer_Functions = R"__SHADER__(
const char* gFS_sRGB_TransferFunctions = R"__SHADER__(
        float OETF_sRGB(const float linear) {
            // IEC 61966-2-1:1999
            return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
@@ -187,12 +231,56 @@ const char* gFS_Transfer_Functions = R"__SHADER__(
        }
)__SHADER__";

const char* gFS_TransferFunction[4] = {
        // Conversion done by the texture unit (sRGB)
        R"__SHADER__(
        vec3 EOTF_Parametric(const vec3 x) {
            return x;
        }
        )__SHADER__",
        // Full transfer function
        // TODO: We should probably use a 1D LUT (256x1 with texelFetch() since input is 8 bit)
        // TODO: That would cause 3 dependent texture fetches. Is it worth it?
        R"__SHADER__(
        float EOTF_Parametric(float x) {
            return x <= transferFunction[4]
                  ? transferFunction[3] * x + transferFunction[6]
                  : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0])
                          + transferFunction[5];
        }

        vec3 EOTF_Parametric(const vec3 x) {
            return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
        }
        )__SHADER__",
        // Limited transfer function, e = f = 0.0
        R"__SHADER__(
        float EOTF_Parametric(float x) {
            return x <= transferFunction[4]
                  ? transferFunction[3] * x
                  : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0]);
        }

        vec3 EOTF_Parametric(const vec3 x) {
            return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
        }
        )__SHADER__",
        // Gamma transfer function, e = f = 0.0
        R"__SHADER__(
        vec3 EOTF_Parametric(const vec3 x) {
            return vec3(pow(x.r, transferFunctionGamma),
                        pow(x.g, transferFunctionGamma),
                        pow(x.b, transferFunctionGamma));
        }
        )__SHADER__"
};

// Dithering must be done in the quantization space
// When we are writing to an sRGB framebuffer, we must do the following:
//     EOTF(OETF(color) + dither)
// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0]
// TODO: Handle linear fp16 render targets
const char* gFS_Gradient_Functions = R"__SHADER__(
const char* gFS_GradientFunctions = R"__SHADER__(
        float triangleNoise(const highp vec2 n) {
            highp vec2 p = fract(n * vec2(5.3987, 5.4421));
            p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
@@ -200,7 +288,8 @@ const char* gFS_Gradient_Functions = R"__SHADER__(
            return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
        }
)__SHADER__";
const char* gFS_Gradient_Preamble[2] = {

const char* gFS_GradientPreamble[2] = {
        // Linear framebuffer
        R"__SHADER__(
        vec4 dither(const vec4 color) {
@@ -259,9 +348,9 @@ const char* gFS_Main_ApplyVertexAlphaShadowInterp =
        "    fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
const char* gFS_Main_FetchTexture[2] = {
        // Don't modulate
        "    fragColor = OETF(texture2D(baseSampler, outTexCoords));\n",
        "    fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n",
        // Modulate
        "    fragColor = color * texture2D(baseSampler, outTexCoords);\n"
        "    fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"
};
const char* gFS_Main_FetchA8Texture[4] = {
        // Don't modulate
@@ -290,9 +379,9 @@ const char* gFS_Main_FetchGradient[6] = {
        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
        "    vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n";
        "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
const char* gFS_Main_FetchBitmapNpot =
        "    vec4 bitmapColor = OETF(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
        "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
const char* gFS_Main_BlendShadersBG =
        "    fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShadersGB =
@@ -627,6 +716,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    }
    shader.append(gFS_Uniforms_ColorOp[static_cast<int>(description.colorOp)]);

    if (description.hasColorSpaceConversion) {
        shader.append(gFS_Uniforms_ColorSpaceConversion);
    }
    shader.append(gFS_Uniforms_TransferFunction[static_cast<int>(description.transferFunction)]);

    // Generate required functions
    if (description.hasGradient && description.hasBitmap) {
        generateBlend(shader, "blendShaders", description.shadersMode);
@@ -640,16 +734,21 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
    if (description.useShaderBasedWrap) {
        generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
    }
    if (description.hasGradient || description.hasLinearTexture) {
        shader.append(gFS_Transfer_Functions);
    if (description.hasGradient || description.hasLinearTexture
            || description.hasColorSpaceConversion) {
        shader.append(gFS_sRGB_TransferFunctions);
    }
    if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
            !description.hasAlpha8Texture)) {
        shader.append(gFS_OETF[description.hasLinearTexture && !mHasLinearBlending]);
        shader.append(gFS_TransferFunction[static_cast<int>(description.transferFunction)]);
        shader.append(gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion)
                && !mHasLinearBlending]);
        shader.append(gFS_ColorConvert[description.hasColorSpaceConversion
                ? 1 + description.hasTranslucentConversion : 0]);
    }
    if (description.hasGradient) {
        shader.append(gFS_Gradient_Functions);
        shader.append(gFS_Gradient_Preamble[mHasLinearBlending]);
        shader.append(gFS_GradientFunctions);
        shader.append(gFS_GradientPreamble[mHasLinearBlending]);
    }

    // Begin the shader
Loading