Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7e752e2 authored by Alec Mouri's avatar Alec Mouri
Browse files

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
parent ef7f5d11
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -86,6 +86,22 @@ struct DisplaySettings {
    // Configures the rendering intent of the output display. This is used for tonemapping.
    aidl::android::hardware::graphics::composer3::RenderIntent renderIntent =
            aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC;

    // Tonemapping strategy to use for each layer. This is only used for tonemapping HDR source
    // content
    enum class TonemapStrategy {
        // Use a tonemapper defined by libtonemap. This may be OEM-defined as of Android 13, aka
        // undefined.
        // This is typically a global tonemapper, designed to match what is on screen.
        Libtonemap,
        // Use a local tonemapper. Because local tonemapping uses large intermediate allocations,
        // this
        // method is primarily recommended for infrequent rendering that does not need to exactly
        // match
        // pixels that are on-screen.
        Local,
    };
    TonemapStrategy tonemapStrategy = TonemapStrategy::Libtonemap;
};

static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
+5 −0
Original line number Diff line number Diff line
@@ -519,6 +519,11 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader(
    }

    if (parameters.requiresLinearEffect) {
        if (parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local) {
            // TODO: Apply a local tonemap
            // fallthrough for now
        }

        auto effect =
                shaders::LinearEffect{.inputDataspace = parameters.layer.sourceDataspace,
                                      .outputDataspace = parameters.outputDataSpace,
+10 −3
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp
            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 @@ std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutp

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 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp
                aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
    }

    if (mEnableLocalTonemapping) {
        clientCompositionDisplay.tonemapStrategy =
                renderengine::DisplaySettings::TonemapStrategy::Local;
    }

    return clientCompositionDisplay;
}

+4 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct ScreenCaptureOutputArgs {
    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 @@ class ScreenCaptureOutput : public compositionengine::impl::Output {
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 @@ private:
    const compositionengine::Output::ColorProfile& mColorProfile;
    const bool mRegionSampling;
    const bool mDimInGammaSpaceForEnhancedScreenshots;
    const bool mEnableLocalTonemapping;
};

std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs);
+25 −13
Original line number Diff line number Diff line
@@ -8302,6 +8302,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(

    captureResults.capturedDataspace = requestedDataspace;

    const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() &&
            !renderArea->getHintForSeamlessTransition();

    {
        Mutex::Autolock lock(mStateLock);
        const DisplayDevice* display = nullptr;
@@ -8335,18 +8338,21 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
                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 (!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
                        // 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);
                    }
                }
            }

            // Screenshots leaving the device should be colorimetric
            if (requestedDataspace == ui::Dataspace::UNKNOWN &&
@@ -8376,7 +8382,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
    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 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
                                                             .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 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
                                        .treat170mAsSrgb = mTreat170mAsSrgb,
                                        .dimInGammaSpaceForEnhancedScreenshots =
                                                dimInGammaSpaceForEnhancedScreenshots,
                                        .isProtected = isProtected});
                                        .isProtected = isProtected,
                                        .enableLocalTonemapping = enableLocalTonemapping});

        const float colorSaturation = grayscale ? 0 : 1;
        compositionengine::CompositionRefreshArgs refreshArgs{