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

Commit e4a3d635 authored by John Reck's avatar John Reck
Browse files

Update ColorSpace _HLG & _PQ to use 203 nit whitepoints

Also cleans up identifying PQ & HLG transfer functions
using the same hack skia does of using negative G values
as an enum

Fixes: 272555335
Test: mapped out the curves

Change-Id: I2bd6cd0a234fdea701b85737a1378058f6c40a1b
parent 83b5bfc0
Loading
Loading
Loading
Loading
+128 −100
Original line number Original line Diff line number Diff line
@@ -210,12 +210,16 @@ public abstract class ColorSpace {


    private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS =
    private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS =
            new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4);
            new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4);

    // HLG transfer with an SDR whitepoint of 203 nits
    private static final Rgb.TransferParameters BT2020_HLG_TRANSFER_PARAMETERS =
    private static final Rgb.TransferParameters BT2020_HLG_TRANSFER_PARAMETERS =
            new Rgb.TransferParameters(2.0f, 2.0f, 1 / 0.17883277f,
            new Rgb.TransferParameters(2.0, 2.0, 1 / 0.17883277, 0.28466892, 0.55991073,
                0.28466892f, 0.5599107f, -11 / 12.0f, -3.0f, true);
                    -0.685490157, Rgb.TransferParameters.TYPE_HLGish);

    // PQ transfer with an SDR whitepoint of 203 nits
    private static final Rgb.TransferParameters BT2020_PQ_TRANSFER_PARAMETERS =
    private static final Rgb.TransferParameters BT2020_PQ_TRANSFER_PARAMETERS =
            new Rgb.TransferParameters(-107 / 128.0f, 1.0f, 32 / 2523.0f,
            new Rgb.TransferParameters(-1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
                2413 / 128.0f, -2392 / 128.0f, 8192 / 1305.0f, -2.0f, true);
                    -2392 / 128.0, 8192 / 1305.0, Rgb.TransferParameters.TYPE_PQish);


    // See static initialization block next to #get(Named)
    // See static initialization block next to #get(Named)
    private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length];
    private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length];
