Add ColorSpace::createLUT

Generates a 3D LUT of a specified size. The generated LUT is meant to
be used as a 3D OpenGL texture for fast color space conversions in
shaders. This will be used to convert from P3 bitmaps to scRGB.

Bug: 32984164
Test: colorspace_test
Change-Id: I01f7276f885c71bde480e79260013d62786b377c
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
index 15e6628..b1863df 100644
--- a/include/ui/ColorSpace.h
+++ b/include/ui/ColorSpace.h
@@ -180,6 +180,11 @@
             return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
         }
 
+        constexpr float3 transformLinear(const float3& v) const noexcept {
+            float3 linear = apply(v, mSource.getClamper());
+            return apply(mTransform * linear, mDestination.getClamper());
+        }
+
     private:
         const ColorSpace& mSource;
         const ColorSpace& mDestination;
@@ -190,6 +195,15 @@
         return Connector(src, dst);
     }
 
+    // Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
+    // The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
+    // The generated 3D LUT is meant to be used as a 3D texture and its Y
+    // axis is thus already flipped
+    // The source color space must define its values in the domain [0..1]
+    // The generated LUT transforms from gamma space to gamma space
+    static std::unique_ptr<float3> createLUT(uint32_t size,
+            const ColorSpace& src, const ColorSpace& dst);
+
 private:
     static constexpr mat3 computeXYZMatrix(
             const std::array<float2, 3>& primaries, const float2& whitePoint);
diff --git a/include/ui/TVecHelpers.h b/include/ui/TVecHelpers.h
index 4934338..1884608 100644
--- a/include/ui/TVecHelpers.h
+++ b/include/ui/TVecHelpers.h
@@ -324,7 +324,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE equal(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE equal(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] == rv[i];
@@ -334,7 +334,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE notEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE notEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] != rv[i];
@@ -344,7 +344,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE lessThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE lessThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] < rv[i];
@@ -354,7 +354,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] <= rv[i];
@@ -364,7 +364,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE greaterThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE greaterThan(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] > rv[i];
@@ -374,7 +374,7 @@
 
     template<typename RT>
     friend inline
-    constexpr VECTOR<bool> PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+    CONSTEXPR VECTOR<bool> PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
         VECTOR<bool> r;
         for (size_t i = 0; i < lv.size(); i++) {
             r[i] = lv[i] >= rv[i];