Merge "InputDispatcher: Update tests to verify spy window gesture monitors"
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 6882ea3..0128859 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -593,6 +593,10 @@
 }
 
 void EGLConsumer::onFreeBufferLocked(int slotIndex) {
+    if (mEglSlots[slotIndex].mEglImage != nullptr &&
+        mEglSlots[slotIndex].mEglImage == mCurrentTextureImage) {
+        mCurrentTextureImage.clear();
+    }
     mEglSlots[slotIndex].mEglImage.clear();
 }
 
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 612a0aa..e197150 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -49,6 +49,50 @@
 namespace android {
 namespace renderengine {
 
+namespace {
+
+double EOTF_PQ(double channel) {
+    float m1 = (2610.0 / 4096.0) / 4.0;
+    float m2 = (2523.0 / 4096.0) * 128.0;
+    float c1 = (3424.0 / 4096.0);
+    float c2 = (2413.0 / 4096.0) * 32.0;
+    float c3 = (2392.0 / 4096.0) * 32.0;
+
+    float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2);
+    tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp);
+    return std::pow(tmp, 1.0 / m1);
+}
+
+vec3 EOTF_PQ(vec3 color) {
+    return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b));
+}
+
+double EOTF_HLG(double channel) {
+    const float a = 0.17883277;
+    const float b = 0.28466892;
+    const float c = 0.55991073;
+    return channel <= 0.5 ? channel * channel / 3.0 : (exp((channel - c) / a) + b) / 12.0;
+}
+
+vec3 EOTF_HLG(vec3 color) {
+    return vec3(EOTF_HLG(color.r), EOTF_HLG(color.g), EOTF_HLG(color.b));
+}
+
+double OETF_sRGB(double channel) {
+    return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055;
+}
+
+int sign(float in) {
+    return in >= 0.0 ? 1 : -1;
+}
+
+vec3 OETF_sRGB(vec3 linear) {
+    return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g),
+                sign(linear.b) * OETF_sRGB(linear.b));
+}
+
+} // namespace
+
 class RenderEngineFactory {
 public:
     virtual ~RenderEngineFactory() = default;
@@ -598,6 +642,12 @@
                                  const renderengine::ShadowSettings& shadow,
                                  const ubyte4& backgroundColor);
 
+    // Tonemaps grey values from sourceDataspace -> Display P3 and checks that GPU and CPU
+    // implementations are identical Also implicitly checks that the injected tonemap shader
+    // compiles
+    void tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
+                 std::function<vec3(vec3, float)> scaleOotf);
+
     void initializeRenderEngine();
 
     std::unique_ptr<renderengine::RenderEngine> mRE;
@@ -1418,6 +1468,119 @@
     invokeDraw(settings, layers);
 }
 
+void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
+                               std::function<vec3(vec3, float)> scaleOotf) {
+    constexpr int32_t kGreyLevels = 256;
+
+    const auto rect = Rect(0, 0, kGreyLevels, 1);
+
+    constexpr float kMaxLuminance = 750.f;
+    constexpr float kCurrentLuminanceNits = 500.f;
+    const renderengine::DisplaySettings display{
+            .physicalDisplay = rect,
+            .clip = rect,
+            .maxLuminance = kMaxLuminance,
+            .currentLuminanceNits = kCurrentLuminanceNits,
+            .outputDataspace = ui::Dataspace::DISPLAY_P3,
+    };
+
+    auto buf = std::make_shared<
+            renderengine::impl::
+                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+                                                       1,
+                                                       GRALLOC_USAGE_SW_READ_OFTEN |
+                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                               GRALLOC_USAGE_HW_RENDER |
+                                                               GRALLOC_USAGE_HW_TEXTURE,
+                                                       "input"),
+                                     *mRE,
+                                     renderengine::impl::ExternalTexture::Usage::READABLE |
+                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+    ASSERT_EQ(0, buf->getBuffer()->initCheck());
+    {
+        uint8_t* pixels;
+        buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                               reinterpret_cast<void**>(&pixels));
+
+        uint8_t color = 0;
+        for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
+            uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4);
+            for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
+                dest[0] = color;
+                dest[1] = color;
+                dest[2] = color;
+                dest[3] = 255;
+                color++;
+                dest += 4;
+            }
+        }
+        buf->getBuffer()->unlock();
+    }
+
+    mBuffer = std::make_shared<
+            renderengine::impl::
+                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+                                                       1,
+                                                       GRALLOC_USAGE_SW_READ_OFTEN |
+                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
+                                                               GRALLOC_USAGE_HW_RENDER |
+                                                               GRALLOC_USAGE_HW_TEXTURE,
+                                                       "output"),
+                                     *mRE,
+                                     renderengine::impl::ExternalTexture::Usage::READABLE |
+                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+    ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());
+
+    const renderengine::LayerSettings layer{.geometry.boundaries = rect.toFloatRect(),
+                                            .source =
+                                                    renderengine::PixelSource{
+                                                            .buffer =
+                                                                    renderengine::Buffer{
+                                                                            .buffer =
+                                                                                    std::move(buf),
+                                                                            .usePremultipliedAlpha =
+                                                                                    true,
+                                                                    },
+                                                    },
+                                            .alpha = 1.0f,
+                                            .sourceDataspace = sourceDataspace};
+
+    std::vector<renderengine::LayerSettings> layers{layer};
+    invokeDraw(display, layers);
+
+    ColorSpace displayP3 = ColorSpace::DisplayP3();
+    ColorSpace bt2020 = ColorSpace::BT2020();
+
+    tonemap::Metadata metadata{.displayMaxLuminance = 750.0f};
+
+    auto generator = [=](Point location) {
+        const double normColor = static_cast<double>(location.x) / (kGreyLevels - 1);
+        const vec3 rgb = vec3(normColor, normColor, normColor);
+
+        const vec3 linearRGB = eotf(rgb);
+
+        const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB;
+
+        const vec3 scaledXYZ = scaleOotf(xyz, kCurrentLuminanceNits);
+        const double gain =
+                tonemap::getToneMapper()
+                        ->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
+                                                                Dataspace>(sourceDataspace),
+                                            static_cast<aidl::android::hardware::graphics::common::
+                                                                Dataspace>(
+                                                    ui::Dataspace::DISPLAY_P3),
+                                            scaleOotf(linearRGB, kCurrentLuminanceNits), scaledXYZ,
+                                            metadata);
+        const vec3 normalizedXYZ = scaledXYZ * gain / metadata.displayMaxLuminance;
+
+        const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * normalizedXYZ) * 255;
+        return ubyte4(static_cast<uint8_t>(targetRGB.r), static_cast<uint8_t>(targetRGB.g),
+                      static_cast<uint8_t>(targetRGB.b), 255);
+    };
+
+    expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
+}
+
 INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
                          testing::Values(std::make_shared<GLESRenderEngineFactory>(),
                                          std::make_shared<GLESCMRenderEngineFactory>(),
@@ -2412,155 +2575,47 @@
     }
 }
 
-double EOTF_PQ(double channel) {
-    float m1 = (2610.0 / 4096.0) / 4.0;
-    float m2 = (2523.0 / 4096.0) * 128.0;
-    float c1 = (3424.0 / 4096.0);
-    float c2 = (2413.0 / 4096.0) * 32.0;
-    float c3 = (2392.0 / 4096.0) * 32.0;
-
-    float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2);
-    tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp);
-    return std::pow(tmp, 1.0 / m1);
-}
-
-vec3 EOTF_PQ(vec3 color) {
-    return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b));
-}
-
-double OETF_sRGB(double channel) {
-    return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055;
-}
-
-int sign(float in) {
-    return in >= 0.0 ? 1 : -1;
-}
-
-vec3 OETF_sRGB(vec3 linear) {
-    return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g),
-                sign(linear.b) * OETF_sRGB(linear.b));
-}
-
 TEST_P(RenderEngineTest, test_tonemapPQMatches) {
     if (!GetParam()->useColorManagement()) {
-        return;
+        GTEST_SKIP();
     }
 
     if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
-        return;
+        GTEST_SKIP();
     }
 
     initializeRenderEngine();
 
-    constexpr int32_t kGreyLevels = 256;
+    tonemap(
+            static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
+                                       HAL_DATASPACE_TRANSFER_ST2084 | HAL_DATASPACE_RANGE_FULL),
+            [](vec3 color) { return EOTF_PQ(color); },
+            [](vec3 color, float) {
+                static constexpr float kMaxPQLuminance = 10000.f;
+                return color * kMaxPQLuminance;
+            });
+}
 