@@ -1651,8 +1655,8 @@ public abstract class ColorSpace {
                BT2020_PRIMARIES,
                BT2020_PRIMARIES,
                ILLUMINANT_D65,
                ILLUMINANT_D65,
                null,
                null,
                x -> transferHLGOETF(x),
                x -> transferHLGOETF(BT2020_HLG_TRANSFER_PARAMETERS, x),
                x -> transferHLGEOTF(x),
                x -> transferHLGEOTF(BT2020_HLG_TRANSFER_PARAMETERS, x),
                0.0f, 1.0f,
                0.0f, 1.0f,
                BT2020_HLG_TRANSFER_PARAMETERS,
                BT2020_HLG_TRANSFER_PARAMETERS,
                Named.BT2020_HLG.ordinal()
                Named.BT2020_HLG.ordinal()
@@ -1663,8 +1667,8 @@ public abstract class ColorSpace {
                BT2020_PRIMARIES,
                BT2020_PRIMARIES,
                ILLUMINANT_D65,
                ILLUMINANT_D65,
                null,
                null,
                x -> transferST2048OETF(x),
                x -> transferST2048OETF(BT2020_PQ_TRANSFER_PARAMETERS, x),
                x -> transferST2048EOTF(x),
                x -> transferST2048EOTF(BT2020_PQ_TRANSFER_PARAMETERS, x),
                0.0f, 1.0f,
                0.0f, 1.0f,
                BT2020_PQ_TRANSFER_PARAMETERS,
                BT2020_PQ_TRANSFER_PARAMETERS,
                Named.BT2020_PQ.ordinal()
                Named.BT2020_PQ.ordinal()
@@ -1672,44 +1676,58 @@ public abstract class ColorSpace {
        sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal());
        sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020_PQ, Named.BT2020_PQ.ordinal());
    }
    }


    private static double transferHLGOETF(double x) {
    private static double transferHLGOETF(Rgb.TransferParameters params, double x) {
        double a = 0.17883277;
        double sign = x < 0 ? -1.0 : 1.0;
        double b = 0.28466892;
        x *= sign;
        double c = 0.55991073;

        double r = 0.5;
        // Unpack the transfer params matching skia's packing & invert R, G, and a
        return x > 1.0 ? a * Math.log(x - b) + c : r * Math.sqrt(x);
        final double R = 1.0 / params.a;
        final double G = 1.0 / params.b;
        final double a = 1.0 / params.c;
        final double b = params.d;
        final double c = params.e;
        final double K = params.f + 1.0;

        x /= K;
        return sign * (x <= 1 ? R * Math.pow(x, G) : a * Math.log(x - b) + c);
    }
    }


    private static double transferHLGEOTF(double x) {
    private static double transferHLGEOTF(Rgb.TransferParameters params, double x) {
        double a = 0.17883277;
        double sign = x < 0 ? -1.0 : 1.0;
        double b = 0.28466892;
        x *= sign;
        double c = 0.55991073;

        double r = 0.5;
        // Unpack the transfer params matching skia's packing
        return x <= 0.5 ? (x * x) / (r * r) : Math.exp((x - c) / a + b);
        final double R = params.a;
        final double G = params.b;
        final double a = params.c;
        final double b = params.d;
        final double c = params.e;
        final double K = params.f + 1.0;

        return K * sign * (x * R <= 1 ? Math.pow(x * R, G) : Math.exp((x - c) * a) + b);
    }
    }


    private static double transferST2048OETF(double x) {
    private static double transferST2048OETF(Rgb.TransferParameters params, double x) {
        double m1 = (2610.0 / 4096.0) / 4.0;
        double sign = x < 0 ? -1.0 : 1.0;
        double m2 = (2523.0 / 4096.0) * 128.0;
        x *= sign;
        double c1 = (3424.0 / 4096.0);

        double c2 = (2413.0 / 4096.0) * 32.0;
        double a = -params.a;
        double c3 = (2392.0 / 4096.0) * 32.0;
        double b = params.d;
        double c = 1.0 / params.f;
        double d = params.b;
        double e = -params.e;
        double f = 1.0 / params.c;


        double tmp = Math.pow(x, m1);
        double tmp = Math.max(a + b * Math.pow(x, c), 0);
        tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
        return sign * Math.pow(tmp / (d + e * Math.pow(x, c)), f);
        return Math.pow(tmp, m2);
    }
    }


    private static double transferST2048EOTF(double x) {
    private static double transferST2048EOTF(Rgb.TransferParameters pq, double x) {
        double m1 = (2610.0 / 4096.0) / 4.0;
        double sign = x < 0 ? -1.0 : 1.0;
        double m2 = (2523.0 / 4096.0) * 128.0;
        x *= sign;
        double c1 = (3424.0 / 4096.0);
        double c2 = (2413.0 / 4096.0) * 32.0;
        double c3 = (2392.0 / 4096.0) * 32.0;


        double tmp = Math.pow(Math.min(Math.max(x, 0.0), 1.0), 1.0 / m2);
        double tmp = Math.max(pq.a + pq.b * Math.pow(x, pq.c), 0);
        tmp = Math.max(tmp - c1, 0.0) / (c2 - c3 * tmp);
        return sign * Math.pow(tmp / (pq.d + pq.e * Math.pow(x, pq.c)), pq.f);
        return Math.pow(tmp, 1.0 / m1);
    }
    }


    // Reciprocal piecewise gamma response
    // Reciprocal piecewise gamma response
