Loading services/surfaceflinger/RenderEngine/ProgramCache.cpp +78 −152 Original line number Diff line number Diff line Loading @@ -233,73 +233,31 @@ void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { } // Generate OOTF that modifies the relative scence light to relative display light. void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { // When HDR and non-HDR contents are mixed, or different types of HDR contents are // mixed, we will do a transcoding process to transcode the input content to output // content. Currently, the following conversions handled, they are: // * SDR -> HLG // * SDR -> PQ // * HLG -> PQ // Convert relative light to absolute light. switch (needs.getInputTF()) { case Key::INPUT_TF_ST2084: void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { return color * 10000.0; } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { // The formula is: // alpha * pow(Y, gamma - 1.0) * color + beta; // where alpha is 1000.0, gamma is 1.2, beta is 0.0. return color * 1000.0 * pow(color.y, 0.2); 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; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { return color * displayMaxLuminance; } )__SHADER__"; break; } // Tone map absolute light to display luminance range. // Generate OOTF that modifies the relative display light. switch(needs.getInputTF()) { case Key::INPUT_TF_ST2084: case Key::INPUT_TF_HLG: switch (needs.getOutputTF()) { case Key::OUTPUT_TF_HLG: // Right now when mixed PQ and HLG contents are presented, // HLG content will always be converted to PQ. However, for // completeness, we simply clamp the value to [0.0, 1000.0]. fs << R"__SHADER__( highp vec3 ToneMap(color) { return clamp(color, 0.0, 1000.0); } )__SHADER__"; break; case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 ToneMap(color) { return color; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ToneMap(color) { highp vec3 OOTF(const highp vec3 color) { const float maxLumi = 10000.0; const float maxMasteringLumi = 1000.0; const float maxContentLumi = 1000.0; const float maxInLumi = min(maxMasteringLumi, maxContentLumi); float maxOutLumi = displayMaxLuminance; float nits = color.y; // Calculate Y value in XYZ color space. float colorY = CalculateY(color); // convert to nits first float nits = colorY * maxLumi; // clamp to max input luminance nits = clamp(nits, 0.0, maxInLumi); Loading @@ -317,12 +275,12 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { float y2 = y1 + (maxOutLumi - y1) * 0.75; // horizontal distances between the last three control points const float h12 = x2 - x1; const float h23 = maxInLumi - x2; float h12 = x2 - x1; float h23 = maxInLumi - x2; // tangents at the last three control points const float m1 = (y2 - y1) / h12; const float m3 = (maxOutLumi - y2) / h23; const float m2 = (m1 + m3) / 2.0; float m1 = (y2 - y1) / h12; float m3 = (maxOutLumi - y2) / h23; float m2 = (m1 + m3) / 2.0; if (nits < x0) { // scale [0.0, x0] to [0.0, y0] linearly Loading @@ -330,7 +288,7 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { nits *= slope; } else if (nits < x1) { // scale [x0, x1] to [y0, y1] linearly const float slope = (y1 - y0) / (x1 - x0); float slope = (y1 - y0) / (x1 - x0); nits = y0 + (nits - x0) * slope; } else if (nits < x2) { // scale [x1, x2] to [y1, y2] using Hermite interp Loading @@ -345,64 +303,32 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { } } return color * (nits / max(1e-6, color.y)); // convert back to [0.0, 1.0] float targetY = nits / maxOutLumi; return color * (targetY / max(1e-6, colorY)); } )__SHADER__"; break; } break; default: // TODO(73825729) We need to revert the tone mapping in // hardware composer properly. fs << R"__SHADER__( highp vec3 ToneMap(color) { return color; } )__SHADER__"; break; } // convert absolute light to relative light. switch (needs.getOutputTF()) { case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 NormalizeLuminance(color) { return color / 10000.0; } )__SHADER__"; break; case Key::OUTPUT_TF_HLG: case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 NormalizeLuminance(color) { return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); 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 NormalizeLuminance(color) { return color / displayMaxLuminance; } )__SHADER__"; break; } if (needs.getInputTF() == needs.getOutputTF() || (needs.getInputTF() == Key::INPUT_TF_LINEAR && needs.getOutputTF() == Key::OUTPUT_TF_SRGB) || (needs.getInputTF() == Key::INPUT_TF_SRGB && needs.getOutputTF() == Key::OUTPUT_TF_LINEAR)) { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return color; } )__SHADER__"; } else { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return NormalizeLuminance(ToneMap(ScaleLuminance(color))); } )__SHADER__"; break; } } Loading Loading
services/surfaceflinger/RenderEngine/ProgramCache.cpp +78 −152 Original line number Diff line number Diff line Loading @@ -233,73 +233,31 @@ void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { } // Generate OOTF that modifies the relative scence light to relative display light. void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { // When HDR and non-HDR contents are mixed, or different types of HDR contents are // mixed, we will do a transcoding process to transcode the input content to output // content. Currently, the following conversions handled, they are: // * SDR -> HLG // * SDR -> PQ // * HLG -> PQ // Convert relative light to absolute light. switch (needs.getInputTF()) { case Key::INPUT_TF_ST2084: void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { return color * 10000.0; } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { // The formula is: // alpha * pow(Y, gamma - 1.0) * color + beta; // where alpha is 1000.0, gamma is 1.2, beta is 0.0. return color * 1000.0 * pow(color.y, 0.2); 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; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ScaleLuminance(color) { return color * displayMaxLuminance; } )__SHADER__"; break; } // Tone map absolute light to display luminance range. // Generate OOTF that modifies the relative display light. switch(needs.getInputTF()) { case Key::INPUT_TF_ST2084: case Key::INPUT_TF_HLG: switch (needs.getOutputTF()) { case Key::OUTPUT_TF_HLG: // Right now when mixed PQ and HLG contents are presented, // HLG content will always be converted to PQ. However, for // completeness, we simply clamp the value to [0.0, 1000.0]. fs << R"__SHADER__( highp vec3 ToneMap(color) { return clamp(color, 0.0, 1000.0); } )__SHADER__"; break; case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 ToneMap(color) { return color; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ToneMap(color) { highp vec3 OOTF(const highp vec3 color) { const float maxLumi = 10000.0; const float maxMasteringLumi = 1000.0; const float maxContentLumi = 1000.0; const float maxInLumi = min(maxMasteringLumi, maxContentLumi); float maxOutLumi = displayMaxLuminance; float nits = color.y; // Calculate Y value in XYZ color space. float colorY = CalculateY(color); // convert to nits first float nits = colorY * maxLumi; // clamp to max input luminance nits = clamp(nits, 0.0, maxInLumi); Loading @@ -317,12 +275,12 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { float y2 = y1 + (maxOutLumi - y1) * 0.75; // horizontal distances between the last three control points const float h12 = x2 - x1; const float h23 = maxInLumi - x2; float h12 = x2 - x1; float h23 = maxInLumi - x2; // tangents at the last three control points const float m1 = (y2 - y1) / h12; const float m3 = (maxOutLumi - y2) / h23; const float m2 = (m1 + m3) / 2.0; float m1 = (y2 - y1) / h12; float m3 = (maxOutLumi - y2) / h23; float m2 = (m1 + m3) / 2.0; if (nits < x0) { // scale [0.0, x0] to [0.0, y0] linearly Loading @@ -330,7 +288,7 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { nits *= slope; } else if (nits < x1) { // scale [x0, x1] to [y0, y1] linearly const float slope = (y1 - y0) / (x1 - x0); float slope = (y1 - y0) / (x1 - x0); nits = y0 + (nits - x0) * slope; } else if (nits < x2) { // scale [x1, x2] to [y1, y2] using Hermite interp Loading @@ -345,64 +303,32 @@ void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { } } return color * (nits / max(1e-6, color.y)); // convert back to [0.0, 1.0] float targetY = nits / maxOutLumi; return color * (targetY / max(1e-6, colorY)); } )__SHADER__"; break; } break; default: // TODO(73825729) We need to revert the tone mapping in // hardware composer properly. fs << R"__SHADER__( highp vec3 ToneMap(color) { return color; } )__SHADER__"; break; } // convert absolute light to relative light. switch (needs.getOutputTF()) { case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 NormalizeLuminance(color) { return color / 10000.0; } )__SHADER__"; break; case Key::OUTPUT_TF_HLG: case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 NormalizeLuminance(color) { return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); 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 NormalizeLuminance(color) { return color / displayMaxLuminance; } )__SHADER__"; break; } if (needs.getInputTF() == needs.getOutputTF() || (needs.getInputTF() == Key::INPUT_TF_LINEAR && needs.getOutputTF() == Key::OUTPUT_TF_SRGB) || (needs.getInputTF() == Key::INPUT_TF_SRGB && needs.getOutputTF() == Key::OUTPUT_TF_LINEAR)) { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return color; } )__SHADER__"; } else { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return NormalizeLuminance(ToneMap(ScaleLuminance(color))); } )__SHADER__"; break; } } Loading