Introduce MouriMap
MouriMap is a local-tonemapping algorithm optimized for near-exact
preservation of SDR/LDR regions, while trying to do a good job of
rendering HDR. MouriMap was designed to run well on mobile hardware.
On a Pixel 8 Pro, MouriMap is able to tonemap screen-sized images
between 20 and 25 milliseconds. This is not fast enough for real-time
rendering at the panel refresh rate. But, this is sufficient for
screenshots, which is the use-case that MouriMap is intended to be
deployed for.
Tests will follow after this patch.
Bug: 329464641
Test: builds, boots
Test: Swipe apps into Recents
Test: adb screenshot
Change-Id: I0ded29b65ccf41940de74cff26d36275bfa46e78
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index ccbf092..d844764 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -79,6 +79,7 @@
#include "filters/GaussianBlurFilter.h"
#include "filters/KawaseBlurFilter.h"
#include "filters/LinearEffect.h"
+#include "filters/MouriMap.h"
#include "log/log_main.h"
#include "skia/compat/SkiaBackendTexture.h"
#include "skia/debug/SkiaCapture.h"
@@ -509,9 +510,9 @@
// Determine later on if we need to leverage the stertch shader within
// surface flinger
const auto& stretchEffect = parameters.layer.stretchEffect;
+ const auto& targetBuffer = parameters.layer.source.buffer.buffer;
auto shader = parameters.shader;
if (stretchEffect.hasEffect()) {
- const auto targetBuffer = parameters.layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
if (graphicBuffer && parameters.shader) {
shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
@@ -519,9 +520,22 @@
}
if (parameters.requiresLinearEffect) {
+ const auto format = targetBuffer != nullptr
+ ? std::optional<ui::PixelFormat>(
+ static_cast<ui::PixelFormat>(targetBuffer->getPixelFormat()))
+ : std::nullopt;
+
if (parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local) {
- // TODO: Apply a local tonemap
- // fallthrough for now
+ // TODO: Handle color matrix transforms in linear space.
+ SkImage* image = parameters.shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr);
+ if (image) {
+ static MouriMap kMapper;
+ const float ratio = getHdrRenderType(parameters.layer.sourceDataspace, format) ==
+ HdrRenderType::GENERIC_HDR
+ ? 1.0f
+ : parameters.layerDimmingRatio;
+ return kMapper.mouriMap(getActiveContext(), parameters.shader, ratio);
+ }
}
auto effect =