Adds support for bgra10xr loading.

Bug: skia: https://github.com/flutter/flutter/issues/148851
Change-Id: I79cbd7043638a0cb455c2477baabbcb4895a0a5d
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/861638
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Aaron Clarke <aaclarke@google.com>
diff --git a/skcms.cc b/skcms.cc
index 6c9c111..047f21b 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -2448,25 +2448,26 @@
 
 static size_t bytes_per_pixel(skcms_PixelFormat fmt) {
     switch (fmt >> 1) {   // ignore rgb/bgr
-        case skcms_PixelFormat_A_8             >> 1: return  1;
-        case skcms_PixelFormat_G_8             >> 1: return  1;
-        case skcms_PixelFormat_ABGR_4444       >> 1: return  2;
-        case skcms_PixelFormat_RGB_565         >> 1: return  2;
-        case skcms_PixelFormat_RGB_888         >> 1: return  3;
-        case skcms_PixelFormat_RGBA_8888       >> 1: return  4;
-        case skcms_PixelFormat_RGBA_8888_sRGB  >> 1: return  4;
-        case skcms_PixelFormat_RGBA_1010102    >> 1: return  4;
-        case skcms_PixelFormat_RGB_101010x_XR  >> 1: return  4;
-        case skcms_PixelFormat_RGB_161616LE    >> 1: return  6;
-        case skcms_PixelFormat_RGBA_16161616LE >> 1: return  8;
-        case skcms_PixelFormat_RGB_161616BE    >> 1: return  6;
-        case skcms_PixelFormat_RGBA_16161616BE >> 1: return  8;
-        case skcms_PixelFormat_RGB_hhh_Norm    >> 1: return  6;
-        case skcms_PixelFormat_RGBA_hhhh_Norm  >> 1: return  8;
-        case skcms_PixelFormat_RGB_hhh         >> 1: return  6;
-        case skcms_PixelFormat_RGBA_hhhh       >> 1: return  8;
-        case skcms_PixelFormat_RGB_fff         >> 1: return 12;
-        case skcms_PixelFormat_RGBA_ffff       >> 1: return 16;
+        case skcms_PixelFormat_A_8              >> 1: return  1;
+        case skcms_PixelFormat_G_8              >> 1: return  1;
+        case skcms_PixelFormat_ABGR_4444        >> 1: return  2;
+        case skcms_PixelFormat_RGB_565          >> 1: return  2;
+        case skcms_PixelFormat_RGB_888          >> 1: return  3;
+        case skcms_PixelFormat_RGBA_8888        >> 1: return  4;
+        case skcms_PixelFormat_RGBA_8888_sRGB   >> 1: return  4;
+        case skcms_PixelFormat_RGBA_1010102     >> 1: return  4;
+        case skcms_PixelFormat_RGB_101010x_XR   >> 1: return  4;
+        case skcms_PixelFormat_RGB_161616LE     >> 1: return  6;
+        case skcms_PixelFormat_RGBA_10101010_XR >> 1: return  8;
+        case skcms_PixelFormat_RGBA_16161616LE  >> 1: return  8;
+        case skcms_PixelFormat_RGB_161616BE     >> 1: return  6;
+        case skcms_PixelFormat_RGBA_16161616BE  >> 1: return  8;
+        case skcms_PixelFormat_RGB_hhh_Norm     >> 1: return  6;
+        case skcms_PixelFormat_RGBA_hhhh_Norm   >> 1: return  8;
+        case skcms_PixelFormat_RGB_hhh          >> 1: return  6;
+        case skcms_PixelFormat_RGBA_hhhh        >> 1: return  8;
+        case skcms_PixelFormat_RGB_fff          >> 1: return 12;
+        case skcms_PixelFormat_RGBA_ffff        >> 1: return 16;
     }
     assert(false);
     return 0;
@@ -2559,24 +2560,25 @@
 
     switch (srcFmt >> 1) {
         default: return false;
-        case skcms_PixelFormat_A_8             >> 1: add_op(Op::load_a8);         break;
-        case skcms_PixelFormat_G_8             >> 1: add_op(Op::load_g8);         break;
-        case skcms_PixelFormat_ABGR_4444       >> 1: add_op(Op::load_4444);       break;
-        case skcms_PixelFormat_RGB_565         >> 1: add_op(Op::load_565);        break;
-        case skcms_PixelFormat_RGB_888         >> 1: add_op(Op::load_888);        break;
-        case skcms_PixelFormat_RGBA_8888       >> 1: add_op(Op::load_8888);       break;
-        case skcms_PixelFormat_RGBA_1010102    >> 1: add_op(Op::load_1010102);    break;
-        case skcms_PixelFormat_RGB_101010x_XR  >> 1: add_op(Op::load_101010x_XR); break;
-        case skcms_PixelFormat_RGB_161616LE    >> 1: add_op(Op::load_161616LE);   break;
-        case skcms_PixelFormat_RGBA_16161616LE >> 1: add_op(Op::load_16161616LE); break;
-        case skcms_PixelFormat_RGB_161616BE    >> 1: add_op(Op::load_161616BE);   break;
-        case skcms_PixelFormat_RGBA_16161616BE >> 1: add_op(Op::load_16161616BE); break;
-        case skcms_PixelFormat_RGB_hhh_Norm    >> 1: add_op(Op::load_hhh);        break;
-        case skcms_PixelFormat_RGBA_hhhh_Norm  >> 1: add_op(Op::load_hhhh);       break;
-        case skcms_PixelFormat_RGB_hhh         >> 1: add_op(Op::load_hhh);        break;
-        case skcms_PixelFormat_RGBA_hhhh       >> 1: add_op(Op::load_hhhh);       break;
-        case skcms_PixelFormat_RGB_fff         >> 1: add_op(Op::load_fff);        break;
-        case skcms_PixelFormat_RGBA_ffff       >> 1: add_op(Op::load_ffff);       break;
+        case skcms_PixelFormat_A_8              >> 1: add_op(Op::load_a8);          break;
+        case skcms_PixelFormat_G_8              >> 1: add_op(Op::load_g8);          break;
+        case skcms_PixelFormat_ABGR_4444        >> 1: add_op(Op::load_4444);        break;
+        case skcms_PixelFormat_RGB_565          >> 1: add_op(Op::load_565);         break;
+        case skcms_PixelFormat_RGB_888          >> 1: add_op(Op::load_888);         break;
+        case skcms_PixelFormat_RGBA_8888        >> 1: add_op(Op::load_8888);        break;
+        case skcms_PixelFormat_RGBA_1010102     >> 1: add_op(Op::load_1010102);     break;
+        case skcms_PixelFormat_RGB_101010x_XR   >> 1: add_op(Op::load_101010x_XR);  break;
+        case skcms_PixelFormat_RGBA_10101010_XR >> 1: add_op(Op::load_10101010_XR); break;
+        case skcms_PixelFormat_RGB_161616LE     >> 1: add_op(Op::load_161616LE);    break;
+        case skcms_PixelFormat_RGBA_16161616LE  >> 1: add_op(Op::load_16161616LE);  break;
+        case skcms_PixelFormat_RGB_161616BE     >> 1: add_op(Op::load_161616BE);    break;
+        case skcms_PixelFormat_RGBA_16161616BE  >> 1: add_op(Op::load_16161616BE);  break;
+        case skcms_PixelFormat_RGB_hhh_Norm     >> 1: add_op(Op::load_hhh);         break;
+        case skcms_PixelFormat_RGBA_hhhh_Norm   >> 1: add_op(Op::load_hhhh);        break;
+        case skcms_PixelFormat_RGB_hhh          >> 1: add_op(Op::load_hhh);         break;
+        case skcms_PixelFormat_RGBA_hhhh        >> 1: add_op(Op::load_hhhh);        break;
+        case skcms_PixelFormat_RGB_fff          >> 1: add_op(Op::load_fff);         break;
+        case skcms_PixelFormat_RGBA_ffff        >> 1: add_op(Op::load_ffff);        break;
 
         case skcms_PixelFormat_RGBA_8888_sRGB >> 1:
             add_op(Op::load_8888);
diff --git a/src/Transform_inl.h b/src/Transform_inl.h
index 69c935e..b9c27ac 100644
--- a/src/Transform_inl.h
+++ b/src/Transform_inl.h
@@ -902,6 +902,17 @@
     b = cast<F>((rgba >> 20) & 0x3ff) * (1/1023.0f) * range + min;
 }
 
+STAGE(load_10101010_XR, NoCtx) {
+    static constexpr float min = -0.752941f;
+    static constexpr float max = 1.25098f;
+    static constexpr float range = max - min;
+    U64 rgba = load<U64>(src + 8*i);
+    r = cast<F>((rgba >>  0) & 0x3ff) * (1/1023.0f) * range + min;
+    g = cast<F>((rgba >> 16) & 0x3ff) * (1/1023.0f) * range + min;
+    b = cast<F>((rgba >> 32) & 0x3ff) * (1/1023.0f) * range + min;
+    a = cast<F>((rgba >> 48) & 0x3ff) * (1/1023.0f) * range + min;
+}
+
 STAGE(load_161616LE, NoCtx) {
     uintptr_t ptr = (uintptr_t)(src + 6*i);
     assert( (ptr & 1) == 0 );                   // src must be 2-byte aligned for this
diff --git a/src/skcms_Transform.h b/src/skcms_Transform.h
index 049bf01..9f02e79 100644
--- a/src/skcms_Transform.h
+++ b/src/skcms_Transform.h
@@ -26,6 +26,7 @@
     M(load_8888)          \
     M(load_1010102)       \
     M(load_101010x_XR)    \
+    M(load_10101010_XR)   \
     M(load_161616LE)      \
     M(load_16161616LE)    \
     M(load_161616BE)      \
diff --git a/src/skcms_public.h b/src/skcms_public.h
index 9e06016..3510f89 100644
--- a/src/skcms_public.h
+++ b/src/skcms_public.h
@@ -319,6 +319,8 @@
 
     skcms_PixelFormat_RGB_101010x_XR,  // Note: This is located here to signal no clamping.
     skcms_PixelFormat_BGR_101010x_XR,  // Compatible with MTLPixelFormatBGR10_XR.
+    skcms_PixelFormat_RGBA_10101010_XR,  // Note: This is located here to signal no clamping.
+    skcms_PixelFormat_BGRA_10101010_XR,  // Compatible with MTLPixelFormatBGRA10_XR.
 } skcms_PixelFormat;
 
 // We always store any alpha channel linearly.  In the chart below, tf-1() is the inverse
diff --git a/tests.c b/tests.c
index 741bdc3..2c463a4 100644
--- a/tests.c
+++ b/tests.c
@@ -420,6 +420,26 @@
     expect(((dst2 >> 16) & 0xff) == 0);
 }
 
