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;
     }
 }