Support linear color transforms in Skia-RenderEngine.
Per-layer color transforms are defined by the HWC spec to apply in linear
space immediately before OETF. Support that by passing an additional
matrix into LinearEffect.
Note that this probably is not the most efficient way to do this at
runtime; when tone mapping is not required and RGB primaries are the
same, we can remove an additional matrix computation, but the number of
shaders cached on-device is cut down this way.
Bug: 164223050
Test: Hack in a color transform and compare gles vs skiagl.
Change-Id: If01995a90a4381d811c39c68cff5983b04e2971d
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 74f342a..a0660fb 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -416,6 +416,11 @@
sourceTransfer != destTransfer;
}
+static bool needsLinearEffect(const mat4& colorTransform, ui::Dataspace sourceDataspace,
+ ui::Dataspace destinationDataspace) {
+ return colorTransform != mat4() || needsToneMapping(sourceDataspace, destinationDataspace);
+}
+
void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
std::lock_guard<std::mutex> lock(mRenderingMutex);
mTextureCache.erase(bufferId);
@@ -559,11 +564,13 @@
false));
mTextureCache.insert({buffer->getId(), imageTextureRef});
}
+
sk_sp<SkImage> image =
imageTextureRef->getTexture()
->makeImage(mUseColorManagement
- ? (needsToneMapping(layer->sourceDataspace,
- display.outputDataspace)
+ ? (needsLinearEffect(layer->colorTransform,
+ layer->sourceDataspace,
+ display.outputDataspace)
// If we need to map to linear space,
// then mark the source image with the
// same colorspace as the destination
@@ -633,7 +640,8 @@
}
if (mUseColorManagement &&
- needsToneMapping(layer->sourceDataspace, display.outputDataspace)) {
+ needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
+ display.outputDataspace)) {
LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
.outputDataspace = display.outputDataspace,
.undoPremultipliedAlpha = !item.isOpaque &&
@@ -649,6 +657,7 @@
}
paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect,
+ layer->colorTransform,
display.maxLuminance,
layer->source.buffer.maxMasteringLuminance,
layer->source.buffer.maxContentLuminance));
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index b3d5d63..7680649 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -447,8 +447,8 @@
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
- float maxDisplayLuminance, float maxMasteringLuminance,
- float maxContentLuminance) {
+ const mat4& colorTransform, float maxDisplayLuminance,
+ float maxMasteringLuminance, float maxContentLuminance) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
@@ -458,7 +458,7 @@
ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
- effectBuilder.uniform("in_xyzToRgb") = mat4(outputColorSpace.getXYZtoRGB());
+ effectBuilder.uniform("in_xyzToRgb") = colorTransform * mat4(outputColorSpace.getXYZtoRGB());
effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
effectBuilder.uniform("in_inputMaxLuminance") =
std::min(maxMasteringLuminance, maxContentLuminance);
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index dadba32..20b8338 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -16,9 +16,10 @@
#pragma once
+#include <math/mat4.h>
+
#include <optional>
-#include "SkColorMatrix.h"
#include "SkRuntimeEffect.h"
#include "SkShader.h"
#include "ui/GraphicTypes.h"
@@ -84,8 +85,10 @@
sk_sp<SkRuntimeEffect> buildRuntimeEffect(const LinearEffect& linearEffect);
// Generates a shader resulting from applying the a linear effect created from
-// LinearEffectARgs::buildEffect to an inputShader. We also provide additional HDR metadata upon
-// creating the shader:
+// LinearEffectArgs::buildEffect to an inputShader.
+// Optionally, a color transform may also be provided, which combines with the
+// matrix transforming from linear XYZ to linear RGB immediately before OETF.
+// We also provide additional HDR metadata upon creating the shader:
// * The max display luminance is the max luminance of the physical display in nits
// * The max mastering luminance is provided as the max luminance from the SMPTE 2086
// standard.
@@ -94,8 +97,8 @@
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> inputShader,
const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
- float maxDisplayLuminance, float maxMasteringLuminance,
- float maxContentLuminance);
+ const mat4& colorTransform, float maxDisplayLuminance,
+ float maxMasteringLuminance, float maxContentLuminance);
} // namespace skia
} // namespace renderengine
} // namespace android