Loading libs/binder/IServiceManager.cpp +26 −10 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <binder/IPermissionController.h> #endif #include <binder/Parcel.h> #include <cutils/properties.h> #include <utils/String8.h> #include <utils/SystemClock.h> #include <utils/CallStack.h> Loading Loading @@ -142,20 +143,35 @@ public: virtual sp<IBinder> getService(const String16& name) const { unsigned n; for (n = 0; n < 5; n++){ if (n > 0) { if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) { sp<IBinder> svc = checkService(name); if (svc != NULL) return svc; const bool isVendorService = strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; const long timeout = uptimeMillis() + 5000; if (!gSystemBootCompleted) { char bootCompleted[PROPERTY_VALUE_MAX]; property_get("sys.boot_completed", bootCompleted, "0"); gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; } // retry interval in millisecond. const long sleepTime = gSystemBootCompleted ? 1000 : 100; int n = 0; while (uptimeMillis() < timeout) { n++; if (isVendorService) { ALOGI("Waiting for vendor service %s...", String8(name).string()); CallStack stack(LOG_TAG); } else { } else if (n%10 == 0) { ALOGI("Waiting for service %s...", String8(name).string()); } sleep(1); } usleep(1000*sleepTime); sp<IBinder> svc = checkService(name); if (svc != NULL) return svc; } ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); return NULL; } Loading libs/binder/Static.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -97,5 +97,6 @@ sp<IServiceManager> gDefaultServiceManager; #ifndef __ANDROID_VNDK__ sp<IPermissionController> gPermissionController; #endif bool gSystemBootCompleted = false; } // namespace android libs/binder/include/private/binder/Static.h +1 −0 Original line number Diff line number Diff line Loading @@ -41,5 +41,6 @@ extern sp<IServiceManager> gDefaultServiceManager; #ifndef __ANDROID_VNDK__ extern sp<IPermissionController> gPermissionController; #endif extern bool gSystemBootCompleted; } // namespace android opengl/libs/EGL/eglApi.cpp +19 −7 Original line number Diff line number Diff line Loading @@ -475,6 +475,12 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { return HAL_DATASPACE_UNKNOWN; } // Get the colorspace value that should be reported from queries. When the colorspace // is unknown (no attribute passed), default to reporting LINEAR. static EGLint getReportedColorSpace(EGLint colorspace) { return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace; } // Returns a list of color spaces understood by the vendor EGL driver. static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, android_pixel_format format) { Loading Loading @@ -569,7 +575,8 @@ static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, // supports wide color. const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR; *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN; if (window && !colorSpaceIsNarrow) { bool windowSupportsWideColor = true; // Ordinarily we'd put a call to native_window_get_wide_color_support Loading Loading @@ -718,7 +725,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, window, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading Loading @@ -757,7 +764,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx); new egl_surface_t(dp.get(), config, window, surface, getReportedColorSpace(colorSpace), cnx); return s; } Loading @@ -782,7 +790,7 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // now select a corresponding sRGB format if needed EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading @@ -794,7 +802,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, getReportedColorSpace(colorSpace), cnx); return s; } } Loading @@ -814,7 +824,7 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading @@ -826,7 +836,9 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, getReportedColorSpace(colorSpace), cnx); return s; } } Loading services/surfaceflinger/RenderEngine/ProgramCache.cpp +147 −81 Original line number Diff line number Diff line Loading @@ -232,32 +232,66 @@ 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 Key& needs) { void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) { // Convert relative light to absolute light. switch (needs.getInputTF()) { case Key::INPUT_TF_ST2084: fs << R"__SHADER__( 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; highp vec3 ScaleLuminance(highp vec3 color) { return color * 10000.0; } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 ScaleLuminance(highp vec3 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); } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ScaleLuminance(highp vec3 color) { return color * displayMaxLuminance; } )__SHADER__"; break; } // Generate OOTF that modifies the relative display light. // Tone map absolute light to display luminance range. 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 OOTF(const highp vec3 color) { const float maxLumi = 10000.0; highp vec3 ToneMap(highp vec3 color) { return clamp(color, 0.0, 1000.0); } )__SHADER__"; break; case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 ToneMap(highp vec3 color) { return color; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ToneMap(highp vec3 color) { const float maxMasteringLumi = 1000.0; const float maxContentLumi = 1000.0; const float maxInLumi = min(maxMasteringLumi, maxContentLumi); float maxOutLumi = displayMaxLuminance; // Calculate Y value in XYZ color space. float colorY = CalculateY(color); // convert to nits first float nits = colorY * maxLumi; float nits = color.y; // clamp to max input luminance nits = clamp(nits, 0.0, maxInLumi); Loading @@ -275,12 +309,12 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { float y2 = y1 + (maxOutLumi - y1) * 0.75; // horizontal distances between the last three control points float h12 = x2 - x1; float h23 = maxInLumi - x2; const float h12 = x2 - x1; const float h23 = maxInLumi - x2; // tangents at the last three control points float m1 = (y2 - y1) / h12; float m3 = (maxOutLumi - y2) / h23; float m2 = (m1 + m3) / 2.0; const float m1 = (y2 - y1) / h12; const float m3 = (maxOutLumi - y2) / h23; const float m2 = (m1 + m3) / 2.0; if (nits < x0) { // scale [0.0, x0] to [0.0, y0] linearly Loading @@ -288,7 +322,7 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { nits *= slope; } else if (nits < x1) { // scale [x0, x1] to [y0, y1] linearly float slope = (y1 - y0) / (x1 - x0); const 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 @@ -303,32 +337,64 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { } } // convert back to [0.0, 1.0] float targetY = nits / maxOutLumi; return color * (targetY / max(1e-6, colorY)); return color * (nits / max(1e-6, color.y)); } )__SHADER__"; break; case Key::INPUT_TF_HLG: } break; default: // TODO(73825729) We need to revert the tone mapping in // hardware composer properly. fs << R"__SHADER__( 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; highp vec3 ToneMap(highp vec3 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(highp vec3 color) { return color / 10000.0; } )__SHADER__"; break; case Key::OUTPUT_TF_HLG: fs << R"__SHADER__( highp vec3 NormalizeLuminance(highp vec3 color) { return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 NormalizeLuminance(highp vec3 color) { return color / displayMaxLuminance; } )__SHADER__"; break; } } // Generate OOTF that modifies the relative scence light to relative display light. void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { if (!needs.needsToneMapping()) { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return color; } )__SHADER__"; break; } else { generateToneMappingProcess(fs, needs); fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return NormalizeLuminance(ToneMap(ScaleLuminance(color))); } )__SHADER__"; } } Loading Loading @@ -446,8 +512,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { // Currently, only the OOTF of BT2020 PQ needs display maximum luminance. if (needs.getInputTF() == Key::INPUT_TF_ST2084) { // Currently, display maximum luminance is needed when doing tone mapping. if (needs.needsToneMapping()) { fs << "uniform float displayMaxLuminance;"; } Loading Loading
libs/binder/IServiceManager.cpp +26 −10 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <binder/IPermissionController.h> #endif #include <binder/Parcel.h> #include <cutils/properties.h> #include <utils/String8.h> #include <utils/SystemClock.h> #include <utils/CallStack.h> Loading Loading @@ -142,20 +143,35 @@ public: virtual sp<IBinder> getService(const String16& name) const { unsigned n; for (n = 0; n < 5; n++){ if (n > 0) { if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) { sp<IBinder> svc = checkService(name); if (svc != NULL) return svc; const bool isVendorService = strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; const long timeout = uptimeMillis() + 5000; if (!gSystemBootCompleted) { char bootCompleted[PROPERTY_VALUE_MAX]; property_get("sys.boot_completed", bootCompleted, "0"); gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false; } // retry interval in millisecond. const long sleepTime = gSystemBootCompleted ? 1000 : 100; int n = 0; while (uptimeMillis() < timeout) { n++; if (isVendorService) { ALOGI("Waiting for vendor service %s...", String8(name).string()); CallStack stack(LOG_TAG); } else { } else if (n%10 == 0) { ALOGI("Waiting for service %s...", String8(name).string()); } sleep(1); } usleep(1000*sleepTime); sp<IBinder> svc = checkService(name); if (svc != NULL) return svc; } ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); return NULL; } Loading
libs/binder/Static.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -97,5 +97,6 @@ sp<IServiceManager> gDefaultServiceManager; #ifndef __ANDROID_VNDK__ sp<IPermissionController> gPermissionController; #endif bool gSystemBootCompleted = false; } // namespace android
libs/binder/include/private/binder/Static.h +1 −0 Original line number Diff line number Diff line Loading @@ -41,5 +41,6 @@ extern sp<IServiceManager> gDefaultServiceManager; #ifndef __ANDROID_VNDK__ extern sp<IPermissionController> gPermissionController; #endif extern bool gSystemBootCompleted; } // namespace android
opengl/libs/EGL/eglApi.cpp +19 −7 Original line number Diff line number Diff line Loading @@ -475,6 +475,12 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { return HAL_DATASPACE_UNKNOWN; } // Get the colorspace value that should be reported from queries. When the colorspace // is unknown (no attribute passed), default to reporting LINEAR. static EGLint getReportedColorSpace(EGLint colorspace) { return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace; } // Returns a list of color spaces understood by the vendor EGL driver. static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, android_pixel_format format) { Loading Loading @@ -569,7 +575,8 @@ static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, // supports wide color. const bool colorSpaceIsNarrow = *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR; *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || *colorSpace == EGL_UNKNOWN; if (window && !colorSpaceIsNarrow) { bool windowSupportsWideColor = true; // Ordinarily we'd put a call to native_window_get_wide_color_support Loading Loading @@ -718,7 +725,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, window, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading Loading @@ -757,7 +764,8 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx); new egl_surface_t(dp.get(), config, window, surface, getReportedColorSpace(colorSpace), cnx); return s; } Loading @@ -782,7 +790,7 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // now select a corresponding sRGB format if needed EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading @@ -794,7 +802,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreatePixmapSurface( dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, getReportedColorSpace(colorSpace), cnx); return s; } } Loading @@ -814,7 +824,7 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, getNativePixelFormat(iDpy, cnx, config, &format); // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR; EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, &strippedAttribList)) { Loading @@ -826,7 +836,9 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, EGLSurface surface = cnx->egl.eglCreatePbufferSurface( dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx); egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, getReportedColorSpace(colorSpace), cnx); return s; } } Loading
services/surfaceflinger/RenderEngine/ProgramCache.cpp +147 −81 Original line number Diff line number Diff line Loading @@ -232,32 +232,66 @@ 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 Key& needs) { void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) { // Convert relative light to absolute light. switch (needs.getInputTF()) { case Key::INPUT_TF_ST2084: fs << R"__SHADER__( 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; highp vec3 ScaleLuminance(highp vec3 color) { return color * 10000.0; } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( highp vec3 ScaleLuminance(highp vec3 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); } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ScaleLuminance(highp vec3 color) { return color * displayMaxLuminance; } )__SHADER__"; break; } // Generate OOTF that modifies the relative display light. // Tone map absolute light to display luminance range. 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 OOTF(const highp vec3 color) { const float maxLumi = 10000.0; highp vec3 ToneMap(highp vec3 color) { return clamp(color, 0.0, 1000.0); } )__SHADER__"; break; case Key::OUTPUT_TF_ST2084: fs << R"__SHADER__( highp vec3 ToneMap(highp vec3 color) { return color; } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 ToneMap(highp vec3 color) { const float maxMasteringLumi = 1000.0; const float maxContentLumi = 1000.0; const float maxInLumi = min(maxMasteringLumi, maxContentLumi); float maxOutLumi = displayMaxLuminance; // Calculate Y value in XYZ color space. float colorY = CalculateY(color); // convert to nits first float nits = colorY * maxLumi; float nits = color.y; // clamp to max input luminance nits = clamp(nits, 0.0, maxInLumi); Loading @@ -275,12 +309,12 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { float y2 = y1 + (maxOutLumi - y1) * 0.75; // horizontal distances between the last three control points float h12 = x2 - x1; float h23 = maxInLumi - x2; const float h12 = x2 - x1; const float h23 = maxInLumi - x2; // tangents at the last three control points float m1 = (y2 - y1) / h12; float m3 = (maxOutLumi - y2) / h23; float m2 = (m1 + m3) / 2.0; const float m1 = (y2 - y1) / h12; const float m3 = (maxOutLumi - y2) / h23; const float m2 = (m1 + m3) / 2.0; if (nits < x0) { // scale [0.0, x0] to [0.0, y0] linearly Loading @@ -288,7 +322,7 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { nits *= slope; } else if (nits < x1) { // scale [x0, x1] to [y0, y1] linearly float slope = (y1 - y0) / (x1 - x0); const 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 @@ -303,32 +337,64 @@ void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { } } // convert back to [0.0, 1.0] float targetY = nits / maxOutLumi; return color * (targetY / max(1e-6, colorY)); return color * (nits / max(1e-6, color.y)); } )__SHADER__"; break; case Key::INPUT_TF_HLG: } break; default: // TODO(73825729) We need to revert the tone mapping in // hardware composer properly. fs << R"__SHADER__( 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; highp vec3 ToneMap(highp vec3 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(highp vec3 color) { return color / 10000.0; } )__SHADER__"; break; case Key::OUTPUT_TF_HLG: fs << R"__SHADER__( highp vec3 NormalizeLuminance(highp vec3 color) { return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); } )__SHADER__"; break; default: fs << R"__SHADER__( highp vec3 NormalizeLuminance(highp vec3 color) { return color / displayMaxLuminance; } )__SHADER__"; break; } } // Generate OOTF that modifies the relative scence light to relative display light. void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { if (!needs.needsToneMapping()) { fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return color; } )__SHADER__"; break; } else { generateToneMappingProcess(fs, needs); fs << R"__SHADER__( highp vec3 OOTF(const highp vec3 color) { return NormalizeLuminance(ToneMap(ScaleLuminance(color))); } )__SHADER__"; } } Loading Loading @@ -446,8 +512,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) { // Currently, only the OOTF of BT2020 PQ needs display maximum luminance. if (needs.getInputTF() == Key::INPUT_TF_ST2084) { // Currently, display maximum luminance is needed when doing tone mapping. if (needs.needsToneMapping()) { fs << "uniform float displayMaxLuminance;"; } Loading