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

Commit 5a5e992e authored by Peiyong Lin's avatar Peiyong Lin Committed by Android (Google) Code Review
Browse files

Merge "[RenderEngine] Add hybrid Log-Gamma support." into pi-dev

parents f9fd1660 a3fb7d6b
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -73,8 +73,4 @@ void Description::setOutputTransferFunction(TransferFunction transferFunction) {
    mOutputTransferFunction = transferFunction;
}

void Description::enableToneMapping(bool enable) {
    mToneMappingEnabled = enable;
}

} /* namespace android */
+1 −5
Original line number Diff line number Diff line
@@ -51,12 +51,11 @@ public:
        LINEAR,
        SRGB,
        ST2084,
        HLG,  // Hybrid Log-Gamma for HDR.
    };
    void setInputTransferFunction(TransferFunction transferFunction);
    void setOutputTransferFunction(TransferFunction transferFunction);

    void enableToneMapping(bool enable);

private:
    friend class Program;
    friend class ProgramCache;
@@ -84,9 +83,6 @@ private:
    // transfer functions for the input/output
    TransferFunction mInputTransferFunction = TransferFunction::LINEAR;
    TransferFunction mOutputTransferFunction = TransferFunction::LINEAR;

    // tone-map the color
    bool mToneMappingEnabled = false;
};

} /* namespace android */
+6 −1
Original line number Diff line number Diff line
@@ -316,7 +316,12 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
                wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
                wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
                wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                wideColorState.enableToneMapping(true);
                break;
            case Dataspace::BT2020_HLG:
            case Dataspace::BT2020_ITU_HLG:
                wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
                wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
                wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                break;
            default:
                // treat all other dataspaces as sRGB
+138 −80
Original line number Diff line number Diff line
@@ -143,6 +143,9 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) {
            case Description::TransferFunction::ST2084:
                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084);
                break;
            case Description::TransferFunction::HLG:
                needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG);
                break;
        }

        switch (description.mOutputTransferFunction) {
@@ -156,10 +159,10 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) {
            case Description::TransferFunction::ST2084:
                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084);
                break;
            case Description::TransferFunction::HLG:
                needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG);
                break;
        }

        needs.set(Key::TONE_MAPPING_MASK,
                  description.mToneMappingEnabled ? Key::TONE_MAPPING_ON : Key::TONE_MAPPING_OFF);
    }

    return needs;
