[LUT shader] add CIE_Y shader

- Use D65 illuminant

Bug: 358422255
Test: android.view.surfacecontrol.cts.SurfaceControlTest#testSurfaceTransaction_setLuts_1DLut_withCIEy
Flag: EXEMPT no flag needed

Change-Id: Icfae89bcd6538d6c0c0a9ba1bce2f1dba8776b8d
diff --git a/libs/gui/aidl/android/gui/LutProperties.aidl b/libs/gui/aidl/android/gui/LutProperties.aidl
index 87b878c..84c7013 100644
--- a/libs/gui/aidl/android/gui/LutProperties.aidl
+++ b/libs/gui/aidl/android/gui/LutProperties.aidl
@@ -27,6 +27,6 @@
 
     int size;
     @Backing(type="int")
-    enum SamplingKey { RGB, MAX_RGB }
+    enum SamplingKey { RGB, MAX_RGB, CIE_Y }
     SamplingKey[] samplingKeys;
 }
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index a93f6c3..433f4a1 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -545,6 +545,7 @@
 
     if (graphicBuffer && parameters.layer.luts) {
         shader = mLutShader.lutShader(shader, parameters.layer.luts,
+                                      parameters.layer.sourceDataspace,
                                       toSkColorSpace(parameters.outputDataSpace));
     }
 
diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp
index 1e43ff3..5e9dfbb 100644
--- a/libs/renderengine/skia/filters/LutShader.cpp
+++ b/libs/renderengine/skia/filters/LutShader.cpp
@@ -15,11 +15,13 @@
  */
 #include "LutShader.h"
 
+#include <SkM44.h>
 #include <SkTileMode.h>
 #include <common/trace.h>
 #include <cutils/ashmem.h>
 #include <math/half.h>
 #include <sys/mman.h>
+#include <ui/ColorSpace.h>
 
 #include "include/core/SkColorSpace.h"
 #include "src/core/SkColorFilterPriv.h"
@@ -36,6 +38,8 @@
     uniform int size;
     uniform int key;
     uniform int dimension;
+    uniform vec3 luminanceCoefficients; // for CIE_Y
+
     vec4 main(vec2 xy) {
         float4 rgba = image.eval(xy);
         float3 linear = toLinearSrgb(rgba.rgb);
@@ -51,12 +55,16 @@
                 return float4(linear.r * gainR, linear.g * gainG, linear.b * gainB, rgba.a);
             // MAX_RGB
             } else if (key == 1) {
-                float4 rgba = image.eval(xy);
-                float3 linear = toLinearSrgb(rgba.rgb);
                 float maxRGB = max(linear.r, max(linear.g, linear.b));
                 float index = maxRGB * float(size - 1);
                 float gain = lut.eval(vec2(index, 0.0) + 0.5).r;
                 return float4(linear * gain, rgba.a);
+            // CIE_Y
+            } else if (key == 2) {
+                float y = dot(linear, luminanceCoefficients) / 3.0;
+                float index = y * float(size - 1);
+                float gain = lut.eval(vec2(index, 0.0) + 0.5).r;
+                return float4(linear * gain, rgba.a);
             }
         } else if (dimension == 3) {
             if (key == 0) {
@@ -110,11 +118,37 @@
         return rgba;
     })");
 
+// same as shader::toColorSpace function
+// TODO: put this function in a general place
+static ColorSpace toColorSpace(ui::Dataspace dataspace) {
+    switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            return ColorSpace::sRGB();
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            return ColorSpace::DisplayP3();
+        case HAL_DATASPACE_STANDARD_BT2020:
+        case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+            return ColorSpace::BT2020();
+        case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+            return ColorSpace::AdobeRGB();
+        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_BT470M:
+        case HAL_DATASPACE_STANDARD_FILM:
+        case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+        default:
+            return ColorSpace::sRGB();
+    }
+}
+
 sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input,
                                              const std::vector<float>& buffers,
                                              const int32_t offset, const int32_t length,
                                              const int32_t dimension, const int32_t size,