-    const auto rect = Rect(0, 0, kGreyLevels, 1);
-    const renderengine::DisplaySettings display{
-            .physicalDisplay = rect,
-            .clip = rect,
-            .maxLuminance = 750.0f,
-            .outputDataspace = ui::Dataspace::DISPLAY_P3,
-    };
-
-    auto buf = std::make_shared<
-            renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                       1,
-                                                       GRALLOC_USAGE_SW_READ_OFTEN |
-                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                               GRALLOC_USAGE_HW_RENDER |
-                                                               GRALLOC_USAGE_HW_TEXTURE,
-                                                       "input"),
-                                     *mRE,
-                                     renderengine::impl::ExternalTexture::Usage::READABLE |
-                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
-    ASSERT_EQ(0, buf->getBuffer()->initCheck());
-
-    {
-        uint8_t* pixels;
-        buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                               reinterpret_cast<void**>(&pixels));
-
-        uint8_t color = 0;
-        for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
-            uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4);
-            for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
-                dest[0] = color;
-                dest[1] = color;
-                dest[2] = color;
-                dest[3] = 255;
-                color++;
-                dest += 4;
-            }
-        }
-        buf->getBuffer()->unlock();
+TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
+    if (!GetParam()->useColorManagement()) {
+        GTEST_SKIP();
     }
 
-    mBuffer = std::make_shared<
-            renderengine::impl::
-                    ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                       1,
-                                                       GRALLOC_USAGE_SW_READ_OFTEN |
-                                                               GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                                               GRALLOC_USAGE_HW_RENDER |
-                                                               GRALLOC_USAGE_HW_TEXTURE,
-                                                       "output"),
-                                     *mRE,
-                                     renderengine::impl::ExternalTexture::Usage::READABLE |
-                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
-    ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());
+    if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        GTEST_SKIP();
+    }
 
-    const renderengine::LayerSettings layer{
-            .geometry.boundaries = rect.toFloatRect(),
-            .source =
-                    renderengine::PixelSource{
-                            .buffer =
-                                    renderengine::Buffer{
-                                            .buffer = std::move(buf),
-                                            .usePremultipliedAlpha = true,
-                                    },
-                    },
-            .alpha = 1.0f,
-            .sourceDataspace = static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
-                                                          HAL_DATASPACE_TRANSFER_ST2084 |
-                                                          HAL_DATASPACE_RANGE_FULL),
-    };
+    initializeRenderEngine();
 
