Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98b37718 authored by Alec Mouri's avatar Alec Mouri Committed by Android (Google) Code Review
Browse files

Merge "Remove PQ/HLG tonemap tests in RenderEngine" into main

parents cd7bf125 32e2e20f
Loading
Loading
Loading
Loading
+0 −199
Original line number Diff line number Diff line
@@ -63,46 +63,6 @@ namespace renderengine {

namespace {

double EOTF_PQ(double channel) {
    float m1 = (2610.0 / 4096.0) / 4.0;
    float m2 = (2523.0 / 4096.0) * 128.0;
    float c1 = (3424.0 / 4096.0);
    float c2 = (2413.0 / 4096.0) * 32.0;
    float c3 = (2392.0 / 4096.0) * 32.0;

    float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2);
    tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp);
    return std::pow(tmp, 1.0 / m1);
}

vec3 EOTF_PQ(vec3 color) {
    return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b));
}

double EOTF_HLG(double channel) {
    const float a = 0.17883277;
    const float b = 0.28466892;
    const float c = 0.55991073;
    return channel <= 0.5 ? channel * channel / 3.0 : (exp((channel - c) / a) + b) / 12.0;
}

vec3 EOTF_HLG(vec3 color) {
    return vec3(EOTF_HLG(color.r), EOTF_HLG(color.g), EOTF_HLG(color.b));
}

double OETF_sRGB(double channel) {
    return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055;
}

int sign(float in) {
    return in >= 0.0 ? 1 : -1;
}

vec3 OETF_sRGB(vec3 linear) {
    return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g),
                sign(linear.b) * OETF_sRGB(linear.b));
}

// clang-format off
// Converts red channels to green channels, and zeroes out an existing green channel.
static const auto kRemoveGreenAndMoveRedToGreenMat4 = mat4(0, 1, 0, 0,
@@ -623,12 +583,6 @@ public:
    void drawShadowWithoutCaster(const FloatRect& castingBounds, const ShadowSettings& shadow,
                                 const ubyte4& backgroundColor);

    // Tonemaps grey values from sourceDataspace -> Display P3 and checks that GPU and CPU
    // implementations are identical Also implicitly checks that the injected tonemap shader
    // compiles
    void tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
                 std::function<vec3(vec3, float)> scaleOotf);

    void initializeRenderEngine();

    std::unique_ptr<renderengine::RenderEngine> mRE;
@@ -1423,125 +1377,6 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
    invokeDraw(settings, layers);
}

