diff options
-rw-r--r-- | libs/renderengine/skia/ColorSpaces.cpp | 21 | ||||
-rw-r--r-- | libs/renderengine/tests/RenderEngineTest.cpp | 194 | ||||
-rw-r--r-- | libs/shaders/shaders.cpp | 144 |
3 files changed, 355 insertions, 4 deletions
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp index ff4d348f0d..f367a84946 100644 --- a/libs/renderengine/skia/ColorSpaces.cpp +++ b/libs/renderengine/skia/ColorSpaces.cpp @@ -20,6 +20,7 @@ namespace android { 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 @@ sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) { 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 @@ sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) { 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 5bc08ac089..82590638a8 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -504,6 +504,18 @@ public: 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 @@ void RenderEngineTest::fillBufferWithColorTransform() { } 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 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) { 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 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) 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 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) { 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 ee2d4a46a5..6019c4ac28 100644 --- a/libs/shaders/shaders.cpp +++ b/libs/shaders/shaders.cpp @@ -72,6 +72,70 @@ static void generateEOTF(ui::Dataspace dataspace, std::string& shader) { } )"); 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 @@ static void generateOETF(ui::Dataspace dataspace, std::string& shader) { } )"); 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 @@ static void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shad } )"); } + +// 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; } } |