-    std::vector<renderengine::LayerSettings> layers{layer};
-    invokeDraw(display, layers);
-
-    ColorSpace displayP3 = ColorSpace::DisplayP3();
-    ColorSpace bt2020 = ColorSpace::BT2020();
-
-    tonemap::Metadata metadata{.displayMaxLuminance = 750.0f};
-
-    auto generator = [=](Point location) {
-        const double normColor = static_cast<double>(location.x) / (kGreyLevels - 1);
-        const vec3 rgb = vec3(normColor, normColor, normColor);
-
-        const vec3 linearRGB = EOTF_PQ(rgb);
-
-        static constexpr float kMaxPQLuminance = 10000.f;
-        const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB * kMaxPQLuminance;
-        const double gain =
-                tonemap::getToneMapper()
-                        ->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
-                                                                Dataspace>(
-                                                    HAL_DATASPACE_STANDARD_BT2020 |
-                                                    HAL_DATASPACE_TRANSFER_ST2084 |
-                                                    HAL_DATASPACE_RANGE_FULL),
-                                            static_cast<aidl::android::hardware::graphics::common::
-                                                                Dataspace>(
-                                                    ui::Dataspace::DISPLAY_P3),
-                                            linearRGB * 10000.0, xyz, metadata);
-        const vec3 scaledXYZ = xyz * gain / metadata.displayMaxLuminance;
-
-        const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * scaledXYZ) * 255;
-        return ubyte4(static_cast<uint8_t>(targetRGB.r), static_cast<uint8_t>(targetRGB.g),
-                      static_cast<uint8_t>(targetRGB.b), 255);
-    };
-
-    expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
+    tonemap(
+            static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
+                                       HAL_DATASPACE_RANGE_FULL),
+            [](vec3 color) { return EOTF_HLG(color); },
+            [](vec3 color, float currentLuminaceNits) {
+                static constexpr float kMaxHLGLuminance = 1000.f;
+                static const float kHLGGamma = 1.2 + 0.42 * std::log10(currentLuminaceNits / 1000);
+                return color * kMaxHLGLuminance * std::pow(color.y, kHLGGamma - 1);
+            });
 }
 
 TEST_P(RenderEngineTest, r8_behaves_as_mask) {
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 4d88d5d..03da3ec 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -18,6 +18,7 @@
 
 #include <tonemap/tonemap.h>
 
+#include <cmath>
 #include <optional>
 
 #include <math/mat4.h>
@@ -26,12 +27,13 @@
 
 namespace android::shaders {
 
-static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(
-        ui::Dataspace dataspace) {
+namespace {
+
+aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(ui::Dataspace dataspace) {
     return static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace);
 }
 
-static void generateEOTF(ui::Dataspace dataspace, std::string& shader) {
+void generateEOTF(ui::Dataspace dataspace, std::string& shader) {
     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_ST2084:
             shader.append(R"(
@@ -156,7 +158,7 @@
     }
 }
 
-static void generateXYZTransforms(std::string& shader) {
+void generateXYZTransforms(std::string& shader) {
     shader.append(R"(
         uniform float4x4 in_rgbToXyz;
         uniform float4x4 in_xyzToRgb;
@@ -171,8 +173,8 @@
 }
 
 // Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits])
-static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace,
-                                           ui::Dataspace outputDataspace, std::string& shader) {
+void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
+                                    std::string& shader) {
     switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_ST2084:
             shader.append(R"(
@@ -183,8 +185,9 @@
             break;
         case HAL_DATASPACE_TRANSFER_HLG:
             shader.append(R"(
+                    uniform float in_hlgGamma;
                     float3 ScaleLuminance(float3 xyz) {
-                        return xyz * 1000.0 * pow(xyz.y, 0.2);
+                        return xyz * 1000.0 * pow(xyz.y, in_hlgGamma - 1);
                     }
                 )");
             break;
@@ -225,8 +228,10 @@
             break;
         case HAL_DATASPACE_TRANSFER_HLG:
             shader.append(R"(
+                    uniform float in_hlgGamma;
                     float3 NormalizeLuminance(float3 xyz) {
-                        return xyz / 1000.0 * pow(xyz.y / 1000.0, -0.2 / 1.2);
+                        return xyz / 1000.0 *
+                                pow(xyz.y / 1000.0, (1 - in_hlgGamma) / (in_hlgGamma));
                     }
                 )");
             break;
@@ -240,8 +245,8 @@
     }
 }
 
-static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
-                         std::string& shader) {
+void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
+                  std::string& shader) {
     shader.append(tonemap::getToneMapper()
                           ->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace),
                                                           toAidlDataspace(outputDataspace))
@@ -262,7 +267,7 @@
         )");
 }
 
-static void generateOETF(ui::Dataspace dataspace, std::string& shader) {
+void generateOETF(ui::Dataspace dataspace, std::string& shader) {
     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_ST2084:
             shader.append(R"(
@@ -384,7 +389,7 @@
     }
 }
 
-static void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) {
+void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) {
     shader.append(R"(
         uniform shader child;
         half4 main(float2 xy) {
@@ -412,7 +417,7 @@
 }
 
 // please keep in sync with toSkColorSpace function in renderengine/skia/ColorSpaces.cpp
-static ColorSpace toColorSpace(ui::Dataspace dataspace) {
+ColorSpace toColorSpace(ui::Dataspace dataspace) {
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
         case HAL_DATASPACE_STANDARD_BT709:
             return ColorSpace::sRGB();
@@ -438,6 +443,21 @@
     }
 }
 
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+    std::vector<uint8_t> result;
+    result.resize(sizeof(value));
+    std::memcpy(result.data(), &value, sizeof(value));
+    return result;
+}
+
+// Refer to BT2100-2
+float computeHlgGamma(float currentDisplayBrightnessNits) {
+    return 1.2 + 0.42 * std::log10(currentDisplayBrightnessNits / 1000);
+}
+
+} // namespace
+
 std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) {
     std::string shaderString;
     generateEOTF(linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
@@ -451,14 +471,6 @@
     return shaderString;
 }
 
-template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
-std::vector<uint8_t> buildUniformValue(T value) {
-    std::vector<uint8_t> result;
-    result.resize(sizeof(value));
-    std::memcpy(result.data(), &value, sizeof(value));
-    return result;
-}
-
 // Generates a list of uniforms to set on the LinearEffect shader above.
 std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
                                                               const mat4& colorTransform,
@@ -480,8 +492,13 @@
                                     colorTransform * mat4(outputColorSpace.getXYZtoRGB()))});
     }
 
