diff options
author | 2021-11-22 10:09:22 -0800 | |
---|---|---|
committer | 2021-11-24 13:22:57 -0800 | |
commit | d0001fee74b578a285fdfbe565e3dd0e451d2bfa (patch) | |
tree | 31877616cf5b5da71be9db78d63330ccee4c9023 | |
parent | afb5771b0e75ce78394233f9b95e664c8fad7f20 (diff) |
Support HDR tonemapping in TextureView
This reuses the HDR tonemapping curve that was used in RenderEngine,
however display-level metadata may not be aligned. But because there are
no composition changes that can cause flicker, e.g., switching rapidly
between using a TextureView and a SurfaceView, then that should be okay.
That means that the HDR tonemapping is not as high quality as it could
be, but it is much better than before.
Bug: 200309590
Test: builds, boots
Test: Instagram video preview
Change-Id: I4dd042333f383f383d568b6f2326ee14facd08ed
-rw-r--r-- | libs/hwui/Android.bp | 4 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 27 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 2 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 11 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/LayerDrawable.cpp | 62 |
5 files changed, 99 insertions, 7 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 491f5f58035a..a2d0103450f5 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -107,6 +107,8 @@ cc_defaults { target: { android: { shared_libs: [ + "android.hardware.graphics.common-V3-ndk", + "android.hardware.graphics.common@1.2", "liblog", "libcutils", "libutils", @@ -126,9 +128,11 @@ cc_defaults { static_libs: [ "libEGL_blobCache", "libprotoutil", + "libshaders", "libstatslog_hwui", "libstatspull_lazy", "libstatssocket_lazy", + "libtonemap", ], }, host: { diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 0b3b39397ee4..a5c0924579eb 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -20,9 +20,11 @@ // TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. #include <surfacetexture/surface_texture_platform.h> + #include "AutoBackendTextureRelease.h" #include "Matrix.h" #include "Properties.h" +#include "android/hdr_metadata.h" #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "renderthread/RenderThread.h" @@ -147,6 +149,9 @@ void DeferredLayerUpdater::apply() { mUpdateTexImage = false; float transformMatrix[16]; android_dataspace dataspace; + AHdrMetadataType hdrMetadataType; + android_cta861_3_metadata cta861_3; + android_smpte2086_metadata smpte2086; int slot; bool newContent = false; ARect currentCrop; @@ -155,8 +160,9 @@ void DeferredLayerUpdater::apply() { // is necessary if the SurfaceTexture queue is in synchronous mode, and we // cannot tell which mode it is in. AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer( - mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &outTransform, - &newContent, createReleaseFence, fenceWait, this, ¤tCrop); + mSurfaceTexture.get(), &slot, &dataspace, &hdrMetadataType, &cta861_3, + &smpte2086, transformMatrix, &outTransform, &newContent, createReleaseFence, + fenceWait, this, ¤tCrop); if (hardwareBuffer) { mCurrentSlot = slot; @@ -173,7 +179,18 @@ void DeferredLayerUpdater::apply() { SkRect currentCropRect = SkRect::MakeLTRB(currentCrop.left, currentCrop.top, currentCrop.right, currentCrop.bottom); - updateLayer(forceFilter, layerImage, outTransform, currentCropRect); + + float maxLuminanceNits = -1.f; + if (hdrMetadataType & HDR10_SMPTE2086) { + maxLuminanceNits = std::max(smpte2086.maxLuminance, maxLuminanceNits); + } + + if (hdrMetadataType & HDR10_CTA861_3) { + maxLuminanceNits = + std::max(cta861_3.maxContentLightLevel, maxLuminanceNits); + } + updateLayer(forceFilter, layerImage, outTransform, currentCropRect, + maxLuminanceNits); } } } @@ -186,13 +203,15 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage, - const uint32_t transform, SkRect currentCrop) { + const uint32_t transform, SkRect currentCrop, + float maxLuminanceNits) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); mLayer->setCurrentCropRect(currentCrop); mLayer->setWindowTransform(transform); mLayer->setImage(layerImage); + mLayer->setMaxLuminanceNits(maxLuminanceNits); } void DeferredLayerUpdater::detachSurfaceTexture() { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index da8041f0d0fe..9a4c5505fa35 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -91,7 +91,7 @@ public: void detachSurfaceTexture(); void updateLayer(bool forceFilter, const sk_sp<SkImage>& layerImage, const uint32_t transform, - SkRect currentCrop); + SkRect currentCrop, float maxLuminanceNits = -1.f); void destroyLayer(); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 0789344f970e..47eb5d3bfb83 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -96,6 +96,12 @@ public: inline sk_sp<SkImage> getImage() const { return this->layerImage; } + inline void setMaxLuminanceNits(float maxLuminanceNits) { + mMaxLuminanceNits = maxLuminanceNits; + } + + inline float getMaxLuminanceNits() { return mMaxLuminanceNits; } + void draw(SkCanvas* canvas); protected: @@ -158,6 +164,11 @@ private: */ bool mBlend = false; + /** + * Max input luminance if the layer is HDR + */ + float mMaxLuminanceNits = -1; + }; // struct Layer } // namespace uirenderer diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 14396569ccdd..553b08febdcc 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -15,12 +15,19 @@ */ #include "LayerDrawable.h" + +#include <shaders/shaders.h> +#include <utils/Color.h> #include <utils/MathUtils.h> +#include "DeviceInfo.h" #include "GrBackendSurface.h" #include "SkColorFilter.h" +#include "SkRuntimeEffect.h" #include "SkSurface.h" #include "gl/GrGLTypes.h" +#include "math/mat4.h" +#include "system/graphics-base-v1.0.h" #include "system/window.h" namespace android { @@ -69,6 +76,35 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons isIntegerAligned(dstDevRect.y())); } +static sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, + const shaders::LinearEffect& linearEffect, + float maxDisplayLuminance, float maxLuminance) { + auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect)); + auto [runtimeEffect, error] = SkRuntimeEffect::MakeForShader(std::move(shaderString)); + if (!runtimeEffect) { + LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str()); + } + + SkRuntimeShaderBuilder effectBuilder(std::move(runtimeEffect)); + + effectBuilder.child("child") = std::move(shader); + + const auto uniforms = shaders::buildLinearEffectUniforms(linearEffect, mat4(), + maxDisplayLuminance, maxLuminance); + + for (const auto& uniform : uniforms) { + effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size()); + } + + return effectBuilder.makeShader(nullptr, false); +} + +static bool isHdrDataspace(ui::Dataspace dataspace) { + const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK; + + return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG; +} + // TODO: Context arg probably doesn't belong here – do debug check at callsite instead. bool LayerDrawable::DrawLayer(GrRecordingContext* context, SkCanvas* canvas, @@ -150,8 +186,30 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context, sampling = SkSamplingOptions(SkFilterMode::kLinear); } - canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint, - constraint); + const auto sourceDataspace = static_cast<ui::Dataspace>( + ColorSpaceToADataSpace(layerImage->colorSpace(), layerImage->colorType())); + const SkImageInfo& imageInfo = canvas->imageInfo(); + const auto destinationDataspace = static_cast<ui::Dataspace>( + ColorSpaceToADataSpace(imageInfo.colorSpace(), imageInfo.colorType())); + + if (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace)) { + const auto effect = shaders::LinearEffect{ + .inputDataspace = sourceDataspace, + .outputDataspace = destinationDataspace, + .undoPremultipliedAlpha = layerImage->alphaType() == kPremul_SkAlphaType, + .fakeInputDataspace = destinationDataspace}; + auto shader = layerImage->makeShader(sampling, + SkMatrix::RectToRect(skiaSrcRect, skiaDestRect)); + constexpr float kMaxDisplayBrightess = 1000.f; + shader = createLinearEffectShader(std::move(shader), effect, kMaxDisplayBrightess, + layer->getMaxLuminanceNits()); + paint.setShader(shader); + canvas->drawRect(skiaDestRect, paint); + } else { + canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint, + constraint); + } + canvas->restore(); // restore the original matrix if (useLayerTransform) { |