void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
                               std::function<vec3(vec3, float)> scaleOotf) {
    constexpr int32_t kGreyLevels = 256;

    const auto rect = Rect(0, 0, kGreyLevels, 1);

    constexpr float kMaxLuminance = 750.f;
    constexpr float kCurrentLuminanceNits = 500.f;
    const renderengine::DisplaySettings display{
            .physicalDisplay = rect,
            .clip = rect,
            .maxLuminance = kMaxLuminance,
            .currentLuminanceNits = kCurrentLuminanceNits,
            .outputDataspace = ui::Dataspace::DISPLAY_P3,
    };

    auto buf = std::make_shared<
            renderengine::impl::
                    ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
                                                             HAL_PIXEL_FORMAT_RGBA_8888, 1,
                                                             GRALLOC_USAGE_SW_READ_OFTEN |
                                                                     GRALLOC_USAGE_SW_WRITE_OFTEN |
                                                                     GRALLOC_USAGE_HW_RENDER |
                                                                     GRALLOC_USAGE_HW_TEXTURE,
                                                             "input"),
                                     *mRE,
                                     renderengine::impl::ExternalTexture::Usage::READABLE |
                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
    ASSERT_EQ(0, buf->getBuffer()->initCheck());
    {
        uint8_t* pixels;
        buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                               reinterpret_cast<void**>(&pixels));

        uint8_t color = 0;
        for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
            uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4);
            for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
                dest[0] = color;
                dest[1] = color;
                dest[2] = color;
                dest[3] = 255;
                color++;
                dest += 4;
            }
        }
        buf->getBuffer()->unlock();
    }

    mBuffer = std::make_shared<
            renderengine::impl::
                    ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
                                                             HAL_PIXEL_FORMAT_RGBA_8888, 1,
                                                             GRALLOC_USAGE_SW_READ_OFTEN |
                                                                     GRALLOC_USAGE_SW_WRITE_OFTEN |
                                                                     GRALLOC_USAGE_HW_RENDER |
                                                                     GRALLOC_USAGE_HW_TEXTURE,
                                                             "output"),
                                     *mRE,
                                     renderengine::impl::ExternalTexture::Usage::READABLE |
                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
    ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());

    const renderengine::LayerSettings layer{.geometry.boundaries = rect.toFloatRect(),
                                            .source =
                                                    renderengine::PixelSource{
                                                            .buffer =
                                                                    renderengine::Buffer{
                                                                            .buffer =
                                                                                    std::move(buf),
                                                                            .usePremultipliedAlpha =
                                                                                    true,
                                                                    },
                                                    },
                                            .alpha = 1.0f,
                                            .sourceDataspace = sourceDataspace};

    std::vector<renderengine::LayerSettings> layers{layer};
    invokeDraw(display, layers);

    ColorSpace displayP3 = ColorSpace::DisplayP3();
    ColorSpace bt2020 = ColorSpace::BT2020();

    tonemap::Metadata metadata{.displayMaxLuminance = 750.0f};

    auto generator = [=](Point location) {
        const double normColor = static_cast<double>(location.x) / (kGreyLevels - 1);
        const vec3 rgb = vec3(normColor, normColor, normColor);

        const vec3 linearRGB = eotf(rgb);

        const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB;

        const vec3 scaledXYZ = scaleOotf(xyz, kCurrentLuminanceNits);
        const auto gains =
                tonemap::getToneMapper()
                        ->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
                                                                Dataspace>(sourceDataspace),
                                            static_cast<aidl::android::hardware::graphics::common::
                                                                Dataspace>(
                                                    ui::Dataspace::DISPLAY_P3),
                                            {tonemap::
                                                     Color{.linearRGB =
                                                                   scaleOotf(linearRGB,
                                                                             kCurrentLuminanceNits),
                                                           .xyz = scaledXYZ}},
                                            metadata);
        EXPECT_EQ(1, gains.size());
        const double gain = gains.front();
        const vec3 normalizedXYZ = scaledXYZ * gain / metadata.displayMaxLuminance;

        const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * normalizedXYZ) * 255;
        return ubyte4(static_cast<uint8_t>(targetRGB.r), static_cast<uint8_t>(targetRGB.g),
                      static_cast<uint8_t>(targetRGB.b), 255);
    };

    expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
}

// TODO: b/341728634 - Clean up conditional compilation.
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
                         testing::Values(std::make_shared<SkiaGLESRenderEngineFactory>(),
@@ -2953,40 +2788,6 @@ TEST_P(RenderEngineTest, test_isOpaque) {
    expectBufferColor(rect, 117, 251, 76, 255);
}

TEST_P(RenderEngineTest, test_tonemapPQMatches) {
    if (!GetParam()->apiSupported()) {
        GTEST_SKIP();
    }

    initializeRenderEngine();

    tonemap(
            static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
                                       HAL_DATASPACE_TRANSFER_ST2084 | HAL_DATASPACE_RANGE_FULL),
            [](vec3 color) { return EOTF_PQ(color); },
            [](vec3 color, float) {
                static constexpr float kMaxPQLuminance = 10000.f;
                return color * kMaxPQLuminance;
            });
}

TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
    if (!GetParam()->apiSupported()) {
        GTEST_SKIP();
    }

    initializeRenderEngine();

    tonemap(
            static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
                                       HAL_DATASPACE_RANGE_FULL),
            [](vec3 color) { return EOTF_HLG(color); },
            [](vec3 color, float currentLuminaceNits) {
                static constexpr float kMaxHLGLuminance = 1000.f;
                return color * kMaxHLGLuminance;
            });
}

TEST_P(RenderEngineTest, r8_behaves_as_mask) {
    if (!GetParam()->apiSupported()) {
        GTEST_SKIP();