diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
| -rw-r--r-- | libs/hwui/Readback.cpp | 41 | ||||
| -rw-r--r-- | libs/hwui/SkiaInterpolator.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/Tonemapper.cpp | 107 | ||||
| -rw-r--r-- | libs/hwui/Tonemapper.h | 28 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/LayerDrawable.cpp | 61 |
6 files changed, 172 insertions, 68 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index c0a4fdf5eb74..88cfed9357d8 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -589,6 +589,7 @@ cc_defaults { "ProfileData.cpp", "ProfileDataContainer.cpp", "Readback.cpp", + "Tonemapper.cpp", "TreeInfo.cpp", "WebViewFunctorManager.cpp", "protos/graphicsstats.proto", diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 02c2e67a319b..8dcd6dbe6421 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -16,16 +16,6 @@ #include "Readback.h" -#include <sync/sync.h> -#include <system/window.h> - -#include <gui/TraceUtils.h> -#include "DeferredLayerUpdater.h" -#include "Properties.h" -#include "hwui/Bitmap.h" -#include "pipeline/skia/LayerDrawable.h" -#include "renderthread/EglManager.h" -#include "renderthread/VulkanManager.h" #include <SkBitmap.h> #include <SkBlendMode.h> #include <SkCanvas.h> @@ -38,6 +28,19 @@ #include <SkRefCnt.h> #include <SkSamplingOptions.h> #include <SkSurface.h> +#include <gui/TraceUtils.h> +#include <private/android/AHardwareBufferHelpers.h> +#include <shaders/shaders.h> +#include <sync/sync.h> +#include <system/window.h> + +#include "DeferredLayerUpdater.h" +#include "Properties.h" +#include "Tonemapper.h" +#include "hwui/Bitmap.h" +#include "pipeline/skia/LayerDrawable.h" +#include "renderthread/EglManager.h" +#include "renderthread/VulkanManager.h" #include "utils/Color.h" #include "utils/MathUtils.h" #include "utils/NdkUtils.h" @@ -91,8 +94,18 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy } } - sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace( - static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window))); + int32_t dataspace = ANativeWindow_getBuffersDataSpace(window); + + // If the application is not updating the Surface themselves, e.g., another + // process is producing buffers for the application to display, then + // ANativeWindow_getBuffersDataSpace will return an unknown answer, so grab + // the dataspace from buffer metadata instead, if it exists. + if (dataspace == 0) { + dataspace = AHardwareBuffer_getDataSpace(sourceBuffer.get()); + } + + sk_sp<SkColorSpace> colorSpace = + DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace)); sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace); @@ -227,6 +240,10 @@ void Readback::copySurfaceInto(ANativeWindow* window, const std::shared_ptr<Copy const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom; auto constraint = hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint; + + static constexpr float kMaxLuminanceNits = 4000.f; + tonemapPaint(image->imageInfo(), canvas->imageInfo(), kMaxLuminanceNits, paint); + canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint); canvas->restore(); diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp index 0695dd1ab218..153c3b6f7e04 100644 --- a/libs/hwui/SkiaInterpolator.cpp +++ b/libs/hwui/SkiaInterpolator.cpp @@ -17,6 +17,8 @@ #include "SkiaInterpolator.h" #include "include/core/SkMath.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypes.h" #include "include/private/SkFixed.h" #include "include/private/SkMalloc.h" #include "include/private/SkTo.h" diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp new file mode 100644 index 000000000000..a7e76b631140 --- /dev/null +++ b/libs/hwui/Tonemapper.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Tonemapper.h" + +#include <SkRuntimeEffect.h> +#include <log/log.h> +#include <shaders/shaders.h> + +#include "utils/Color.h" + +namespace android::uirenderer { + +namespace { + +class ColorFilterRuntimeEffectBuilder : public SkRuntimeEffectBuilder { +public: + explicit ColorFilterRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect) + : SkRuntimeEffectBuilder(std::move(effect)) {} + + sk_sp<SkColorFilter> makeColorFilter() { + return this->effect()->makeColorFilter(this->uniforms()); + } +}; + +static sk_sp<SkColorFilter> createLinearEffectColorFilter(const shaders::LinearEffect& linearEffect, + float maxDisplayLuminance, + float currentDisplayLuminanceNits, + float maxLuminance) { + auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect)); + auto [runtimeEffect, error] = SkRuntimeEffect::MakeForColorFilter(std::move(shaderString)); + if (!runtimeEffect) { + LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str()); + } + + ColorFilterRuntimeEffectBuilder effectBuilder(std::move(runtimeEffect)); + + const auto uniforms = + shaders::buildLinearEffectUniforms(linearEffect, android::mat4(), maxDisplayLuminance, + currentDisplayLuminanceNits, maxLuminance); + + for (const auto& uniform : uniforms) { + effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size()); + } + + return effectBuilder.makeColorFilter(); +} + +static bool extractTransfer(ui::Dataspace dataspace) { + return dataspace & HAL_DATASPACE_TRANSFER_MASK; +} + +static bool isHdrDataspace(ui::Dataspace dataspace) { + const auto transfer = extractTransfer(dataspace); + + return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG; +} + +static ui::Dataspace getDataspace(const SkImageInfo& image) { + return static_cast<ui::Dataspace>( + ColorSpaceToADataSpace(image.colorSpace(), image.colorType())); +} + +} // namespace + +// Given a source and destination image info, and the max content luminance, generate a tonemaping +// shader and tag it on the supplied paint. +void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, float maxLuminanceNits, + SkPaint& paint) { + const auto sourceDataspace = getDataspace(source); + const auto destinationDataspace = getDataspace(destination); + + if (extractTransfer(sourceDataspace) != extractTransfer(destinationDataspace) && + (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace))) { + const auto effect = shaders::LinearEffect{ + .inputDataspace = sourceDataspace, + .outputDataspace = destinationDataspace, + .undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType, + .fakeInputDataspace = destinationDataspace, + .type = shaders::LinearEffect::SkSLType::ColorFilter}; + constexpr float kMaxDisplayBrightnessNits = 1000.f; + constexpr float kCurrentDisplayBrightnessNits = 500.f; + sk_sp<SkColorFilter> colorFilter = createLinearEffectColorFilter( + effect, kMaxDisplayBrightnessNits, kCurrentDisplayBrightnessNits, maxLuminanceNits); + + if (paint.getColorFilter()) { + paint.setColorFilter(SkColorFilters::Compose(paint.refColorFilter(), colorFilter)); + } else { + paint.setColorFilter(colorFilter); + } + } +} + +} // namespace android::uirenderer diff --git a/libs/hwui/Tonemapper.h b/libs/hwui/Tonemapper.h new file mode 100644 index 000000000000..c0d5325fa9f8 --- /dev/null +++ b/libs/hwui/Tonemapper.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <SkCanvas.h> + +namespace android::uirenderer { + +// Given a source and destination image info, and the max content luminance, generate a tonemaping +// shader and tag it on the supplied paint. +void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, float maxLuminanceNits, + SkPaint& paint); + +} // namespace android::uirenderer diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 3ba540921f64..99f54c19d2e5 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -25,6 +25,7 @@ #include "SkColorFilter.h" #include "SkRuntimeEffect.h" #include "SkSurface.h" +#include "Tonemapper.h" #include "gl/GrGLTypes.h" #include "math/mat4.h" #include "system/graphics-base-v1.0.h" @@ -76,37 +77,6 @@ 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 currentDisplayLuminanceNits, - 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, currentDisplayLuminanceNits, maxLuminance); - - for (const auto& uniform : uniforms) { - effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size()); - } - - return effectBuilder.makeShader(); -} - -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; -} - static void adjustCropForYUV(uint32_t format, int bufferWidth, int bufferHeight, SkRect* cropRect) { // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an @@ -215,31 +185,10 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context, sampling = SkSamplingOptions(SkFilterMode::kLinear); } - 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; - constexpr float kCurrentDisplayBrightness = 500.f; - shader = createLinearEffectShader(std::move(shader), effect, kMaxDisplayBrightess, - kCurrentDisplayBrightness, - layer->getMaxLuminanceNits()); - paint.setShader(shader); - canvas->drawRect(skiaDestRect, paint); - } else { - canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint, - constraint); - } + tonemapPaint(layerImage->imageInfo(), canvas->imageInfo(), layer->getMaxLuminanceNits(), + paint); + canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint, + constraint); canvas->restore(); // restore the original matrix |