Merge changes Ife3ef43f,I50ec5d8b into pi-dev

* changes:
  SF: Test coverage for onInitializeDisplays
  SF: Test Coverage for setDisplayStateLocked
diff --git a/headers/media_plugin/media/openmax/OMX_Audio.h b/headers/media_plugin/media/openmax/OMX_Audio.h
index 9c0296b..f8a36bd 100644
--- a/headers/media_plugin/media/openmax/OMX_Audio.h
+++ b/headers/media_plugin/media/openmax/OMX_Audio.h
@@ -263,6 +263,7 @@
   OMX_AUDIO_AACObjectLD = 23,       /**< AAC Low Delay object (Error Resilient) */
   OMX_AUDIO_AACObjectHE_PS = 29,    /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */
   OMX_AUDIO_AACObjectELD = 39,      /** AAC Enhanced Low Delay. NOTE: Pending Khronos standardization **/
+  OMX_AUDIO_AACObjectXHE = 42,      /** extended High Efficiency AAC. NOTE: Pending Khronos standardization */
   OMX_AUDIO_AACObjectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
   OMX_AUDIO_AACObjectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
   OMX_AUDIO_AACObjectMax = 0x7FFFFFFF
diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
index 05c2232..8409553 100644
--- a/headers/media_plugin/media/openmax/OMX_AudioExt.h
+++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h
@@ -82,6 +82,7 @@
                                    limit the audio signal. Use 0 to let encoder decide */
 } OMX_AUDIO_PARAM_ANDROID_OPUSTYPE;
 
+/** deprecated. use OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
 typedef struct OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE {
     OMX_U32 nSize;            /**< size of the structure in bytes */
     OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
@@ -94,6 +95,19 @@
     OMX_S32 nPCMLimiterEnable;     /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */
 } OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE;
 
+typedef struct OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_S32 nMaxOutputChannels;    /**< Maximum channel count to be output, -1 if unspecified, 0 if downmixing disabled */
+    OMX_S32 nDrcCut;               /**< The DRC attenuation factor, between 0 and 127, -1 if unspecified */
+    OMX_S32 nDrcBoost;             /**< The DRC amplification factor, between 0 and 127, -1 if unspecified */
+    OMX_S32 nHeavyCompression;     /**< 0 for light compression, 1 for heavy compression, -1 if unspecified */
+    OMX_S32 nTargetReferenceLevel; /**< Target reference level, between 0 and 127, -1 if unspecified */
+    OMX_S32 nEncodedTargetLevel;   /**< Target reference level assumed at the encoder, between 0 and 127, -1 if unspecified */
+    OMX_S32 nPCMLimiterEnable;     /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */
+    OMX_S32 nDrcEffectType;        /**< MPEG-D DRC effect type, between -1 and 6, -2 if unspecified */
+} OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE;
+
 typedef struct OMX_AUDIO_PARAM_ANDROID_PROFILETYPE {
    OMX_U32 nSize;
    OMX_VERSIONTYPE nVersion;
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index c2bf97e..716d959 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -63,6 +63,7 @@
     OMX_IndexParamAudioAndroidAacPresentation,      /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */
     OMX_IndexParamAudioAndroidEac3,                 /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
     OMX_IndexParamAudioProfileQuerySupported,       /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
+    OMX_IndexParamAudioAndroidAacDrcPresentation,   /**< reference: OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE */
     OMX_IndexExtAudioEndUnused,
 
     /* Image parameters and configurations */
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8f6b1bd..8b2f842 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -42,6 +42,7 @@
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
         "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.drm@1.0::IDrmFactory",
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 34e6d80..89bc0c4 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -92,10 +92,13 @@
     Mutex::Autolock _l(mMutex);
 
     err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
+    if (err != OK) {
+        BI_LOGE("Failed to addReleaseFenceLocked");
+    }
 
     err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY,
             EGL_NO_SYNC_KHR);
-    if (err != OK) {
+    if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) {
         BI_LOGE("Failed to release buffer: %s (%d)",
                 strerror(-err), err);
     }
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index b022a20..3615577 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1733,13 +1733,31 @@
     ContextRef _c(dp.get(), ctx);
     egl_context_t * const c = _c.get();
 
+    // Temporary hack: eglImageCreateKHR should accept EGL_GL_COLORSPACE_LINEAR_KHR,
+    // EGL_GL_COLORSPACE_SRGB_KHR and EGL_GL_COLORSPACE_DEFAULT_EXT if
+    // EGL_EXT_image_gl_colorspace is supported, but some drivers don't like
+    // the DEFAULT value and generate an error.
+    std::vector<EGLint> strippedAttribList;
+    for (const EGLint *attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
+        if (attr[0] == EGL_GL_COLORSPACE_KHR &&
+            dp->haveExtension("EGL_EXT_image_gl_colorspace")) {
+            if (attr[1] != EGL_GL_COLORSPACE_LINEAR_KHR &&
+                attr[1] != EGL_GL_COLORSPACE_SRGB_KHR) {
+                continue;
+            }
+        }
+        strippedAttribList.push_back(attr[0]);
+        strippedAttribList.push_back(attr[1]);
+    }
+    strippedAttribList.push_back(EGL_NONE);
+
     EGLImageKHR result = EGL_NO_IMAGE_KHR;
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->egl.eglCreateImageKHR) {
         result = cnx->egl.eglCreateImageKHR(
                 dp->disp.dpy,
                 c ? c->context : EGL_NO_CONTEXT,
-                target, buffer, attrib_list);
+                target, buffer, strippedAttribList.data());
     }
     return result;
 }
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index d1887ee..fb63296 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -168,6 +168,227 @@
     return needs;
 }
 
