Loading services/surfaceflinger/RenderEngine/Description.cpp +0 −4 Original line number Diff line number Diff line Loading @@ -73,8 +73,4 @@ void Description::setOutputTransferFunction(TransferFunction transferFunction) { mOutputTransferFunction = transferFunction; } void Description::enableToneMapping(bool enable) { mToneMappingEnabled = enable; } } /* namespace android */ services/surfaceflinger/RenderEngine/Description.h +1 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 */ Loading services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading services/surfaceflinger/RenderEngine/ProgramCache.cpp +138 −80 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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);"; Loading services/surfaceflinger/RenderEngine/ProgramCache.h +3 −7 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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 Loading Loading
services/surfaceflinger/RenderEngine/Description.cpp +0 −4 Original line number Diff line number Diff line Loading @@ -73,8 +73,4 @@ void Description::setOutputTransferFunction(TransferFunction transferFunction) { mOutputTransferFunction = transferFunction; } void Description::enableToneMapping(bool enable) { mToneMappingEnabled = enable; } } /* namespace android */
services/surfaceflinger/RenderEngine/Description.h +1 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 */ Loading
services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
services/surfaceflinger/RenderEngine/ProgramCache.cpp +138 −80 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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);"; Loading
services/surfaceflinger/RenderEngine/ProgramCache.h +3 −7 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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 Loading