+    if ((linearEffect.inputDataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_HLG) {
+        uniforms.push_back(
+                {.name = "in_hlgGamma",
+                 .value = buildUniformValue<float>(computeHlgGamma(currentDisplayLuminanceNits))});
+    }
+
     tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
-                               .currentDisplayLuminanceNits = currentDisplayLuminanceNits,
                                // If the input luminance is unknown, use display luminance (aka,
                                // no-op any luminance changes)
                                // This will be the case for eg screenshots in addition to
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index 6233e6c..b9abf8c 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -44,8 +44,6 @@
 struct Metadata {
     // The maximum luminance of the display in nits
     float displayMaxLuminance = 0.0;
-    // The current luminance of the display in nits
-    float currentDisplayLuminanceNits = 0.0;
     // The maximum luminance of the content in nits
     float contentMaxLuminance = 0.0;
 };
diff --git a/libs/tonemap/tests/tonemap_test.cpp b/libs/tonemap/tests/tonemap_test.cpp
index 7a7958f..1d46482 100644
--- a/libs/tonemap/tests/tonemap_test.cpp
+++ b/libs/tonemap/tests/tonemap_test.cpp
@@ -61,7 +61,7 @@
     EXPECT_GT(contentLumFloat, 0);
 }
 
-TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPoint) {
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPointForPQ) {
     const auto shader =
             tonemap::getToneMapper()
                     ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
@@ -73,4 +73,16 @@
     EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
 }
 
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPointForHLG) {
+    const auto shader =
+            tonemap::getToneMapper()
+                    ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
+                                                            Dataspace::BT2020_ITU_HLG,
+                                                    aidl::android::hardware::graphics::common::
+                                                            Dataspace::DISPLAY_P3);
+
+    // Other tests such as librenderengine_test will plug in the shader to check compilation.
+    EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
+}
+
 } // namespace android
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
index c2372fe..bc0a884 100644
--- a/libs/tonemap/tonemap.cpp
+++ b/libs/tonemap/tonemap.cpp
@@ -407,7 +407,6 @@
             )");
         switch (sourceDataspaceInt & kTransferMask) {
             case kTransferST2084:
-            case kTransferHLG:
                 switch (destinationDataspaceInt & kTransferMask) {
                     case kTransferST2084:
                         program.append(R"(
@@ -428,39 +427,22 @@
                         break;
 
                     default:
-                        switch (sourceDataspaceInt & kTransferMask) {
-                            case kTransferST2084:
-                                program.append(R"(
-                                        float libtonemap_OETFTone(float channel) {
-                                            channel = channel / 10000.0;
-                                            float m1 = (2610.0 / 4096.0) / 4.0;
-                                            float m2 = (2523.0 / 4096.0) * 128.0;
-                                            float c1 = (3424.0 / 4096.0);
-                                            float c2 = (2413.0 / 4096.0) * 32.0;
-                                            float c3 = (2392.0 / 4096.0) * 32.0;
-
-                                            float tmp = pow(channel, float(m1));
-                                            tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
-                                            return pow(tmp, float(m2));
-                                        }
-                                    )");
-                                break;
-                            case kTransferHLG:
-                                program.append(R"(
-                                        float libtonemap_OETFTone(float channel) {
-                                            channel = channel / 1000.0;
-                                            const float a = 0.17883277;
-                                            const float b = 0.28466892;
-                                            const float c = 0.55991073;
-                                            return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
-                                                    a * log(12.0 * channel - b) + c;
-                                        }
-                                    )");
-                                break;
-                        }
                         // Here we're mapping from HDR to SDR content, so interpolate using a
                         // Hermitian polynomial onto the smaller luminance range.
                         program.append(R"(
+                                float libtonemap_OETFTone(float channel) {
+                                    channel = channel / 10000.0;
+                                    float m1 = (2610.0 / 4096.0) / 4.0;
+                                    float m2 = (2523.0 / 4096.0) * 128.0;
+                                    float c1 = (3424.0 / 4096.0);
+                                    float c2 = (2413.0 / 4096.0) * 32.0;
+                                    float c3 = (2392.0 / 4096.0) * 32.0;
+
+                                    float tmp = pow(channel, float(m1));
+                                    tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+                                    return pow(tmp, float(m2));
+                                }
+
                                 float libtonemap_ToneMapTargetNits(float maxRGB) {
                                     float maxInLumi = in_libtonemap_inputMaxLuminance;
                                     float maxOutLumi = in_libtonemap_displayMaxLuminance;
@@ -508,6 +490,30 @@
                         break;
                 }
                 break;
+            case kTransferHLG:
+                switch (destinationDataspaceInt & kTransferMask) {
+                    // HLG -> HDR does not tone-map at all
+                    case kTransferST2084:
+                    case kTransferHLG:
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                        return maxRGB;
+                                    }
+                                )");
+                        break;
+                    default:
+                        // libshaders follows BT2100 OOTF, but with a nominal peak display luminance
+                        // of 1000 nits. Renormalize to max display luminance if we're tone-mapping
+                        // down to SDR, as libshaders normalizes all SDR output from [0,
+                        // maxDisplayLumins] -> [0, 1]
+                        program.append(R"(
+                                    float libtonemap_ToneMapTargetNits(float maxRGB) {
+                                        return maxRGB * in_libtonemap_displayMaxLuminance / 1000.0;
+                                    }
+                                )");
+                        break;
+                }
+                break;
             default:
                 // Inverse tone-mapping and SDR-SDR mapping is not supported.
                 program.append(R"(
@@ -558,7 +564,6 @@
         double targetNits = 0.0;
         switch (sourceDataspaceInt & kTransferMask) {
             case kTransferST2084:
-            case kTransferHLG:
                 switch (destinationDataspaceInt & kTransferMask) {
                     case kTransferST2084:
                         targetNits = maxRGB;
@@ -587,19 +592,9 @@
                         double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
                         double y2 = maxOutLumi * 0.9;
 
-                        double greyNorm1 = 0.0;
-                        double greyNorm2 = 0.0;
-                        double greyNorm3 = 0.0;
-
-                        if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) {
-                            greyNorm1 = OETF_ST2084(x1);
-                            greyNorm2 = OETF_ST2084(x2);
-                            greyNorm3 = OETF_ST2084(x3);
-                        } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
-                            greyNorm1 = OETF_HLG(x1);
-                            greyNorm2 = OETF_HLG(x2);
-                            greyNorm3 = OETF_HLG(x3);
-                        }
+                        const double greyNorm1 = OETF_ST2084(x1);
+                        const double greyNorm2 = OETF_ST2084(x2);
+                        const double greyNorm3 = OETF_ST2084(x3);
 
                         double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
                         double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);
@@ -613,12 +608,7 @@
                             break;
                         }
 
-                        double greyNits = 0.0;
-                        if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) {
-                            greyNits = OETF_ST2084(targetNits);
-                        } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
-                            greyNits = OETF_HLG(targetNits);
-                        }
+                        const double greyNits = OETF_ST2084(targetNits);
 
                         if (greyNits <= greyNorm2) {
                             targetNits = (greyNits - greyNorm2) * slope2 + y2;
@@ -630,15 +620,20 @@
                         break;
                 }
                 break;