-                                             const int32_t samplingKey) {
+                                             const int32_t samplingKey,
+                                             ui::Dataspace srcDataspace) {
     SFTRACE_NAME("lut shader");
     std::vector<half> buffer(length * 4); // 4 is for RGBA
     auto d = static_cast<LutProperties::Dimension>(dimension);
@@ -133,12 +167,16 @@
         }
     }
     /**
-     * 1D Lut(rgba)
+     * 1D Lut RGB/MAX_RGB
      * (R0, 0, 0, 0)
      * (R1, 0, 0, 0)
+     *
+     * 1D Lut CIE_Y
+     * (Y0, 0, 0, 0)
+     * (Y1, 0, 0, 0)
      * ...
      *
-     * 3D Lut
+     * 3D Lut MAX_RGB
      * (R0, G0, B0, 0)
      * (R1, G1, B1, 0)
      * ...
@@ -162,6 +200,14 @@
     const int uSize = static_cast<int>(size);
     const int uKey = static_cast<int>(samplingKey);
     const int uDimension = static_cast<int>(dimension);
+    if (static_cast<LutProperties::SamplingKey>(samplingKey) == LutProperties::SamplingKey::CIE_Y) {
+        // Use predefined colorspaces of input dataspace so that we can get D65 illuminant
+        mat3 toXYZMatrix(toColorSpace(srcDataspace).getRGBtoXYZ());
+        mBuilder->uniform("luminanceCoefficients") =
+                SkV3{toXYZMatrix[0][1], toXYZMatrix[1][1], toXYZMatrix[2][1]};
+    } else {
+        mBuilder->uniform("luminanceCoefficients") = SkV3{1.f, 1.f, 1.f};
+    }
     mBuilder->uniform("size") = uSize;
     mBuilder->uniform("key") = uKey;
     mBuilder->uniform("dimension") = uDimension;
@@ -170,6 +216,7 @@
 
 sk_sp<SkShader> LutShader::lutShader(sk_sp<SkShader>& input,
                                      std::shared_ptr<gui::DisplayLuts> displayLuts,
+                                     ui::Dataspace srcDataspace,
                                      sk_sp<SkColorSpace> outColorSpace) {
     if (mBuilder == nullptr) {
         const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(kShader);
@@ -218,7 +265,7 @@
             }
             input = generateLutShader(input, buffers, offsets[i], bufferSizePerLut,
                                       lutProperties[i].dimension, lutProperties[i].size,
-                                      lutProperties[i].samplingKey);
+                                      lutProperties[i].samplingKey, srcDataspace);
         }
 
         auto colorXformLutToDst =
diff --git a/libs/renderengine/skia/filters/LutShader.h b/libs/renderengine/skia/filters/LutShader.h
index ce3e059..7c62fca 100644
--- a/libs/renderengine/skia/filters/LutShader.h
+++ b/libs/renderengine/skia/filters/LutShader.h
@@ -21,6 +21,7 @@
 
 #include <aidl/android/hardware/graphics/composer3/LutProperties.h>
 #include <gui/DisplayLuts.h>
+#include <ui/GraphicTypes.h>
 
 namespace android {
 namespace renderengine {
@@ -29,13 +30,13 @@
 class LutShader {
 public:
     sk_sp<SkShader> lutShader(sk_sp<SkShader>& input, std::shared_ptr<gui::DisplayLuts> displayLuts,
-                              sk_sp<SkColorSpace> outColorSpace);
+                              ui::Dataspace srcDataspace, sk_sp<SkColorSpace> outColorSpace);
 
 private:
     sk_sp<SkShader> generateLutShader(sk_sp<SkShader> input, const std::vector<float>& buffers,
                                       const int32_t offset, const int32_t length,
                                       const int32_t dimension, const int32_t size,
-                                      const int32_t samplingKey);
+                                      const int32_t samplingKey, ui::Dataspace srcDataspace);
     std::unique_ptr<SkRuntimeShaderBuilder> mBuilder;
 };