+static void test_FormatConversions_10101010_xr(void) {
+    uint64_t src[2];
+    src[0] = 384LL | (894LL << 16) | (384LL << 32) | (639LL << 48);
+    src[1] = 384LL | (639LL << 16) | (384LL << 32) | (894LL << 48);
+    uint32_t dst[2] = {0xffffffff, 0xffffffff};
+    expect(skcms_Transform(&src, skcms_PixelFormat_BGRA_10101010_XR,
+                           skcms_AlphaFormat_Unpremul, NULL, &dst,
+                           skcms_PixelFormat_BGRA_8888,
+                           skcms_AlphaFormat_Unpremul, NULL, 2));
+    expect(((dst[0] >> 0) & 0xff) == 0);
+    expect(((dst[0] >> 8) & 0xff) == 255);
+    expect(((dst[0] >> 16) & 0xff) == 0);
+    expect(((dst[0] >> 24) & 0xff) == 127);
+
+    expect(((dst[1] >> 0) & 0xff) == 0);
+    expect(((dst[1] >> 8) & 0xff) == 127);
+    expect(((dst[1] >> 16) & 0xff) == 0);
+    expect(((dst[1] >> 24) & 0xff) == 255);
+}
+
 static void test_FormatConversions_half(void) {
     uint16_t src[] = {
         0x3c00,  // 1.0
@@ -1852,6 +1872,7 @@
     test_FormatConversions_565();
     test_FormatConversions_101010();
     test_FormatConversions_101010_xr();
+    test_FormatConversions_10101010_xr();
     test_FormatConversions_16161616LE();
     test_FormatConversions_161616LE();
     test_FormatConversions_16161616BE();