-            default:
+            case kTransferHLG:
                 switch (destinationDataspaceInt & kTransferMask) {
                     case kTransferST2084:
                     case kTransferHLG:
-                    default:
                         targetNits = maxRGB;
                         break;
+                    default:
+                        targetNits = maxRGB * metadata.displayMaxLuminance / 1000.0;
+                        break;
                 }
                 break;
+            default:
+                targetNits = maxRGB;
+                break;
         }
 
         return targetNits / maxRGB;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7d8b58f..f97a9ec 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -17,6 +17,7 @@
 #include "../dispatcher/InputDispatcher.h"
 
 #include <android-base/properties.h>
+#include <android-base/silent_death_test.h>
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
 #include <binder/Binder.h>
@@ -6271,10 +6272,13 @@
     int mSpyCount{0};
 };
 
+using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
 /**
  * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
  */
-TEST_F(InputDispatcherSpyWindowTest, UntrustedSpy_AbortsDispatcher) {
+TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
+    ScopedSilentDeath _silentDeath;
+
     auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
     spy->setTrustedOverlay(false);
     ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
@@ -6735,7 +6739,11 @@
     }
 };
 
-TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) {
+using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
+
+TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
+    ScopedSilentDeath _silentDeath;
+
     auto [overlay, window] = setupStylusOverlayScenario();
     overlay->setTrustedOverlay(false);
     // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index e797b5d..b7e2ff3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -306,7 +306,7 @@
                 : aidl::android::hardware::graphics::composer3::Composition::DEVICE;
     }
 
