Enable more ColorSpaces in RenderEngine
Bug: 200307628
Test: librenderengine_test pass
Change-Id: I81d9e86e8a826a74d65ce378d01ab55496cdd944
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
index ff4d348..f367a84 100644
--- a/libs/renderengine/skia/ColorSpaces.cpp
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -20,6 +20,7 @@
namespace renderengine {
namespace skia {
+// please keep in sync with hwui/utils/Color.cpp
sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
skcms_Matrix3x3 gamut;
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
@@ -32,6 +33,17 @@
case HAL_DATASPACE_STANDARD_DCI_P3:
gamut = SkNamedGamut::kDisplayP3;
break;
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ gamut = SkNamedGamut::kAdobeRGB;
+ break;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ case HAL_DATASPACE_STANDARD_BT470M:
+ case HAL_DATASPACE_STANDARD_FILM:
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
default:
gamut = SkNamedGamut::kSRGB;
break;
@@ -42,10 +54,19 @@
return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
case HAL_DATASPACE_TRANSFER_SRGB:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_HLG:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
default:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 5bc08ac..8259063 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -504,6 +504,18 @@
void fillBufferColorTransform();
template <typename SourceVariant>
+ void fillBufferWithColorTransformAndSourceDataspace(const ui::Dataspace sourceDataspace);
+
+ template <typename SourceVariant>
+ void fillBufferColorTransformAndSourceDataspace();
+
+ template <typename SourceVariant>
+ void fillBufferWithColorTransformAndOutputDataspace(const ui::Dataspace outputDataspace);
+
+ template <typename SourceVariant>
+ void fillBufferColorTransformAndOutputDataspace();
+
+ template <typename SourceVariant>
void fillBufferWithColorTransformZeroLayerAlpha();
template <typename SourceVariant>
@@ -881,12 +893,104 @@
}
template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransformAndSourceDataspace(
+ const ui::Dataspace sourceDataspace) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = Rect(1, 1);
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.sourceDataspace = sourceDataspace;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+ SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+ layer.alpha = 1.0f;
+
+ // construct a fake color matrix
+ // annihilate green and blue channels
+ settings.colorTransform = mat4::scale(vec4(0.9f, 0, 0, 1));
+ // set red channel to red + green
+ layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+ layer.alpha = 1.0f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers);
+}
+
+template <typename SourceVariant>
void RenderEngineTest::fillBufferColorTransform() {
fillBufferWithColorTransform<SourceVariant>();
expectBufferColor(fullscreenRect(), 172, 0, 0, 255, 1);
}
template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformAndSourceDataspace() {
+ unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap;
+ dataspaceToColorMap[ui::Dataspace::V0_BT709] = {172, 0, 0, 255};
+ dataspaceToColorMap[ui::Dataspace::BT2020] = {172, 0, 0, 255};
+ dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {172, 0, 0, 255};
+ ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>(
+ ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_2 |
+ ui::Dataspace::RANGE_FULL);
+ dataspaceToColorMap[customizedDataspace] = {172, 0, 0, 255};
+ for (const auto& [sourceDataspace, color] : dataspaceToColorMap) {
+ fillBufferWithColorTransformAndSourceDataspace<SourceVariant>(sourceDataspace);
+ expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1);
+ }
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransformAndOutputDataspace(
+ const ui::Dataspace outputDataspace) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = Rect(1, 1);
+ settings.outputDataspace = outputDataspace;
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.sourceDataspace = ui::Dataspace::V0_SCRGB_LINEAR;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+ SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+ layer.alpha = 1.0f;
+
+ // construct a fake color matrix
+ // annihilate green and blue channels
+ settings.colorTransform = mat4::scale(vec4(0.9f, 0, 0, 1));
+ // set red channel to red + green
+ layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+ layer.alpha = 1.0f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformAndOutputDataspace() {
+ unordered_map<ui::Dataspace, ubyte4> dataspaceToColorMap;
+ dataspaceToColorMap[ui::Dataspace::V0_BT709] = {202, 0, 0, 255};
+ dataspaceToColorMap[ui::Dataspace::BT2020] = {192, 0, 0, 255};
+ dataspaceToColorMap[ui::Dataspace::ADOBE_RGB] = {202, 0, 0, 255};
+ ui::Dataspace customizedDataspace = static_cast<ui::Dataspace>(
+ ui::Dataspace::STANDARD_BT709 | ui::Dataspace::TRANSFER_GAMMA2_6 |
+ ui::Dataspace::RANGE_FULL);
+ dataspaceToColorMap[customizedDataspace] = {202, 0, 0, 255};
+ for (const auto& [outputDataspace, color] : dataspaceToColorMap) {
+ fillBufferWithColorTransformAndOutputDataspace<SourceVariant>(outputDataspace);
+ expectBufferColor(fullscreenRect(), color.r, color.g, color.b, color.a, 1);
+ }
+}
+
+template <typename SourceVariant>
void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -1427,6 +1531,36 @@
fillBufferColorTransform<ColorSourceVariant>();
}
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndSourceDataspace<ColorSourceVariant>();
+}
+
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndOutputDataspace<ColorSourceVariant>();
+}
+
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
initializeRenderEngine();
fillBufferWithRoundedCorners<ColorSourceVariant>();
@@ -1507,6 +1641,36 @@
fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndSourceDataspace<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_opaqueBufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndOutputDataspace<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
@@ -1587,6 +1751,36 @@
fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndSourceDataspace<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_bufferSource) {
+ const auto& renderEngineFactory = GetParam();
+ // skip for non color management
+ if (!renderEngineFactory->useColorManagement()) {
+ return;
+ }
+ // skip for GLESRenderEngine
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ initializeRenderEngine();
+ fillBufferColorTransformAndOutputDataspace<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index ee2d4a4..6019c4a 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -72,6 +72,70 @@
}
)");
break;
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ shader.append(R"(
+
+ float EOTF_sRGB(float srgb) {
+ return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 0.45);
+ }
+
+ float3 EOTF_sRGB(float3 srgb) {
+ return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ float3 EOTF(float3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ shader.append(R"(
+
+ float EOTF_sRGB(float srgb) {
+ return pow(srgb, 2.2);
+ }
+
+ float3 EOTF_sRGB(float3 srgb) {
+ return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ float3 EOTF(float3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ shader.append(R"(
+
+ float EOTF_sRGB(float srgb) {
+ return pow(srgb, 2.6);
+ }
+
+ float3 EOTF_sRGB(float3 srgb) {
+ return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ float3 EOTF(float3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ shader.append(R"(
+
+ float EOTF_sRGB(float srgb) {
+ return pow(srgb, 2.8);
+ }
+
+ float3 EOTF_sRGB(float3 srgb) {
+ return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ float3 EOTF(float3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )");
+ break;
case HAL_DATASPACE_TRANSFER_SRGB:
default:
shader.append(R"(
@@ -239,6 +303,67 @@
}
)");
break;
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ shader.append(R"(
+ float OETF_sRGB(float linear) {
+ return linear <= 0.018 ?
+ linear * 4.50 : (pow(linear, 0.45) * 1.099) - 0.099;
+ }
+
+ float3 OETF_sRGB(float3 linear) {
+ return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ float3 OETF(float3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+ shader.append(R"(
+ float OETF_sRGB(float linear) {
+ return pow(linear, (1.0 / 2.2));
+ }
+
+ float3 OETF_sRGB(float3 linear) {
+ return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ float3 OETF(float3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_6:
+ shader.append(R"(
+ float OETF_sRGB(float linear) {
+ return pow(linear, (1.0 / 2.6));
+ }
+
+ float3 OETF_sRGB(float3 linear) {
+ return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ float3 OETF(float3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+ )");
+ break;
+ case HAL_DATASPACE_TRANSFER_GAMMA2_8:
+ shader.append(R"(
+ float OETF_sRGB(float linear) {
+ return pow(linear, (1.0 / 2.8));
+ }
+
+ float3 OETF_sRGB(float3 linear) {
+ return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ float3 OETF(float3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+ )");
+ break;
case HAL_DATASPACE_TRANSFER_SRGB:
default:
shader.append(R"(
@@ -285,20 +410,31 @@
}
)");
}
+
+// please keep in sync with toSkColorSpace function in renderengine/skia/ColorSpaces.cpp
static ColorSpace toColorSpace(ui::Dataspace dataspace) {
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT709:
return ColorSpace::sRGB();
- break;
case HAL_DATASPACE_STANDARD_DCI_P3:
return ColorSpace::DisplayP3();
- break;
case HAL_DATASPACE_STANDARD_BT2020:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
return ColorSpace::BT2020();
- break;
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ return ColorSpace::AdobeRGB();
+ // TODO(b/208290320): BT601 format and variants return different primaries
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ // TODO(b/208290329): BT407M format returns different primaries
+ case HAL_DATASPACE_STANDARD_BT470M:
+ // TODO(b/208290904): FILM format returns different primaries
+ case HAL_DATASPACE_STANDARD_FILM:
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
default:
return ColorSpace::sRGB();
- break;
}
}