+// Generate EOTF that converts signal values to relative display light,
+// both normalized to [0, 1].
+void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) {
+    switch (needs.getInputTF()) {
+        case Key::INPUT_TF_SRGB:
+            fs << R"__SHADER__(
+                float EOTF_sRGB(float srgb) {
+                    return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+                }
+
+                vec3 EOTF_sRGB(const vec3 srgb) {
+                    return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+                }
+
+                vec3 EOTF(const vec3 srgb) {
+                    return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_ST2084:
+            fs << R"__SHADER__(
+                vec3 EOTF(const highp vec3 color) {
+                    const highp float m1 = (2610.0 / 4096.0) / 4.0;
+                    const highp float m2 = (2523.0 / 4096.0) * 128.0;
+                    const highp float c1 = (3424.0 / 4096.0);
+                    const highp float c2 = (2413.0 / 4096.0) * 32.0;
+                    const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+                    highp vec3 tmp = pow(color, 1.0 / vec3(m2));
+                    tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
+                    return pow(tmp, 1.0 / vec3(m1));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            fs << R"__SHADER__(
+                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 EOTF(const highp vec3 color) {
+                    return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
+                            EOTF_channel(color.b));
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                vec3 EOTF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+// Generate OOTF that modifies the relative scence light to relative display light.
+void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) {
+    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;
+        }
+    )__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;
+                    const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
+                    const float maxOutLumi = 500.0;
+
+                    // 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);
+
+                    // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+                    if (maxInLumi <= maxOutLumi) {
+                        nits *= maxOutLumi / maxInLumi;
+                    } else {
+                        // three control points
+                        const float x0 = 10.0;
+                        const float y0 = 17.0;
+                        const float x1 = maxOutLumi * 0.75;
+                        const float y1 = x1;
+                        const float x2 = x1 + (maxInLumi - x1) / 2.0;
+                        const 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;
+                        // 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;
+
+                        if (nits < x0) {
+                            // scale [0.0, x0] to [0.0, y0] linearly
+                            const float slope = y0 / x0;
+                            nits *= slope;
+                        } else if (nits < x1) {
+                            // scale [x0, x1] to [y0, y1] linearly
+                            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
+                            float t = (nits - x1) / h12;
+                            nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
+                                    (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+                        } else {
+                            // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
+                            float t = (nits - x2) / h23;
+                            nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
+                                    (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
+                        }
+                    }
+
+                    // convert back to [0.0, 1.0]
+                    float targetY = nits / maxOutLumi;
+                    return color * (targetY / max(1e-6, colorY));
+                }
+            )__SHADER__";
+            break;
+        case Key::INPUT_TF_HLG:
+            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;
+                }
+            )__SHADER__";
+            break;
+        default:
+            fs << R"__SHADER__(
+                highp vec3 OOTF(const highp vec3 color) {
+                    return color;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
+// Generate OETF that converts relative display light to signal values,
+// both normalized to [0, 1]
+void ProgramCache::generateOETF(Formatter& fs, const Key& needs) {
+    switch (needs.getOutputTF()) {
+        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;
+        default:
+            fs << R"__SHADER__(
+                vec3 OETF(const vec3 linear) {
+                    return linear;
+                }
+            )__SHADER__";
+            break;
+    }
+}
+
 String8 ProgramCache::generateVertexShader(const Key& needs) {
     Formatter vs;
     if (needs.isTexturing()) {
@@ -223,221 +444,9 @@
     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:
-                fs << R"__SHADER__(
-                    vec3 EOTF(const vec3 linear) {
-                        return linear;
-                    }
-                )__SHADER__";
-                break;
-            case Key::INPUT_TF_SRGB:
-                fs << R"__SHADER__(
-                    float EOTF_sRGB(float srgb) {
-                        return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
-                    }
-
-                    vec3 EOTF_sRGB(const vec3 srgb) {
-                        return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
-                    }
-
-                    vec3 EOTF(const vec3 srgb) {
-                        return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
-                    }
-                )__SHADER__";
-                break;
-            case Key::INPUT_TF_ST2084:
-                fs << R"__SHADER__(
-                    vec3 EOTF(const highp vec3 color) {
-                        const highp float m1 = (2610.0 / 4096.0) / 4.0;
-                        const highp float m2 = (2523.0 / 4096.0) * 128.0;
-                        const highp float c1 = (3424.0 / 4096.0);
-                        const highp float c2 = (2413.0 / 4096.0) * 32.0;
-                        const highp float c3 = (2392.0 / 4096.0) * 32.0;
-
-                        highp vec3 tmp = pow(color, 1.0 / vec3(m2));
-                        tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
-                        return pow(tmp, 1.0 / vec3(m1));
-                    }
-                    )__SHADER__";
-                break;
-          case Key::INPUT_TF_HLG:
-              fs << R"__SHADER__(
-                  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 EOTF(const highp vec3 color) {
-                      return vec3(EOTF_channel(color.r), EOTF_channel(color.g),
-                              EOTF_channel(color.b));
-                  }
-                  )__SHADER__";
-              break;
-        }
-
-        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;
-            }
-        )__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;
-                        const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
-                        const float maxOutLumi = 500.0;
-
-                        // 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);
-
-                        // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
-                        if (maxInLumi <= maxOutLumi) {
-                            nits *= maxOutLumi / maxInLumi;
-                        } else {
-                            // three control points
-                            const float x0 = 10.0;
-                            const float y0 = 17.0;
-                            const float x1 = maxOutLumi * 0.75;
-                            const float y1 = x1;
-                            const float x2 = x1 + (maxInLumi - x1) / 2.0;
-                            const 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;
-                            // 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;
-
-                            if (nits < x0) {
-                                // scale [0.0, x0] to [0.0, y0] linearly
-                                const float slope = y0 / x0;
-                                nits *= slope;
-                            } else if (nits < x1) {
-                                // scale [x0, x1] to [y0, y1] linearly
-                                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
-                                float t = (nits - x1) / h12;
-                                nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
-                                       (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
-                            } else {
-                                // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
-                                float t = (nits - x2) / h23;
-                                nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
-                                       (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
-                            }
-                        }
-
-                        // convert back to [0.0, 1.0]
-                        float targetY = nits / maxOutLumi;
-                        return color * (targetY / max(1e-6, colorY));
-                    }
-                )__SHADER__";
-                break;
-            case Key::INPUT_TF_HLG:
-                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;
-                    }
-                )__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;
-        }
+        generateEOTF(fs, needs);
+        generateOOTF(fs, needs);
+        generateOETF(fs, needs);
     }
 
     fs << "void main(void) {" << indent;
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index f67e132..d18163a 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -28,6 +28,7 @@
 namespace android {
 
 class Description;
+class Formatter;
 class Program;
 class String8;
 
@@ -132,6 +133,12 @@
     void primeCache();
     // compute a cache Key from a Description
     static Key computeKey(const Description& description);
+    // Generate EOTF based from Key.
+    static void generateEOTF(Formatter& fs, const Key& needs);
+    // Generate OOTF based from Key.
+    static void generateOOTF(Formatter& fs, const Key& needs);
+    // Generate OETF based from Key.
+    static void generateOETF(Formatter& fs, const Key& needs);
     // generates a program from the Key
     static Program* generateProgram(const Key& needs);
     // generates the vertex shader from the Key