diff options
author | 2021-05-17 15:02:03 +0000 | |
---|---|---|
committer | 2021-05-17 15:02:03 +0000 | |
commit | 18c797058c7b4a02a0af26f73115beb448650135 (patch) | |
tree | 7b27f905cd233a98aa83116a61970c3ffc2a9608 | |
parent | 2eef0b65ca535cfecf88d15229273f57f69b5d21 (diff) | |
parent | ac09e45ab3aa3799ff071c8fe97ac4ebe5b9ae5c (diff) |
Merge "Make sdr white point do a thing" into sc-dev
20 files changed, 113 insertions, 34 deletions
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 940003750e..3c582383ca 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1233,8 +1233,10 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } } - mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance; - mState.maxContentLuminance = layer->source.buffer.maxContentLuminance; + // Ensure luminance is at least 100 nits to avoid div-by-zero + const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); + mState.maxMasteringLuminance = maxLuminance; + mState.maxContentLuminance = maxLuminance; mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; const FloatRect bounds = layer->geometry.boundaries; diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index a637796267..53fa622ad8 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -60,6 +60,9 @@ struct DisplaySettings { // capture of a device in landscape while the buffer is in portrait // orientation. uint32_t orientation = ui::Transform::ROT_0; + + // SDR white point, -1f if unknown + float sdrWhitePointNits = -1.f; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 6e983524ce..bfb7465acf 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -64,8 +64,8 @@ struct Buffer { // HDR color-space setting for Y410. bool isY410BT2020 = false; - float maxMasteringLuminance = 0.0; - float maxContentLuminance = 0.0; + + float maxLuminanceNits = 0.0; }; // Metadata describing the layer geometry. @@ -175,8 +175,7 @@ static inline bool operator==(const Buffer& lhs, const Buffer& rhs) { lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxMasteringLuminance == rhs.maxMasteringLuminance && - lhs.maxContentLuminance == rhs.maxContentLuminance; + lhs.maxLuminanceNits == rhs.maxLuminanceNits; } static inline bool operator==(const Geometry& lhs, const Geometry& rhs) { @@ -239,8 +238,7 @@ static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { *os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha; *os << "\n .isOpaque = " << settings.isOpaque; *os << "\n .isY410BT2020 = " << settings.isY410BT2020; - *os << "\n .maxMasteringLuminance = " << settings.maxMasteringLuminance; - *os << "\n .maxContentLuminance = " << settings.maxContentLuminance; + *os << "\n .maxLuminanceNits = " << settings.maxLuminanceNits; *os << "\n}"; } diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 48d76cc475..0eee56443c 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -108,8 +108,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting .source = PixelSource{.buffer = Buffer{ .buffer = srcTexture, - .maxMasteringLuminance = 1000.f, - .maxContentLuminance = 1000.f, + .maxLuminanceNits = 1000.f, }}, }; @@ -205,8 +204,7 @@ static void drawTextureScaleLayers(SkiaRenderEngine* renderengine, const Display .source = PixelSource{.buffer = Buffer{ .buffer = srcTexture, - .maxMasteringLuminance = 1000.f, - .maxContentLuminance = 1000.f, + .maxLuminanceNits = 1000.f, .textureTransform = kScaleYOnly, }}, .sourceDataspace = kOtherDataSpace, diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 6d2af4a77f..05bbc12878 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -590,10 +590,14 @@ sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader( } else { runtimeEffect = effectIter->second; } + float maxLuminance = layer->source.buffer.maxLuminanceNits; + // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR + // white point + if (maxLuminance <= 0.f) { + maxLuminance = display.sdrWhitePointNits; + } return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform, - display.maxLuminance, - layer->source.buffer.maxMasteringLuminance, - layer->source.buffer.maxContentLuminance); + display.maxLuminance, maxLuminance); } return shader; } @@ -904,7 +908,9 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const bool requiresLinearEffect = layer->colorTransform != mat4() || (mUseColorManagement && - needsToneMapping(layer->sourceDataspace, display.outputDataspace)); + needsToneMapping(layer->sourceDataspace, display.outputDataspace)) || + (display.sdrWhitePointNits > 0.f && + display.sdrWhitePointNits != display.maxLuminance); // quick abort from drawing the remaining portion of the layer if (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending && diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 0fbd6698d8..9b044e1685 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -127,7 +127,7 @@ static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkStrin default: shader.append(R"( float3 ScaleLuminance(float3 xyz) { - return xyz * in_displayMaxLuminance; + return xyz * in_inputMaxLuminance; } )"); break; @@ -448,7 +448,7 @@ sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect) { sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect, sk_sp<SkRuntimeEffect> runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, - float maxMasteringLuminance, float maxContentLuminance) { + float maxLuminance) { ATRACE_CALL(); SkRuntimeShaderBuilder effectBuilder(runtimeEffect); @@ -467,8 +467,10 @@ sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEff } effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance; + // 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 uncalibrated displays effectBuilder.uniform("in_inputMaxLuminance") = - std::min(maxMasteringLuminance, maxContentLuminance); + maxLuminance > 0 ? maxLuminance : maxDisplayLuminance; return effectBuilder.makeShader(nullptr, false); } diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h index 20b8338931..9e989eae27 100644 --- a/libs/renderengine/skia/filters/LinearEffect.h +++ b/libs/renderengine/skia/filters/LinearEffect.h @@ -98,7 +98,7 @@ sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader, const LinearEffect& linearEffect, sk_sp<SkRuntimeEffect> runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, - float maxMasteringLuminance, float maxContentLuminance); + float maxLuminance); } // namespace skia } // namespace renderengine } // namespace android diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 4c73b6edda..cacad52410 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -58,8 +58,7 @@ namespace android { -static constexpr float defaultMaxMasteringLuminance = 1000.0; -static constexpr float defaultMaxContentLuminance = 1000.0; +static constexpr float defaultMaxLuminance = 1000.0; BufferLayer::BufferLayer(const LayerCreationArgs& args) : Layer(args), @@ -206,12 +205,24 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli layer.source.buffer.isY410BT2020 = isHdrY410(); bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - layer.source.buffer.maxMasteringLuminance = hasSmpte2086 - ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance - : defaultMaxMasteringLuminance; - layer.source.buffer.maxContentLuminance = hasCta861_3 - ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel - : defaultMaxContentLuminance; + float maxLuminance = 0.f; + if (hasSmpte2086 && hasCta861_3) { + maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance, + mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel); + } else if (hasSmpte2086) { + maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance; + } else if (hasCta861_3) { + maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel; + } else { + switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // Behavior-match previous releases for HDR content + maxLuminance = defaultMaxLuminance; + break; + } + } + layer.source.buffer.maxLuminanceNits = maxLuminance; layer.frameNumber = mCurrentFrameNumber; layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 9fba7aa558..257974f4e9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -184,6 +184,9 @@ public: // Sets the output color mode virtual void setColorProfile(const ColorProfile&) = 0; + // Sets current calibrated display brightness information + virtual void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) = 0; + // Outputs a string with a state dump virtual void dump(std::string&) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 2893c3f910..f10ff2598d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -49,6 +49,7 @@ public: void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; + void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) override; void dump(std::string&) const override; void dumpPlannerInfo(const Vector<String16>& args, std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index f0ef6d6e7d..d41c2dd527 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -118,6 +118,12 @@ struct OutputCompositionState { // The earliest time to send the present command to the HAL std::chrono::steady_clock::time_point earliestPresentTime; + // Current display brightness + float displayBrightnessNits{-1.f}; + + // SDR white point + float sdrWhitePointNits{-1.f}; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 749675d8fd..4b4d37539e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -44,6 +44,7 @@ public: MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); + MOCK_METHOD2(setDisplayBrightness, void(float, float)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD2(dumpPlannerInfo, void(const Vector<String16>&, std::string&)); diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index b1ee3fbf5d..7e020ee1c1 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -46,8 +46,7 @@ inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const rendereng lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxMasteringLuminance == rhs.maxMasteringLuminance && - lhs.maxContentLuminance == rhs.maxContentLuminance; + lhs.maxLuminanceNits == rhs.maxLuminanceNits; } inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs, diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 796fe7dbf0..bf36355fd8 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -259,6 +259,18 @@ void Output::setColorProfile(const ColorProfile& colorProfile) { dirtyEntireOutput(); } +void Output::setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) { + auto& outputState = editState(); + if (outputState.sdrWhitePointNits == sdrWhitePointNits && + outputState.displayBrightnessNits == displayBrightnessNits) { + // Nothing changed + return; + } + outputState.sdrWhitePointNits = sdrWhitePointNits; + outputState.displayBrightnessNits = displayBrightnessNits; + dirtyEntireOutput(); +} + void Output::dump(std::string& out) const { using android::base::StringAppendF; @@ -1035,8 +1047,13 @@ std::optional<base::unique_fd> Output::composeSurfaces( clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() ? outputState.dataspace : ui::Dataspace::UNKNOWN; - clientCompositionDisplay.maxLuminance = - mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); + + // If we have a valid current display brightness use that, otherwise fall back to the + // display's max desired + clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f + ? outputState.displayBrightnessNits + : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); + clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits; // Compute the global color transform matrix. if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 682eff8f8c..4a007ff0fb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -308,6 +308,7 @@ ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat: Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; bool SurfaceFlinger::useFrameRateApi; +bool SurfaceFlinger::enableSdrDimming; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -479,6 +480,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); + + // Debug property overrides ro. property + enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); } SurfaceFlinger::~SurfaceFlinger() = default; @@ -1488,8 +1492,13 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, } return ftl::chain(schedule([=]() MAIN_THREAD { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setDisplayBrightness(*displayId, + if (const auto display = getDisplayDeviceLocked(displayToken)) { + if (enableSdrDimming) { + display->getCompositionDisplay() + ->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.displayBrightnessNits); + } + return getHwComposer().setDisplayBrightness(display->getPhysicalId(), brightness.displayBrightness); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 15b77f147d..da874b6092 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -271,6 +271,10 @@ public: static constexpr SkipInitializationTag SkipInitialization; + // Whether or not SDR layers should be dimmed to the desired SDR white point instead of + // being treated as native display brightness + static bool enableSdrDimming; + // must be called before clients can connect void init() ANDROID_API; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index b3dca789e2..4a69c8f0c3 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -321,6 +321,10 @@ bool use_frame_rate_api(bool defaultValue) { return defaultValue; } +bool enable_sdr_dimming(bool defaultValue) { + return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue); +} + int32_t display_update_imminent_timeout_ms(int32_t defaultValue) { auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index b19d216268..039d316a95 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -102,6 +102,8 @@ bool enable_frame_rate_override(bool defaultValue); bool enable_layer_caching(bool defaultValue); +bool enable_sdr_dimming(bool defaultValue); + } // namespace sysprop } // namespace android #endif // SURFACEFLINGERPROPERTIES_H_ diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index ee5542d628..78f8a2f0ae 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -463,3 +463,12 @@ prop { access: Readonly prop_name: "ro.surface_flinger.enable_layer_caching" } + +# Enables SDR layer dimming +prop { + api_name: "enable_sdr_dimming" + type: Boolean + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.enable_sdr_dimming" +}
\ No newline at end of file diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 47e14f656b..9c567d6afa 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -53,6 +53,10 @@ props { prop_name: "ro.surface_flinger.protected_contents" } prop { + api_name: "enable_sdr_dimming" + prop_name: "ro.surface_flinger.enable_sdr_dimming" + } + prop { api_name: "force_hwc_copy_for_virtual_displays" prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } |