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

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

Set right dimmingRatio for fp16 input layers without metadata

...since 1.0 == SDR white, we can program these layers by sending
SDR/HDR as the dimmingRatio to map the degamma'd value at HDR/SDR
to the max panel lux.

It's a little counter-intuitive at first glance, because we're sending a
dimming ratio < 1.0 for an HDR layer which looks like we're intending to
dim the layer. But it makes sense just from the math: layer_luminance =
panel_luminance * srgb_EOTF(layer_input) * (SDR_white / panel_luminance) =
srgb_EOTF(layer_input) * SDR_white. For an entirely SDR layer, then the
layer luminance is capped by SDR_white as desired, and for a layer that
was rendered with an HDR/SDR ratio then the layer luminance cancels out
to HDR_white == panel_luminance. And, we *are* dimming the layer: since
for a full range layer 1.0 before this infrastructure was in place would
have mapped to the max panel luminance.

Now, the HDR/SDR ratio may have differed by the time we hit the panel
(the layer is slightly in the past), but assuming the ratio changed slowly:
* If HDR/SDR increased, then we dim the layer a bit more than the
  application intended, but the user does not notice because the SDR
  white point stayed the same; the application just used less headroom
  than it could have.
* If HDR/SDR decreased, then we dim the layer less than the application
  intended, but the panel can just clip

Bug: 236745178
Flag: com.android.graphics.surfaceflinger.flags.fp16_client_target
Test: builds
Test: courage
Change-Id: I85a0d978f994d495e34dfbdd9dc7b03bd64f293c
parent f74bfe1f
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ enum class HdrRenderType {
 */
inline HdrRenderType getHdrRenderType(ui::Dataspace dataspace,
                                      std::optional<ui::PixelFormat> pixelFormat,
                                      float hdrSdrRatio = 1.f) {
                                      float hdrSdrRatio = 1.f, bool hasHdrMetadata = false) {
    const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
    const auto range = dataspace & HAL_DATASPACE_RANGE_MASK;

@@ -49,7 +49,8 @@ inline HdrRenderType getHdrRenderType(ui::Dataspace dataspace,
                                                                     HAL_DATASPACE_RANGE_EXTENDED);

    if ((dataspace == BT2020_LINEAR_EXT || dataspace == ui::Dataspace::V0_SCRGB) &&
        pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16) {
        pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16 &&
        hasHdrMetadata) {
        return HdrRenderType::GENERIC_HDR;
    }

+16 −5
Original line number Diff line number Diff line
@@ -315,8 +315,11 @@ void OutputLayer::updateCompositionState(
                                                      layerFEState->buffer->getPixelFormat()))
                                            : std::nullopt;

    auto hdrRenderType =
            getHdrRenderType(outputState.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
    // prefer querying this from gralloc instead to catch 2094-10 metadata
    const bool hasHdrMetadata = layerFEState->hdrMetadata.validTypes != 0;

    auto hdrRenderType = getHdrRenderType(outputState.dataspace, pixelFormat,
                                          layerFEState->desiredHdrSdrRatio, hasHdrMetadata);

    // Determine the output dependent dataspace for this layer. If it is
    // colorspace agnostic, it just uses the dataspace chosen for the output to
@@ -339,8 +342,8 @@ void OutputLayer::updateCompositionState(
    }

    // re-get HdrRenderType after the dataspace gets changed.
    hdrRenderType =
            getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
    hdrRenderType = getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio,
                                     hasHdrMetadata);

    // For hdr content, treat the white point as the display brightness - HDR content should not be
    // boosted or dimmed.
@@ -351,12 +354,20 @@ void OutputLayer::updateCompositionState(
        state.dimmingRatio = 1.f;
        state.whitePointNits = getOutput().getState().displayBrightnessNits;
    } else {
        const bool isLayerFp16 = pixelFormat && *pixelFormat == ui::PixelFormat::RGBA_FP16;
        float layerBrightnessNits = getOutput().getState().sdrWhitePointNits;
        // RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular
        // range that we may need to re-adjust to the current display conditions
        // Do NOT do this when we may render fp16 to an fp16 client target, to avoid applying
        // and additional gain to the layer. This is because the fp16 client target should
        // already be adapted to remap 1.0 to the SDR white point in the panel's luminance
        // space.
        if (hdrRenderType == HdrRenderType::DISPLAY_HDR) {
            if (!FlagManager::getInstance().fp16_client_target() || !isLayerFp16) {
                layerBrightnessNits *= layerFEState->currentHdrSdrRatio;
            }
        }

        state.dimmingRatio =
                std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f,
                           1.f);