Plumb in local tonemapping flag into renderengine

The detailed local tonemapping implementation will come in a later CL.

Also allow the flag to configure luminance spaces in SF, to prevent
SDR-only regions from dimming.

Bug: 329464641
Test: builds
Change-Id: Ia2bbf12b2cdfb5597137a6028911ff71b3d866d3
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index dd03366..8bb72b8 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -30,7 +30,7 @@
             ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
             const compositionengine::Output::ColorProfile&,
             bool>(args.compositionEngine, args.renderArea, args.colorProfile, args.regionSampling,
-                  args.dimInGammaSpaceForEnhancedScreenshots);
+                  args.dimInGammaSpaceForEnhancedScreenshots, args.enableLocalTonemapping);
     output->editState().isSecure = args.renderArea.isSecure();
     output->editState().isProtected = args.isProtected;
     output->setCompositionEnabled(true);
@@ -63,11 +63,13 @@
 
 ScreenCaptureOutput::ScreenCaptureOutput(
         const RenderArea& renderArea, const compositionengine::Output::ColorProfile& colorProfile,
-        bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots)
+        bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots,
+        bool enableLocalTonemapping)
       : mRenderArea(renderArea),
         mColorProfile(colorProfile),
         mRegionSampling(regionSampling),
-        mDimInGammaSpaceForEnhancedScreenshots(dimInGammaSpaceForEnhancedScreenshots) {}
+        mDimInGammaSpaceForEnhancedScreenshots(dimInGammaSpaceForEnhancedScreenshots),
+        mEnableLocalTonemapping(enableLocalTonemapping) {}
 
 void ScreenCaptureOutput::updateColorProfile(const compositionengine::CompositionRefreshArgs&) {
     auto& outputState = editState();
@@ -88,6 +90,11 @@
                 aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
     }
 
+    if (mEnableLocalTonemapping) {
+        clientCompositionDisplay.tonemapStrategy =
+                renderengine::DisplaySettings::TonemapStrategy::Local;
+    }
+
     return clientCompositionDisplay;
 }
 
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
index 069f458..c233ead 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.h
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -39,6 +39,7 @@
     bool treat170mAsSrgb;
     bool dimInGammaSpaceForEnhancedScreenshots;
     bool isProtected = false;
+    bool enableLocalTonemapping = false;
 };
 
 // ScreenCaptureOutput is used to compose a set of layers into a preallocated buffer.
@@ -49,7 +50,8 @@
 public:
     ScreenCaptureOutput(const RenderArea& renderArea,
                         const compositionengine::Output::ColorProfile& colorProfile,
-                        bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots);
+                        bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots,
+                        bool enableLocalTonemapping);
 
     void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
 
@@ -67,6 +69,7 @@
     const compositionengine::Output::ColorProfile& mColorProfile;
     const bool mRegionSampling;
     const bool mDimInGammaSpaceForEnhancedScreenshots;
+    const bool mEnableLocalTonemapping;
 };
 
 std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 66385d8..95f3799 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -8302,6 +8302,9 @@
 
     captureResults.capturedDataspace = requestedDataspace;
 
+    const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() &&
+            !renderArea->getHintForSeamlessTransition();
+
     {
         Mutex::Autolock lock(mStateLock);
         const DisplayDevice* display = nullptr;
@@ -8335,16 +8338,19 @@
                 displayBrightnessNits = sdrWhitePointNits;
             } else {
                 displayBrightnessNits = state.displayBrightnessNits;
-                // Only clamp the display brightness if this is not a seamless transition. Otherwise
-                // for seamless transitions it's important to match the current display state as the
-                // buffer will be shown under these same conditions, and we want to avoid any
-                // flickers
-                if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) {
-                    // Restrict the amount of HDR "headroom" in the screenshot to avoid over-dimming
-                    // the SDR portion. 2.0 chosen by experimentation
-                    constexpr float kMaxScreenshotHeadroom = 2.0f;
-                    displayBrightnessNits = std::min(sdrWhitePointNits * kMaxScreenshotHeadroom,
-                                                     displayBrightnessNits);
+
+                if (!enableLocalTonemapping) {
+                    // Only clamp the display brightness if this is not a seamless transition.
+                    // Otherwise for seamless transitions it's important to match the current
+                    // display state as the buffer will be shown under these same conditions, and we
+                    // want to avoid any flickers
+                    if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) {
+                        // Restrict the amount of HDR "headroom" in the screenshot to avoid
+                        // over-dimming the SDR portion. 2.0 chosen by experimentation
+                        constexpr float kMaxScreenshotHeadroom = 2.0f;
+                        displayBrightnessNits = std::min(sdrWhitePointNits * kMaxScreenshotHeadroom,
+                                                         displayBrightnessNits);
+                    }
                 }
             }
 
@@ -8376,7 +8382,8 @@
     auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
                     sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected,
                     layerFEs = copyLayerFEs(), layerStack, regionSampling,
-                    renderArea = std::move(renderArea), renderIntent]() -> FenceResult {
+                    renderArea = std::move(renderArea), renderIntent,
+                    enableLocalTonemapping]() -> FenceResult {
         std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
                 mFactory.createCompositionEngine();
         compositionEngine->setRenderEngine(mRenderEngine.get());
@@ -8385,7 +8392,11 @@
                                                              .renderIntent = renderIntent};
 
         float targetBrightness = 1.0f;
-        if (dataspace == ui::Dataspace::BT2020_HLG) {
+        if (enableLocalTonemapping) {
+            // Boost the whole scene so that SDR white is at 1.0 while still communicating the hdr
+            // sdr ratio via display brightness / sdrWhite nits.
+            targetBrightness = sdrWhitePointNits / displayBrightnessNits;
+        } else if (dataspace == ui::Dataspace::BT2020_HLG) {
             const float maxBrightnessNits = displayBrightnessNits / sdrWhitePointNits * 203;
             // With a low dimming ratio, don't fit the entire curve. Otherwise mixed content
             // will appear way too bright.
@@ -8411,7 +8422,8 @@
                                         .treat170mAsSrgb = mTreat170mAsSrgb,
                                         .dimInGammaSpaceForEnhancedScreenshots =
                                                 dimInGammaSpaceForEnhancedScreenshots,
-                                        .isProtected = isProtected});
+                                        .isProtected = isProtected,
+                                        .enableLocalTonemapping = enableLocalTonemapping});
 
         const float colorSaturation = grayscale ? 0 : 1;
         compositionengine::CompositionRefreshArgs refreshArgs{