-    compositionState->buffer = mBufferInfo.mBuffer->getBuffer();
+    compositionState->buffer = getBuffer();
     compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
             ? 0
             : mBufferInfo.mBufferSlot;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 1ea13a7..29c146b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -59,9 +59,13 @@
     setName(args.name);
     bool isBootModeSupported = getCompositionEngine().getHwComposer().getBootDisplayModeSupport();
     const auto physicalId = PhysicalDisplayId::tryCast(mId);
-    if (physicalId && isBootModeSupported) {
-        mPreferredBootDisplayModeId = static_cast<int32_t>(
-                getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId));
+    if (!physicalId || !isBootModeSupported) {
+        return;
+    }
+    std::optional<hal::HWConfigId> preferredBootModeId =
+            getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId);
+    if (preferredBootModeId.has_value()) {
+        mPreferredBootDisplayModeId = static_cast<int32_t>(preferredBootModeId.value());
     }
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index bcd4dc2..660f664 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -108,7 +108,7 @@
                           hal::VsyncPeriodChangeTimeline*));
     MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId));
     MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId));
-    MOCK_METHOD1(getPreferredBootDisplayMode, hal::HWConfigId(PhysicalDisplayId));
+    MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
     MOCK_METHOD0(getBootDisplayModeSupport, bool());
     MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
     MOCK_METHOD2(getSupportedContentTypes,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 9174ec7..2696bd8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -772,18 +772,16 @@
     return NO_ERROR;
 }
 
-hal::HWConfigId HWComposer::getPreferredBootDisplayMode(PhysicalDisplayId displayId) {
-    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
-    hal::HWConfigId displayModeId = -1;
+std::optional<hal::HWConfigId> HWComposer::getPreferredBootDisplayMode(
+        PhysicalDisplayId displayId) {
+    RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt);
+    hal::HWConfigId displayModeId;
     const auto error =
             mDisplayData[displayId].hwcDisplay->getPreferredBootDisplayConfig(&displayModeId);
-    if (error == hal::Error::UNSUPPORTED) {
-        RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+    if (error != hal::Error::NONE) {
+        LOG_DISPLAY_ERROR(displayId, to_string(error).c_str());
+        return std::nullopt;
     }
-    if (error == hal::Error::BAD_PARAMETER) {
-        RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
-    }
-    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return displayModeId;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3e68028..29335d5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -260,7 +260,7 @@
     virtual bool getBootDisplayModeSupport() = 0;
     virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
     virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
-    virtual hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
+    virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
 };
 
 namespace impl {
@@ -391,7 +391,7 @@
     bool getBootDisplayModeSupport() override;
     status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
     status_t clearBootDisplayMode(PhysicalDisplayId) override;
-    hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) override;
+    std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
 
     // for debugging ----------------------------------------------------------
     void dump(std::string& out) const override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 61da45d..3459a8f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2523,6 +2523,7 @@
     mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
 
     if (isDisplayConnected && !display->isPoweredOn()) {
+        getRenderEngine().cleanupPostRender();
         return;
     }