@@ -2276,6 +2294,10 @@ public abstract class ColorSpace {
         * </ul>
         * </ul>
         */
         */
        public static class TransferParameters {
        public static class TransferParameters {

            private static final double TYPE_PQish = -2.0;
            private static final double TYPE_HLGish = -3.0;

            /** Variable \(a\) in the equation of the EOTF described above. */
            /** Variable \(a\) in the equation of the EOTF described above. */
            public final double a;
            public final double a;
            /** Variable \(b\) in the equation of the EOTF described above. */
            /** Variable \(b\) in the equation of the EOTF described above. */
@@ -2291,16 +2313,57 @@ public abstract class ColorSpace {
            /** Variable \(g\) in the equation of the EOTF described above. */
            /** Variable \(g\) in the equation of the EOTF described above. */
            public final double g;
            public final double g;


            private TransferParameters(double a, double b, double c, double d, double e,
            private static boolean isSpecialG(double g) {
                    double f, double g, boolean nonCurveTransferParameters) {
                return g == TYPE_PQish || g == TYPE_HLGish;
                // nonCurveTransferParameters correspondes to a "special" transfer function
            }
                if (!nonCurveTransferParameters) {

            /**
             * <p>Defines the parameters for the ICC parametric curve type 3, as
             * defined in ICC.1:2004-10, section 10.15.</p>
             *
             * <p>The EOTF is of the form:</p>
             *
             * \(\begin{equation}
             * Y = \begin{cases}c X & X \lt d \\\
             * \left( a X + b \right) ^{g} & X \ge d \end{cases}
             * \end{equation}\)
             *
             * <p>This constructor is equivalent to setting  \(e\) and \(f\) to 0.</p>
             *
             * @param a The value of \(a\) in the equation of the EOTF described above
             * @param b The value of \(b\) in the equation of the EOTF described above
             * @param c The value of \(c\) in the equation of the EOTF described above
             * @param d The value of \(d\) in the equation of the EOTF described above
             * @param g The value of \(g\) in the equation of the EOTF described above
             *
             * @throws IllegalArgumentException If the parameters form an invalid transfer function
             */
            public TransferParameters(double a, double b, double c, double d, double g) {
                this(a, b, c, d, 0.0, 0.0, g);
            }

            /**
             * <p>Defines the parameters for the ICC parametric curve type 4, as
             * defined in ICC.1:2004-10, section 10.15.</p>
             *
             * @param a The value of \(a\) in the equation of the EOTF described above
             * @param b The value of \(b\) in the equation of the EOTF described above
             * @param c The value of \(c\) in the equation of the EOTF described above
             * @param d The value of \(d\) in the equation of the EOTF described above
             * @param e The value of \(e\) in the equation of the EOTF described above
             * @param f The value of \(f\) in the equation of the EOTF described above
             * @param g The value of \(g\) in the equation of the EOTF described above
             *
             * @throws IllegalArgumentException If the parameters form an invalid transfer function
             */
            public TransferParameters(double a, double b, double c, double d, double e,
                    double f, double g) {
                if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c)
                if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c)
                        || Double.isNaN(d) || Double.isNaN(e) || Double.isNaN(f)
                        || Double.isNaN(d) || Double.isNaN(e) || Double.isNaN(f)
                        || Double.isNaN(g)) {
                        || Double.isNaN(g)) {
                    throw new IllegalArgumentException("Parameters cannot be NaN");
                    throw new IllegalArgumentException("Parameters cannot be NaN");
                }
                }

                if (!isSpecialG(g)) {
                    // Next representable float after 1.0
                    // Next representable float after 1.0
                    // We use doubles here but the representation inside our native code
                    // We use doubles here but the representation inside our native code
                    // is often floats
                    // is often floats
@@ -2343,50 +2406,6 @@ public abstract class ColorSpace {
                this.g = g;
                this.g = g;
            }
            }


            /**
             * <p>Defines the parameters for the ICC parametric curve type 3, as
             * defined in ICC.1:2004-10, section 10.15.</p>
             *
             * <p>The EOTF is of the form:</p>
             *
             * \(\begin{equation}
             * Y = \begin{cases}c X & X \lt d \\\
             * \left( a X + b \right) ^{g} & X \ge d \end{cases}
             * \end{equation}\)
             *
             * <p>This constructor is equivalent to setting  \(e\) and \(f\) to 0.</p>
             *
             * @param a The value of \(a\) in the equation of the EOTF described above
             * @param b The value of \(b\) in the equation of the EOTF described above
             * @param c The value of \(c\) in the equation of the EOTF described above
             * @param d The value of \(d\) in the equation of the EOTF described above
             * @param g The value of \(g\) in the equation of the EOTF described above
             *
             * @throws IllegalArgumentException If the parameters form an invalid transfer function
             */
            public TransferParameters(double a, double b, double c, double d, double g) {
                this(a, b, c, d, 0.0, 0.0, g, false);
            }

            /**
             * <p>Defines the parameters for the ICC parametric curve type 4, as
             * defined in ICC.1:2004-10, section 10.15.</p>
             *
             * @param a The value of \(a\) in the equation of the EOTF described above
             * @param b The value of \(b\) in the equation of the EOTF described above
             * @param c The value of \(c\) in the equation of the EOTF described above
             * @param d The value of \(d\) in the equation of the EOTF described above
             * @param e The value of \(e\) in the equation of the EOTF described above
             * @param f The value of \(f\) in the equation of the EOTF described above
             * @param g The value of \(g\) in the equation of the EOTF described above
             *
             * @throws IllegalArgumentException If the parameters form an invalid transfer function
             */
            public TransferParameters(double a, double b, double c, double d, double e,
                    double f, double g) {
                this(a, b, c, d, e, f, g, false);
            }

            @SuppressWarnings("SimplifiableIfStatement")
            @SuppressWarnings("SimplifiableIfStatement")
            @Override
            @Override
            public boolean equals(Object o) {
            public boolean equals(Object o) {
@@ -2424,6 +2443,17 @@ public abstract class ColorSpace {
                result = 31 * result + (int) (temp ^ (temp >>> 32));
                result = 31 * result + (int) (temp ^ (temp >>> 32));
                return result;
                return result;
            }
            }

            /**
             * @hide
             */
            private boolean isHLGish() {
                return g == TYPE_HLGish;
            }

            private boolean isPQish() {
                return g == TYPE_PQish;
            }
        }
        }


        @NonNull private final float[] mWhitePoint;
        @NonNull private final float[] mWhitePoint;
@@ -2460,11 +2490,10 @@ public abstract class ColorSpace {
                float e, float f, float g, float[] xyz);
                float e, float f, float g, float[] xyz);


        private static DoubleUnaryOperator generateOETF(TransferParameters function) {
        private static DoubleUnaryOperator generateOETF(TransferParameters function) {
            boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS)
            if (function.isHLGish()) {
                    || function.equals(BT2020_PQ_TRANSFER_PARAMETERS);
                return x -> transferHLGOETF(function, x);
            if (isNonCurveTransferParameters) {
            } else if (function.isPQish()) {
                return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGOETF(x)
                return x -> transferST2048OETF(function, x);
                    : x -> transferST2048OETF(x);
            } else {
            } else {
                return function.e == 0.0 && function.f == 0.0
                return function.e == 0.0 && function.f == 0.0
                    ? x -> rcpResponse(x, function.a, function.b,
                    ? x -> rcpResponse(x, function.a, function.b,
@@ -2475,11 +2504,10 @@ public abstract class ColorSpace {
        }
        }


        private static DoubleUnaryOperator generateEOTF(TransferParameters function) {
        private static DoubleUnaryOperator generateEOTF(TransferParameters function) {
            boolean isNonCurveTransferParameters = function.equals(BT2020_HLG_TRANSFER_PARAMETERS)
            if (function.isHLGish()) {
                    || function.equals(BT2020_PQ_TRANSFER_PARAMETERS);
                return x -> transferHLGEOTF(function, x);
            if (isNonCurveTransferParameters) {
            } else if (function.isPQish()) {
                return function.f == 0.0 && function.g < 0.0 ? x -> transferHLGEOTF(x)
                return x -> transferST2048OETF(function, x);
                    : x -> transferST2048EOTF(x);
            } else {
            } else {
                return function.e == 0.0 && function.f == 0.0
                return function.e == 0.0 && function.f == 0.0
                    ? x -> response(x, function.a, function.b,
                    ? x -> response(x, function.a, function.b,
+4 −12
Original line number Original line Diff line number Diff line
@@ -579,17 +579,9 @@ jobject GraphicsJNI::getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace,
    LOG_ALWAYS_FATAL_IF(res == skcms_TFType_HLGinvish || res == skcms_TFType_Invalid);
    LOG_ALWAYS_FATAL_IF(res == skcms_TFType_HLGinvish || res == skcms_TFType_Invalid);


    jobject params;
    jobject params;
    if (res == skcms_TFType_PQish || res == skcms_TFType_HLGish) {
    params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID,
    params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID,
                                transferParams.a, transferParams.b, transferParams.c,
                            transferParams.a, transferParams.b, transferParams.c, transferParams.d,
                                transferParams.d, transferParams.e, transferParams.f,
                            transferParams.e, transferParams.f, transferParams.g);
                                transferParams.g, true);
    } else {
        params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID,
                                transferParams.a, transferParams.b, transferParams.c,
                                transferParams.d, transferParams.e, transferParams.f,
                                transferParams.g, false);
    }


    jfloatArray xyzArray = env->NewFloatArray(9);
    jfloatArray xyzArray = env->NewFloatArray(9);
    jfloat xyz[9] = {
    jfloat xyz[9] = {
@@ -817,7 +809,7 @@ int register_android_graphics_Graphics(JNIEnv* env)
    gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
    gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
            "android/graphics/ColorSpace$Rgb$TransferParameters"));
            "android/graphics/ColorSpace$Rgb$TransferParameters"));
    gTransferParameters_constructorMethodID =
    gTransferParameters_constructorMethodID =
            GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDDZ)V");
            GetMethodIDOrDie(env, gTransferParameters_class, "<init>", "(DDDDDDD)V");


    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);