@@ -220,6 +223,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
    if (needs.hasColorMatrix()) {
        fs << "uniform mat4 colorMatrix;";

        // Generate EOTF that converts signal values to relative display light,
        // both normalized to [0, 1].
        switch (needs.getInputTF()) {
            case Key::INPUT_TF_LINEAR:
            default:
@@ -259,59 +264,38 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
                    }
                    )__SHADER__";
                break;
        }

        switch (needs.getOutputTF()) {
            case Key::OUTPUT_TF_LINEAR:
            default:
                fs << R"__SHADER__(
                    vec3 OETF(const vec3 linear) {
                        return linear;
                    }
                )__SHADER__";
                break;
            case Key::OUTPUT_TF_SRGB:
          case Key::INPUT_TF_HLG:
              fs << R"__SHADER__(
                    float OETF_sRGB(const float linear) {
                        return linear <= 0.0031308 ?
                                linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
                  highp float EOTF_channel(const highp float channel) {
                      const highp float a = 0.17883277;
                      const highp float b = 0.28466892;
                      const highp float c = 0.55991073;
                      return channel <= 0.5 ? channel * channel / 3.0 :
                              (exp((channel - c) / a) + b) / 12.0;
                  }

                    vec3 OETF_sRGB(const vec3 linear) {
                        return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
                    }

                    vec3 OETF(const vec3 linear) {
                        return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
                    }
                )__SHADER__";
                break;
            case Key::OUTPUT_TF_ST2084:
                fs << R"__SHADER__(
                    vec3 OETF(const vec3 linear) {
                        const float m1 = (2610.0 / 4096.0) / 4.0;
                        const float m2 = (2523.0 / 4096.0) * 128.0;
                        const float c1 = (3424.0 / 4096.0);
                        const float c2 = (2413.0 / 4096.0) * 32.0;
                        const float c3 = (2392.0 / 4096.0) * 32.0;

                        vec3 tmp = pow(linear, vec3(m1));
                        tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
                        return pow(tmp, vec3(m2));
                  vec3 EOTF(const highp vec3 color) {
                      return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
                              EOTF_channel(color.b));
                  }
                  )__SHADER__";
              break;
        }

        if (needs.hasToneMapping()) {
        fs << R"__SHADER__(
                float CalculateY(const vec3 color) {
            highp float CalculateY(const highp vec3 color) {
                // BT2020 standard uses the unadjusted KR = 0.2627,
                // KB = 0.0593 luminance interpretation for RGB conversion.
                return color.r * 0.262700 + color.g * 0.677998 +
                        color.b * 0.059302;
            }
                vec3 ToneMap(const vec3 color) {
        )__SHADER__";

        // Generate OOTF that modifies the relative display light.
        switch(needs.getInputTF()) {
            case Key::INPUT_TF_ST2084:
                fs << R"__SHADER__(
                    highp vec3 OOTF(const highp vec3 color) {
                        const float maxLumi = 10000.0;
                        const float maxMasteringLumi = 1000.0;
                        const float maxContentLumi = 1000.0;
@@ -373,13 +357,87 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
                        return color * (targetY / max(1e-6, colorY));
                    }
                )__SHADER__";
        } else {
                break;
            case Key::INPUT_TF_HLG:
                fs << R"__SHADER__(
                vec3 ToneMap(const vec3 color) {
                    highp vec3 OOTF(const highp vec3 color) {
                        const float maxOutLumi = 500.0;
                        const float gamma = 1.2 + 0.42 * log(maxOutLumi / 1000.0) / log(10.0);
                        // The formula is:
                        // alpha * pow(Y, gamma - 1.0) * color + beta;
                        // where alpha is 1.0, beta is 0.0 as recommended in
                        // Rec. ITU-R BT.2100-1 TABLE 5.
                        return pow(CalculateY(color), gamma - 1.0) * color;
                    }
                )__SHADER__";
                break;
            default:
                fs << R"__SHADER__(
                    highp vec3 OOTF(const highp vec3 color) {
                        return color;
                    }
                )__SHADER__";
        }

        // Generate OETF that converts relative display light to signal values,
        // both normalized to [0, 1]
        switch (needs.getOutputTF()) {
            case Key::OUTPUT_TF_LINEAR:
            default:
                fs << R"__SHADER__(
                    vec3 OETF(const vec3 linear) {
                        return linear;
                    }
                )__SHADER__";
                break;
            case Key::OUTPUT_TF_SRGB:
                fs << R"__SHADER__(
                    float OETF_sRGB(const float linear) {
                        return linear <= 0.0031308 ?
                                linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
                    }

                    vec3 OETF_sRGB(const vec3 linear) {
                        return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
                    }

                    vec3 OETF(const vec3 linear) {
                        return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
                    }
                )__SHADER__";
                break;
            case Key::OUTPUT_TF_ST2084:
                fs << R"__SHADER__(
                    vec3 OETF(const vec3 linear) {
                        const float m1 = (2610.0 / 4096.0) / 4.0;
                        const float m2 = (2523.0 / 4096.0) * 128.0;
                        const float c1 = (3424.0 / 4096.0);
                        const float c2 = (2413.0 / 4096.0) * 32.0;
                        const float c3 = (2392.0 / 4096.0) * 32.0;

                        vec3 tmp = pow(linear, vec3(m1));
                        tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
                        return pow(tmp, vec3(m2));
                    }
                )__SHADER__";
                break;
            case Key::OUTPUT_TF_HLG:
                fs << R"__SHADER__(
                    highp float OETF_channel(const highp float channel) {
                        const highp float a = 0.17883277;
                        const highp float b = 0.28466892;
                        const highp float c = 0.55991073;
                        return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
                                a * log(12.0 * channel - b) + c;
                    }

                    vec3 OETF(const highp vec3 color) {
                        return vec3(OETF_channel(color.r), OETF_channel(color.g),
                                OETF_channel(color.b));
                    }
                )__SHADER__";
                break;
        }
    }

    fs << "void main(void) {" << indent;
@@ -411,7 +469,7 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
            // avoid divide by 0 by adding 0.5/256 to the alpha channel
            fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
        }
        fs << "vec4 transformed = colorMatrix * vec4(ToneMap(EOTF(gl_FragColor.rgb)), 1);";
        fs << "vec4 transformed = colorMatrix * vec4(OOTF(EOTF(gl_FragColor.rgb)), 1);";
        // the transformation from a wider colorspace to a narrower one can
        // result in >1.0 or <0.0 pixel values
        fs << "transformed.rgb = clamp(transformed.rgb, 0.0, 1.0);";
+3 −7
Original line number Diff line number Diff line
@@ -81,19 +81,16 @@ public:
            INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
            INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
            INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
            INPUT_TF_HLG = 3 << INPUT_TF_SHIFT,

            OUTPUT_TF_SHIFT = 8,
            OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
            OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
            OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
            OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
            OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT,

            TONE_MAPPING_SHIFT = 10,
            TONE_MAPPING_MASK = 1 << TONE_MAPPING_SHIFT,
            TONE_MAPPING_OFF = 0 << TONE_MAPPING_SHIFT,
            TONE_MAPPING_ON = 1 << TONE_MAPPING_SHIFT,

            Y410_BT2020_SHIFT = 11,
            Y410_BT2020_SHIFT = 10,
            Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
            Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
            Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
@@ -115,7 +112,6 @@ public:
        inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; }
        inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
        inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
        inline bool hasToneMapping() const { return (mKey & TONE_MAPPING_MASK) == TONE_MAPPING_ON; }
        inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }

        // this is the definition of a friend function -- not a method of class Needs