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

Commit fceb229f authored by Alec Mouri's avatar Alec Mouri Committed by Automerger Merge Worker
Browse files

Merge "Tweak libtonemap's CPU interface to support batching." into tm-dev am: 69001d85

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/17085427

Change-Id: I0a0fc6b6c10a0047928cd4211aaa3ccc404b16a4
parents 95c6dd42 69001d85
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -1562,15 +1562,21 @@ void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3
        const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB;

        const vec3 scaledXYZ = scaleOotf(xyz, kCurrentLuminanceNits);
        const double gain =
        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),
                                            scaleOotf(linearRGB, kCurrentLuminanceNits), scaledXYZ,
                                            {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;
+12 −3
Original line number Diff line number Diff line
@@ -48,6 +48,14 @@ struct Metadata {
    float contentMaxLuminance = 0.0;
};

// Utility class containing pre-processed conversions for a particular color
struct Color {
    // RGB color in linear space
    vec3 linearRGB;
    // CIE 1931 XYZ representation of the color
    vec3 xyz;
};

class ToneMapper {
public:
    virtual ~ToneMapper() {}
@@ -108,10 +116,11 @@ public:
    // described by destinationDataspace. To compute the gain, the input colors are provided by
    // linearRGB, which is the RGB colors in linear space. The colors in XYZ space are also
    // provided. Metadata is also provided for helping to compute the tonemapping curve.
    virtual double lookupTonemapGain(
    using Gain = double;
    virtual std::vector<Gain> lookupTonemapGain(
            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
            aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
            vec3 linearRGB, vec3 xyz, const Metadata& metadata) = 0;
            const std::vector<Color>& colors, const Metadata& metadata) = 0;
};

// Retrieves a tonemapper instance.
+206 −197
Original line number Diff line number Diff line
@@ -236,12 +236,17 @@ public:
        return uniforms;
    }

    double lookupTonemapGain(
    std::vector<Gain> lookupTonemapGain(
            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
            aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
            vec3 /* linearRGB */, vec3 xyz, const Metadata& metadata) override {
            const std::vector<Color>& colors, const Metadata& metadata) override {
        std::vector<Gain> gains;
        gains.reserve(colors.size());

        for (const auto [_, xyz] : colors) {
            if (xyz.y <= 0.0) {
            return 1.0;
                gains.push_back(1.0);
                continue;
            }
            const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
            const int32_t destinationDataspaceInt = static_cast<int32_t>(destinationDataspace);
@@ -255,9 +260,9 @@ public:
                            targetNits = xyz.y;
                            break;
                        case kTransferHLG:
                        // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
                        // we'll clamp the luminance range in case we're mapping from PQ input to
                        // HLG output.
                            // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG,
                            // so we'll clamp the luminance range in case we're mapping from PQ
                            // input to HLG output.
                            targetNits = std::clamp(xyz.y, 0.0f, 1000.0f);
                            break;
                        default:
@@ -299,7 +304,8 @@ public:
                                                    (1.0 - t) +
                                            (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
                                } else {
                                // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
                                    // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite
                                    // interp
                                    double t = (targetNits - x2) / h23;
                                    targetNits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) *
                                                    (1.0 - t) +
@@ -317,8 +323,8 @@ public:
                        case kTransferST2084:
                        case kTransferHLG: {
                            // Map from SDR onto an HDR output buffer
                        // Here we use a polynomial curve to map from [0, displayMaxLuminance] onto
                        // [0, maxOutLumi] which is hard-coded to be 3000 nits.
                            // Here we use a polynomial curve to map from [0, displayMaxLuminance]
                            // onto [0, maxOutLumi] which is hard-coded to be 3000 nits.
                            const double maxOutLumi = 3000.0;

                            double x0 = 5.0;
@@ -364,8 +370,9 @@ public:
                            break;
                    }
            }

        return targetNits / xyz.y;
            gains.push_back(targetNits / xyz.y);
        }
        return gains;
    }
};

@@ -427,8 +434,6 @@ public:
                        break;

                    default:
                        // Here we're mapping from HDR to SDR content, so interpolate using a
                        // Hermitian polynomial onto the smaller luminance range.
                        program.append(R"(
                                float libtonemap_OETFTone(float channel) {
                                    channel = channel / 10000.0;
@@ -548,14 +553,39 @@ public:
        return uniforms;
    }

    double lookupTonemapGain(
    std::vector<Gain> lookupTonemapGain(
            aidl::android::hardware::graphics::common::Dataspace sourceDataspace,
            aidl::android::hardware::graphics::common::Dataspace destinationDataspace,
            vec3 linearRGB, vec3 /* xyz */, const Metadata& metadata) override {
            const std::vector<Color>& colors, const Metadata& metadata) override {
        std::vector<Gain> gains;
        gains.reserve(colors.size());

        // Precompute constants for HDR->SDR tonemapping parameters
        constexpr double maxInLumi = 4000;
        const double maxOutLumi = metadata.displayMaxLuminance;

        const double x1 = maxOutLumi * 0.65;
        const double y1 = x1;

        const double x3 = maxInLumi;
        const double y3 = maxOutLumi;

        const double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
        const double y2 = maxOutLumi * 0.9;

        const double greyNorm1 = OETF_ST2084(x1);
        const double greyNorm2 = OETF_ST2084(x2);
        const double greyNorm3 = OETF_ST2084(x3);

        const double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
        const double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);

        for (const auto [linearRGB, _] : colors) {
            double maxRGB = std::max({linearRGB.r, linearRGB.g, linearRGB.b});

            if (maxRGB <= 0.0) {
            return 1.0;
                gains.push_back(1.0);
                continue;
            }

            const int32_t sourceDataspaceInt = static_cast<int32_t>(sourceDataspace);
@@ -569,36 +599,13 @@ public:
                            targetNits = maxRGB;
                            break;
                        case kTransferHLG:
                        // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG, so
                        // we'll clamp the luminance range in case we're mapping from PQ input to
                        // HLG output.
                            // PQ has a wider luminance range (10,000 nits vs. 1,000 nits) than HLG,
                            // so we'll clamp the luminance range in case we're mapping from PQ
                            // input to HLG output.
                            targetNits = std::clamp(maxRGB, 0.0, 1000.0);
                            break;
                        default:
                        // Here we're mapping from HDR to SDR content, so interpolate using a
                        // Hermitian polynomial onto the smaller luminance range.

                        double maxInLumi = 4000;
                        double maxOutLumi = metadata.displayMaxLuminance;

                            targetNits = maxRGB;

                        double x1 = maxOutLumi * 0.65;
                        double y1 = x1;

                        double x3 = maxInLumi;
                        double y3 = maxOutLumi;

                        double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
                        double y2 = maxOutLumi * 0.9;

                        const double greyNorm1 = OETF_ST2084(x1);
                        const double greyNorm2 = OETF_ST2084(x2);
                        const double greyNorm3 = OETF_ST2084(x3);

                        double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
                        double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);

                            if (targetNits < x1) {
                                break;
                            }
@@ -636,7 +643,9 @@ public:
                    break;
            }

        return targetNits / maxRGB;
            gains.push_back(targetNits / maxRGB);
        }
        return gains;
    }
};