diff options
| author | 2024-03-06 03:09:35 +0000 | |
|---|---|---|
| committer | 2025-01-29 09:58:34 -0800 | |
| commit | c282e18f85c41011ecdf8313aa141398b1cc0400 (patch) | |
| tree | 298386271e1bb96bd09ca215f970bab24fde33c2 | |
| parent | f74bfe1f7ffd47ee51c046b73a3ff403b95ec939 (diff) | |
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
| -rw-r--r-- | libs/ui/include_types/ui/HdrRenderTypeUtils.h | 5 | ||||
| -rw-r--r-- | services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp | 21 |
2 files changed, 19 insertions, 7 deletions
diff --git a/libs/ui/include_types/ui/HdrRenderTypeUtils.h b/libs/ui/include_types/ui/HdrRenderTypeUtils.h index b0af878cdb..87997dd1dc 100644 --- a/libs/ui/include_types/ui/HdrRenderTypeUtils.h +++ b/libs/ui/include_types/ui/HdrRenderTypeUtils.h @@ -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; } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 091c207464..776388be71 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -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) { - layerBrightnessNits *= layerFEState->currentHdrSdrRatio; + if (!FlagManager::getInstance().fp16_client_target() || !isLayerFp16) { + layerBrightnessNits *= layerFEState->currentHdrSdrRatio; + } } + state.dimmingRatio = std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f, 1.f); |