diff options
22 files changed, 443 insertions, 66 deletions
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp index 601a5f9b33..2de023e5b2 100644 --- a/libs/gui/ScreenCaptureResults.cpp +++ b/libs/gui/ScreenCaptureResults.cpp @@ -40,6 +40,13 @@ status_t ScreenCaptureResults::writeToParcel(android::Parcel* parcel) const { SAFE_PARCEL(parcel->writeBool, capturedSecureLayers); SAFE_PARCEL(parcel->writeBool, capturedHdrLayers); SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace)); + if (optionalGainMap != nullptr) { + SAFE_PARCEL(parcel->writeBool, true); + SAFE_PARCEL(parcel->write, *optionalGainMap); + } else { + SAFE_PARCEL(parcel->writeBool, false); + } + SAFE_PARCEL(parcel->writeFloat, hdrSdrRatio); return NO_ERROR; } @@ -68,6 +75,14 @@ status_t ScreenCaptureResults::readFromParcel(const android::Parcel* parcel) { uint32_t dataspace = 0; SAFE_PARCEL(parcel->readUint32, &dataspace); capturedDataspace = static_cast<ui::Dataspace>(dataspace); + + bool hasGainmap; + SAFE_PARCEL(parcel->readBool, &hasGainmap); + if (hasGainmap) { + optionalGainMap = new GraphicBuffer(); + SAFE_PARCEL(parcel->read, *optionalGainMap); + } + SAFE_PARCEL(parcel->readFloat, &hdrSdrRatio); return NO_ERROR; } diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 2bbed2b9d6..4920344e0e 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -69,5 +69,10 @@ parcelable CaptureArgs { // exact colorspace is not an appropriate intermediate result. // Note that if the caller is requesting a specific dataspace, this hint does nothing. boolean hintForSeamlessTransition = false; + + // Allows the screenshot to attach a gainmap, which allows for a per-pixel + // transformation of the screenshot to another luminance range, typically + // mapping an SDR base image into HDR. + boolean attachGainmap = false; } diff --git a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl index 97a903515b..f4ef16dc71 100644 --- a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl +++ b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl @@ -16,4 +16,4 @@ package android.gui; -parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults";
\ No newline at end of file +parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults"; diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h index 6e17791a29..f176f48fb4 100644 --- a/libs/gui/include/gui/ScreenCaptureResults.h +++ b/libs/gui/include/gui/ScreenCaptureResults.h @@ -36,6 +36,11 @@ public: bool capturedSecureLayers{false}; bool capturedHdrLayers{false}; ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB}; + // A gainmap that can be used to "lift" the screenshot into HDR + sp<GraphicBuffer> optionalGainMap; + // HDR/SDR ratio value that fully applies the gainmap. + // Note that we use 1/64 epsilon offsets to eliminate precision issues + float hdrSdrRatio{1.0f}; }; } // namespace android::gui diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 7639fab3a5..d248ea0b84 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -100,6 +100,7 @@ filegroup { "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", + "skia/filters/GainmapFactory.cpp", "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurDualFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index bc3976d9f1..907590a236 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -21,6 +21,7 @@ #include "skia/GraphiteVkRenderEngine.h" #include "skia/SkiaGLRenderEngine.h" #include "threaded/RenderEngineThreaded.h" +#include "ui/GraphicTypes.h" #include <com_android_graphics_surfaceflinger_flags.h> #include <cutils/properties.h> @@ -101,17 +102,34 @@ ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); std::future<FenceResult> resultFuture = resultPromise->get_future(); - updateProtectedContext(layers, buffer); + updateProtectedContext(layers, {buffer.get()}); drawLayersInternal(std::move(resultPromise), display, layers, buffer, std::move(bufferFence)); return resultFuture; } +ftl::Future<FenceResult> RenderEngine::drawGainmap( + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); + updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); + drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + return resultFuture; +} + void RenderEngine::updateProtectedContext(const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer) { + vector<const ExternalTexture*> buffers) { const bool needsProtectedContext = - (buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED)) || - std::any_of(layers.begin(), layers.end(), [](const LayerSettings& layer) { - const std::shared_ptr<ExternalTexture>& buffer = layer.source.buffer.buffer; + std::any_of(layers.begin(), layers.end(), + [](const LayerSettings& layer) { + const std::shared_ptr<ExternalTexture>& buffer = + layer.source.buffer.buffer; + return buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + }) || + std::any_of(buffers.begin(), buffers.end(), [](const ExternalTexture* buffer) { return buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); }); useProtectedContext(needsProtectedContext); diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index b640983a55..280ec19a4c 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -102,6 +102,9 @@ struct DisplaySettings { Local, }; TonemapStrategy tonemapStrategy = TonemapStrategy::Libtonemap; + + // For now, meaningful primarily when the TonemappingStrategy is Local + float targetHdrSdrRatio = 1.f; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 9bc2c48a8a..1954fc52e9 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -208,6 +208,13 @@ public: const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence); + virtual ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap); + // Clean-up method that should be called on the main thread after the // drawFence returned by drawLayers fires. This method will free up // resources used by the most recently drawn frame. If the frame is still @@ -285,8 +292,7 @@ protected: // Update protectedContext mode depending on whether or not any layer has a protected buffer. void updateProtectedContext(const std::vector<LayerSettings>&, - const std::shared_ptr<ExternalTexture>&); - + std::vector<const ExternalTexture*>); // Attempt to switch RenderEngine into and out of protectedContext mode virtual void useProtectedContext(bool useProtectedContext) = 0; @@ -294,6 +300,13 @@ protected: const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) = 0; + + virtual void drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) = 0; }; struct RenderEngineCreationArgs { diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a8c242a86f..fb8331d870 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -46,6 +46,17 @@ public: ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, base::unique_fd&&)); + MOCK_METHOD7(drawGainmap, + ftl::Future<FenceResult>(const std::shared_ptr<ExternalTexture>&, + base::borrowed_fd&&, + const std::shared_ptr<ExternalTexture>&, + base::borrowed_fd&&, float, ui::Dataspace, + const std::shared_ptr<ExternalTexture>&)); + MOCK_METHOD8(drawGainmapInternal, + void(const std::shared_ptr<std::promise<FenceResult>>&&, + const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, + const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, + ui::Dataspace, const std::shared_ptr<ExternalTexture>&)); MOCK_METHOD5(drawLayersInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index d58f303e70..426ccd651d 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -75,6 +75,7 @@ #include "ColorSpaces.h" #include "compat/SkiaGpuContext.h" #include "filters/BlurFilter.h" +#include "filters/GainmapFactory.h" #include "filters/GaussianBlurFilter.h" #include "filters/KawaseBlurDualFilter.h" #include "filters/KawaseBlurFilter.h" @@ -238,12 +239,22 @@ static inline SkM44 getSkM44(const android::mat4& matrix) { static inline SkPoint3 getSkPoint3(const android::vec3& vector) { return SkPoint3::Make(vector.x, vector.y, vector.z); } + } // namespace namespace android { namespace renderengine { namespace skia { +namespace { +void trace(sp<Fence> fence) { + if (SFTRACE_ENABLED()) { + static gui::FenceMonitor sMonitor("RE Completion"); + sMonitor.queueFence(std::move(fence)); + } +} +} // namespace + using base::StringAppendF; std::future<void> SkiaRenderEngine::primeCache(PrimeCacheConfig config) { @@ -544,13 +555,15 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( const auto usingLocalTonemap = parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local && hdrType != HdrRenderType::SDR && - shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr); - + shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr) && + (hdrType != HdrRenderType::DISPLAY_HDR || + parameters.display.targetHdrSdrRatio < parameters.layerDimmingRatio); if (usingLocalTonemap) { - static MouriMap kMapper; - const float ratio = + const float inputRatio = hdrType == HdrRenderType::GENERIC_HDR ? 1.0f : parameters.layerDimmingRatio; - shader = kMapper.mouriMap(getActiveContext(), shader, ratio); + static MouriMap kMapper; + shader = kMapper.mouriMap(getActiveContext(), shader, inputRatio, + parameters.display.targetHdrSdrRatio); } // disable tonemapping if we already locally tonemapped @@ -1187,11 +1200,48 @@ void SkiaRenderEngine::drawLayersInternal( LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); + trace(drawFence); + resultPromise->set_value(std::move(drawFence)); +} - if (SFTRACE_ENABLED()) { - static gui::FenceMonitor sMonitor("RE Completion"); - sMonitor.queueFence(drawFence); - } +void SkiaRenderEngine::drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + std::lock_guard<std::mutex> lock(mRenderingMutex); + auto context = getActiveContext(); + auto surfaceTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); + sk_sp<SkSurface> dstSurface = + surfaceTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); + + waitFence(context, sdrFence); + const auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), false); + const auto sdrImage = sdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); + const auto sdrShader = + sdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + nullptr); + waitFence(context, hdrFence); + const auto hdrTextureRef = getOrCreateBackendTexture(hdr->getBuffer(), false); + const auto hdrImage = hdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); + const auto hdrShader = + hdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + nullptr); + + static GainmapFactory kGainmapFactory; + const auto gainmapShader = kGainmapFactory.createSkShader(sdrShader, hdrShader, hdrSdrRatio); + + const auto canvas = dstSurface->getCanvas(); + SkPaint paint; + paint.setShader(gainmapShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); + trace(drawFence); resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 224a1cad92..faa3fb5249 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -143,6 +143,13 @@ private: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override final; + void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override final; void dump(std::string& result) override final; diff --git a/libs/renderengine/skia/filters/GainmapFactory.cpp b/libs/renderengine/skia/filters/GainmapFactory.cpp new file mode 100644 index 0000000000..e4d4fe96f8 --- /dev/null +++ b/libs/renderengine/skia/filters/GainmapFactory.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2024 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 "GainmapFactory.h" + +#include <log/log.h> + +namespace android { +namespace renderengine { +namespace skia { +namespace { + +sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl) { + auto [effect, error] = SkRuntimeEffect::MakeForShader(sksl); + LOG_ALWAYS_FATAL_IF(!effect, "RuntimeShader error: %s", error.c_str()); + return effect; +} + +// Please refer to https://developer.android.com/media/platform/hdr-image-format#gain_map-generation +static const SkString kGainmapShader = SkString(R"( + uniform shader sdr; + uniform shader hdr; + uniform float mapMaxLog2; + + const float mapMinLog2 = 0.0; + const float mapGamma = 1.0; + const float offsetSdr = 0.015625; + const float offsetHdr = 0.015625; + + float luminance(vec3 linearColor) { + return 0.2126 * linearColor.r + 0.7152 * linearColor.g + 0.0722 * linearColor.b; + } + + vec4 main(vec2 xy) { + float sdrY = luminance(toLinearSrgb(sdr.eval(xy).rgb)); + float hdrY = luminance(toLinearSrgb(hdr.eval(xy).rgb)); + float pixelGain = (hdrY + offsetHdr) / (sdrY + offsetSdr); + float logRecovery = (log2(pixelGain) - mapMinLog2) / (mapMaxLog2 - mapMinLog2); + return vec4(pow(clamp(logRecovery, 0.0, 1.0), mapGamma)); + } +)"); +} // namespace + +const float INTERPOLATION_STRENGTH_VALUE = 0.7f; + +GainmapFactory::GainmapFactory() : mEffect(makeEffect(kGainmapShader)) {} + +sk_sp<SkShader> GainmapFactory::createSkShader(const sk_sp<SkShader>& sdr, + const sk_sp<SkShader>& hdr, float hdrSdrRatio) { + SkRuntimeShaderBuilder shaderBuilder(mEffect); + shaderBuilder.child("sdr") = sdr; + shaderBuilder.child("hdr") = hdr; + shaderBuilder.uniform("mapMaxLog2") = std::log2(hdrSdrRatio); + return shaderBuilder.makeShader(); +} + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/GainmapFactory.h b/libs/renderengine/skia/filters/GainmapFactory.h new file mode 100644 index 0000000000..7aea5e2195 --- /dev/null +++ b/libs/renderengine/skia/filters/GainmapFactory.h @@ -0,0 +1,44 @@ +/* + * Copyright 2024 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 <SkRuntimeEffect.h> +#include <SkShader.h> + +namespace android { +namespace renderengine { +namespace skia { + +/** + * Generates a shader for computing a gainmap, given an SDR base image and its idealized HDR + * rendition. The shader follows the procedure in the UltraHDR spec: + * https://developer.android.com/media/platform/hdr-image-format#gain_map-generation, but makes some + * simplifying assumptions about metadata typical for RenderEngine's usage. + */ +class GainmapFactory { +public: + GainmapFactory(); + // Generates the gainmap shader. The hdrSdrRatio is the max_content_boost in the UltraHDR + // specification. + sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& sdr, const sk_sp<SkShader>& hdr, + float hdrSdrRatio); + +private: + sk_sp<SkRuntimeEffect> mEffect; +}; +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/MouriMap.cpp b/libs/renderengine/skia/filters/MouriMap.cpp index b45893919c..b099bcf3d7 100644 --- a/libs/renderengine/skia/filters/MouriMap.cpp +++ b/libs/renderengine/skia/filters/MouriMap.cpp @@ -67,7 +67,7 @@ const SkString kBlur(R"( float result = 0.0; for (int y = -2; y <= 2; y++) { for (int x = -2; x <= 2; x++) { - result += C[y + 2] * C[x + 2] * bitmap.eval(xy + vec2(x, y)).r; + result += C[y + 2] * C[x + 2] * bitmap.eval(xy + vec2(x, y)).r; } } return float4(float3(exp2(result)), 1.0); @@ -78,18 +78,20 @@ const SkString kTonemap(R"( uniform shader lux; uniform float scaleFactor; uniform float hdrSdrRatio; + uniform float targetHdrSdrRatio; vec4 main(vec2 xy) { float localMax = lux.eval(xy * scaleFactor).r; float4 rgba = image.eval(xy); float3 linear = toLinearSrgb(rgba.rgb) * hdrSdrRatio; - if (localMax <= 1.0) { + if (localMax <= targetHdrSdrRatio) { return float4(fromLinearSrgb(linear), rgba.a); } float maxRGB = max(linear.r, max(linear.g, linear.b)); localMax = max(localMax, maxRGB); - float gain = (1 + maxRGB / (localMax * localMax)) / (1 + maxRGB); + float gain = (1 + maxRGB * (targetHdrSdrRatio / (localMax * localMax))) + / (1 + maxRGB / targetHdrSdrRatio); return float4(fromLinearSrgb(linear * gain), rgba.a); } )"); @@ -114,10 +116,10 @@ MouriMap::MouriMap() mTonemap(makeEffect(kTonemap)) {} sk_sp<SkShader> MouriMap::mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio) { + float hdrSdrRatio, float targetHdrSdrRatio) { auto downchunked = downchunk(context, input, hdrSdrRatio); auto localLux = blur(context, downchunked.get()); - return tonemap(input, localLux.get(), hdrSdrRatio); + return tonemap(input, localLux.get(), hdrSdrRatio, targetHdrSdrRatio); } sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, @@ -166,8 +168,8 @@ sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const { LOG_ALWAYS_FATAL_IF(!blurSurface, "%s: Failed to create surface!", __func__); return makeImage(blurSurface.get(), blurBuilder); } -sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, - float hdrSdrRatio) const { +sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, + float targetHdrSdrRatio) const { static constexpr float kScaleFactor = 1.0f / 128.0f; SkRuntimeShaderBuilder tonemapBuilder(mTonemap); tonemapBuilder.child("image") = input; @@ -176,8 +178,9 @@ sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); tonemapBuilder.uniform("scaleFactor") = kScaleFactor; tonemapBuilder.uniform("hdrSdrRatio") = hdrSdrRatio; + tonemapBuilder.uniform("targetHdrSdrRatio") = targetHdrSdrRatio; return tonemapBuilder.makeShader(); } } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/skia/filters/MouriMap.h b/libs/renderengine/skia/filters/MouriMap.h index 3c0df8abf0..9ba2b6ff9d 100644 --- a/libs/renderengine/skia/filters/MouriMap.h +++ b/libs/renderengine/skia/filters/MouriMap.h @@ -64,13 +64,16 @@ public: // Apply the MouriMap tonemmaping operator to the input. // The HDR/SDR ratio describes the luminace range of the input. 1.0 means SDR. Anything larger // then 1.0 means that there is headroom above the SDR region. - sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float hdrSdrRatio); + // Similarly, the target HDR/SDR ratio describes the luminance range of the output. + sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputHdrSdrRatio, + float targetHdrSdrRatio); private: sk_sp<SkImage> downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, float hdrSdrRatio) const; sk_sp<SkImage> blur(SkiaGpuContext* context, SkImage* input) const; - sk_sp<SkShader> tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio) const; + sk_sp<SkShader> tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, + float targetHdrSdrRatio) const; const sk_sp<SkRuntimeEffect> mCrosstalkAndChunk16x16; const sk_sp<SkRuntimeEffect> mChunk8x8; const sk_sp<SkRuntimeEffect> mBlur; @@ -78,4 +81,4 @@ private: }; } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index f5a90fdcfd..c187f93089 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -249,6 +249,16 @@ void RenderEngineThreaded::drawLayersInternal( return; } +void RenderEngineThreaded::drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + resultPromise->set_value(Fence::NO_FENCE); + return; +} + ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) { @@ -262,7 +272,7 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( mFunctionCalls.push( [resultPromise, display, layers, buffer, fd](renderengine::RenderEngine& instance) { SFTRACE_NAME("REThreaded::drawLayers"); - instance.updateProtectedContext(layers, buffer); + instance.updateProtectedContext(layers, {buffer.get()}); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, base::unique_fd(fd)); }); @@ -271,6 +281,30 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( return resultFuture; } +ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + SFTRACE_CALL(); + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); + { + std::lock_guard lock(mThreadMutex); + mNeedsPostRenderCleanup = true; + mFunctionCalls.push([resultPromise, sdr, sdrFence = std::move(sdrFence), hdr, + hdrFence = std::move(hdrFence), hdrSdrRatio, dataspace, + gainmap](renderengine::RenderEngine& instance) mutable { + SFTRACE_NAME("REThreaded::drawGainmap"); + instance.updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); + instance.drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + }); + } + mCondition.notify_one(); + return resultFuture; +} + int RenderEngineThreaded::getContextPriority() { std::promise<int> resultPromise; std::future<int> resultFuture = resultPromise.get_future(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index d4997d6c93..cb6e924d81 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -55,6 +55,12 @@ public: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; + ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override; int getContextPriority() override; bool supportsBackgroundBlur() override; @@ -71,6 +77,13 @@ protected: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; + void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override; private: void threadMain(CreateInstanceFactory factory); diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 7712d38f43..06c2f26a6d 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -346,6 +346,7 @@ void RegionSamplingThread::captureSample() { constexpr bool kRegionSampling = true; constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; + constexpr bool kAttachGainmap = false; SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, @@ -358,15 +359,15 @@ void RegionSamplingThread::captureSample() { std::vector<sp<LayerFE>> layerFEs; auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); - fenceResult = - mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, - kIsProtected, nullptr, displayState, layerFEs) - .get(); + fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, + kGrayscale, kIsProtected, kAttachGainmap, nullptr, + displayState, layerFEs) + .get(); } else { - fenceResult = - mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, buffer, - kRegionSampling, kGrayscale, kIsProtected, nullptr) - .get(); + fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, + buffer, kRegionSampling, kGrayscale, + kIsProtected, kAttachGainmap, nullptr) + .get(); } if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 8bb72b8470..41a9a1bb22 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -93,6 +93,12 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp if (mEnableLocalTonemapping) { clientCompositionDisplay.tonemapStrategy = renderengine::DisplaySettings::TonemapStrategy::Local; + if (static_cast<ui::PixelFormat>(buffer->getPixelFormat()) == ui::PixelFormat::RGBA_FP16) { + clientCompositionDisplay.targetHdrSdrRatio = + getState().displayBrightnessNits / getState().sdrWhitePointNits; + } else { + clientCompositionDisplay.targetHdrSdrRatio = 1.f; + } } return clientCompositionDisplay; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0aad2828cb..7590d981d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7060,7 +7060,8 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, displayWeak, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, + captureArgs.attachGainmap, captureListener); } void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, @@ -7117,7 +7118,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args static_cast<ui::Dataspace>(args.dataspace), displayWeak, options), getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), - kAllowProtected, kGrayscale, captureListener); + kAllowProtected, kGrayscale, args.attachGainmap, captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7228,7 +7229,8 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, + captureArgs.attachGainmap, captureListener); } // Creates a Future release fence for a layer and keeps track of it in a list to @@ -7281,7 +7283,7 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, + bool allowProtected, bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); @@ -7327,9 +7329,9 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); - auto futureFence = - captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, - isProtected, captureListener, displayState, layerFEs); + auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, + grayscale, isProtected, attachGainmap, captureListener, + displayState, layerFEs); futureFence.get(); } else { @@ -7364,7 +7366,7 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil WRITEABLE); auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, - isProtected, captureListener); + isProtected, attachGainmap, captureListener); futureFence.get(); } } @@ -7418,7 +7420,8 @@ std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs( ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) { SFTRACE_CALL(); @@ -7435,19 +7438,87 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } + float displayBrightnessNits = displayState.value().displayBrightnessNits; + float sdrWhitePointNits = displayState.value().sdrWhitePointNits; // Empty vector needed to pass into renderScreenImpl for legacy path std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers; ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, - captureResults, displayState, layers, layerFEs); + renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, + attachGainmap, captureResults, displayState, layers, layerFEs); + + if (captureResults.capturedHdrLayers && attachGainmap && + FlagManager::getInstance().true_hdr_screenshots()) { + sp<GraphicBuffer> hdrBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, + buffer->getUsage(), "screenshot-hdr"); + sp<GraphicBuffer> gainmapBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), 1 /* layerCount */, + buffer->getUsage(), "screenshot-gainmap"); + + const status_t bufferStatus = hdrBuffer->initCheck(); + const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); + + if (bufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", __func__, + bufferStatus); + } else if (gainmapBufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", + __func__, gainmapBufferStatus); + } else { + captureResults.optionalGainMap = gainmapBuffer; + const auto hdrTexture = std::make_shared< + renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + const auto gainmapTexture = std::make_shared< + renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + ScreenCaptureResults unusedResults; + ftl::SharedFuture<FenceResult> hdrRenderFuture = + renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale, + isProtected, attachGainmap, unusedResults, displayState, + layers, layerFEs); + + renderFuture = + ftl::Future(std::move(renderFuture)) + .then([&, hdrRenderFuture = std::move(hdrRenderFuture), + displayBrightnessNits, sdrWhitePointNits, + dataspace = captureResults.capturedDataspace, buffer, hdrTexture, + gainmapTexture](FenceResult fenceResult) -> FenceResult { + if (!fenceResult.ok()) { + return fenceResult; + } + + auto hdrFenceResult = hdrRenderFuture.get(); + + if (!hdrFenceResult.ok()) { + return hdrFenceResult; + } + + return getRenderEngine() + .drawGainmap(buffer, fenceResult.value()->get(), hdrTexture, + hdrFenceResult.value()->get(), + displayBrightnessNits / sdrWhitePointNits, + static_cast<ui::Dataspace>(dataspace), + gainmapTexture) + .get(); + }) + .share(); + }; + } if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. return ftl::Future(std::move(renderFuture)) - .then([captureListener, captureResults = std::move(captureResults)]( - FenceResult fenceResult) mutable -> FenceResult { + .then([captureListener, captureResults = std::move(captureResults), + displayBrightnessNits, + sdrWhitePointNits](FenceResult fenceResult) mutable -> FenceResult { captureResults.fenceResult = std::move(fenceResult); + captureResults.hdrSdrRatio = displayBrightnessNits / sdrWhitePointNits; captureListener->onScreenCaptureCompleted(captureResults); return base::unexpected(NO_ERROR); }) @@ -7459,7 +7530,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) { + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES( @@ -7488,8 +7560,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( auto layerFEs = extractLayerFEs(layers); ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, - isProtected, captureResults, displayState, layers, layerFEs); + renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, + attachGainmap, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. @@ -7519,10 +7591,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( } ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( - std::unique_ptr<const RenderArea> renderArea, - const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, - std::optional<OutputCompositionState>& displayState, + const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, + bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, + ScreenCaptureResults& captureResults, std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) { SFTRACE_CALL(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 282c8cf803..7fb5c36aad 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -869,7 +869,7 @@ private: void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, - bool grayscale, const sp<IScreenCaptureListener>&); + bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>&); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); @@ -883,20 +883,21 @@ private: ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs); ftl::SharedFuture<FenceResult> captureScreenshotLegacy( RenderAreaBuilderVariant, GetLayerSnapshotsFunction, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&); + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>&); ftl::SharedFuture<FenceResult> renderScreenImpl( - std::unique_ptr<const RenderArea>, - const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, - bool grayscale, bool isProtected, ScreenCaptureResults&, - std::optional<OutputCompositionState>& displayState, + const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&, + bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, + ScreenCaptureResults&, std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index a6a275804d..aa9af5d4ca 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -501,9 +501,10 @@ public: auto layers = getLayerSnapshotsFn(); auto layerFEs = mFlinger->extractLayerFEs(layers); - return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling, + return mFlinger->renderScreenImpl(renderArea.get(), buffer, regionSampling, false /* grayscale */, false /* isProtected */, - captureResults, displayState, layers, layerFEs); + false /* attachGainmap */, captureResults, displayState, + layers, layerFEs); } auto getLayerSnapshotsForScreenshotsFn(ui::LayerStack layerStack, uint32_t uid) { |