D3D11: support RGB10A2Unorm in B2T shaders

Bug: 348653642
Change-Id: I2815bc5e5a3ccca7ed32f268832b2a4b69d7f8d6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/232214
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/src/dawn/native/BlitBufferToTexture.cpp b/src/dawn/native/BlitBufferToTexture.cpp
index 1f40095..f5a926c 100644
--- a/src/dawn/native/BlitBufferToTexture.cpp
+++ b/src/dawn/native/BlitBufferToTexture.cpp
@@ -126,6 +126,17 @@
 }
 )";
 
+constexpr std::string_view kUnpackRGB10A2Unorm = R"(
+fn unpackData(byteOffset: u32) -> vec4f {
+    let data = loadU32(byteOffset);
+    let r = f32((data & 0x3ff)) / 1023.0;
+    let g = f32(((data >> 10) & 0x3ff)) / 1023.0;
+    let b = f32(((data >> 20) & 0x3ff)) / 1023.0;
+    let a = f32(((data >> 30) & 0x3)) / 3.0;
+    return vec4f(r, g, b, a);
+}
+)";
+
 constexpr std::string_view kUnpackR16Float = R"(
 fn unpackData(byteOffset: u32) -> vec4f {
     return vec4f(unpack2x16float(loadU16AsU32(byteOffset)), 0.0, 1.0);
@@ -211,6 +222,10 @@
             pixelSize = 4;
             ss << kUnpackBGRA8Unorm;
             break;
+        case wgpu::TextureFormat::RGB10A2Unorm:
+            pixelSize = 4;
+            ss << kUnpackRGB10A2Unorm;
+            break;
         case wgpu::TextureFormat::R16Float:
             pixelSize = 2;
             ss << kUnpackR16Float;
@@ -328,6 +343,7 @@
         case wgpu::TextureFormat::RG8Unorm:
         case wgpu::TextureFormat::RGBA8Unorm:
         case wgpu::TextureFormat::BGRA8Unorm:
+        case wgpu::TextureFormat::RGB10A2Unorm:
         case wgpu::TextureFormat::R16Float:
         case wgpu::TextureFormat::R16Unorm:
         case wgpu::TextureFormat::RG16Float:
diff --git a/src/dawn/tests/end2end/CopyTests.cpp b/src/dawn/tests/end2end/CopyTests.cpp
index 3b54665..745ede8 100644
--- a/src/dawn/tests/end2end/CopyTests.cpp
+++ b/src/dawn/tests/end2end/CopyTests.cpp
@@ -55,92 +55,47 @@
 
 template <typename T, size_t NumComponents>
 struct Color {
-  public:
     static constexpr size_t kNumComponents = NumComponents;
     static constexpr size_t kDataSize = sizeof(T) * NumComponents;
+    using ComponentRepresentation = T;
 
-    Color() = default;
-    explicit Color(T value) { std::fill(components, components + NumComponents, value); }
-
-    bool Equals(const Color& other, const Color& tolerance) const {
-        for (size_t i = 0; i < NumComponents; ++i) {
-            if (Diff(components[i], other.components[i]) > tolerance.components[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    std::string ToString() const {
-        std::ostringstream ss;
-        for (size_t i = 0; i < NumComponents; ++i) {
-            Print(ss, components[i]);
-
-            if (i < NumComponents - 1) {
-                ss << " ";
-            }
-        }
-
-        return ss.str();
-    }
-
-  protected:
-    static T Diff(T lhs, T rhs) {
-        if constexpr (std::is_integral_v<T>) {
-            return std::abs(static_cast<int64_t>(lhs) - static_cast<int64_t>(rhs));
-        }
-        return std::abs(lhs - rhs);
-    }
-
-    static std::ostream& Print(std::ostream& stream, T component) {
-        if constexpr (std::is_same_v<T, uint8_t>) {
-            return stream << static_cast<int>(component);
-        }
-        return stream << component;
-    }
+    // Get representation of one component.
+    T GetCompRep(size_t idx) const { return components[idx]; }
 
     T components[NumComponents] = {};
 };
 
 template <size_t NumComponents>
 struct ColorF16 : public Color<uint16_t, NumComponents> {
-  public:
-    using Base = Color<uint16_t, NumComponents>;
-    using Base::Base;
+    using ComponentRepresentation = float;
 
-    explicit ColorF16(float value) : Base(Float32ToFloat16(value)) {}
+    // Get representation of one component.
+    float GetCompRep(size_t idx) const { return Float16ToFloat32(this->components[idx]); }
+};
 
-    bool Equals(const ColorF16& other, const ColorF16& tolerance) const {
-        for (size_t i = 0; i < NumComponents; ++i) {
-            if (abs(Float16ToFloat32(this->components[i]) - Float16ToFloat32(other.components[i])) >
-                Float16ToFloat32(tolerance.components[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
+struct ColorRGB10A2 {
+    static constexpr size_t kNumComponents = 4;
+    static constexpr size_t kDataSize = sizeof(uint32_t);
+    using ComponentRepresentation = uint32_t;
 
-    std::string ToString() const {
-        std::ostringstream ss;
-        for (size_t i = 0; i < NumComponents; ++i) {
-            ss << Float16ToFloat32(this->components[i]);
-            if (i < NumComponents - 1) {
-                ss << " ";
-            }
-        }
+    // Get representation of one component.
+    uint32_t GetCompRep(size_t idx) const { return (mPackedColor >> (10 * idx)) & 0x3ff; }
 
-        return ss.str();
-    }
+    uint32_t mPackedColor = 0;
 };
 
 static_assert(sizeof(Color<uint8_t, 1>) == 1, "Unexpected padding");
 static_assert(sizeof(Color<uint8_t, 2>) == 2, "Unexpected padding");
 static_assert(sizeof(Color<uint16_t, 1>) == 2, "Unexpected padding");
+static_assert(sizeof(ColorRGB10A2) == 4, "Unexpected padding");
 
 template <typename ColorType>
 class ColorExpectation : public detail::CustomTextureExpectation {
   public:
-    ColorExpectation(const ColorType* expected, size_t count, ColorType tolerance)
+    static constexpr size_t kNumComponents = ColorType::kNumComponents;
+    using CompRepType = ColorType::ComponentRepresentation;
+
+    ColorExpectation(const ColorType* expected, size_t count, CompRepType tolerance)
         : mTolerance(tolerance) {
         mExpected.assign(expected, expected + count);
     }
@@ -152,18 +107,61 @@
         const ColorType* actual = static_cast<const ColorType*>(data);
 
         for (size_t i = 0; i < mExpected.size(); ++i) {
-            if (!mExpected[i].Equals(actual[i], mTolerance)) {
+            if (!AreEqual(mExpected[i], actual[i])) {
                 return testing::AssertionFailure()
-                       << "Expected data[" << i << "] to be " << mExpected[i].ToString()
-                       << ", actual " << actual[i].ToString() << "\n";
+                       << "Expected data[" << i << "] to be " << ToString(mExpected[i])
+                       << ", actual " << ToString(actual[i]) << "\n";
             }
         }
         return testing::AssertionSuccess();
     }
 
   private:
+    static CompRepType GetComponent(const ColorType& color, size_t idx) {
+        DAWN_ASSERT(idx <= kNumComponents);
+        return color.GetCompRep(idx);
+    }
+
+    static CompRepType Diff(CompRepType lhs, CompRepType rhs) {
+        if constexpr (std::is_integral_v<CompRepType>) {
+            return std::abs(static_cast<int64_t>(lhs) - static_cast<int64_t>(rhs));
+        } else {
+            return std::abs(lhs - rhs);
+        }
+    }
+
+    static std::ostream& Print(std::ostream& stream, CompRepType component) {
+        if constexpr (std::is_same_v<CompRepType, uint8_t>) {
+            return stream << static_cast<int>(component);
+        } else {
+            return stream << component;
+        }
+    }
+
+    static std::string ToString(const ColorType& color) {
+        std::ostringstream ss;
+        for (size_t i = 0; i < kNumComponents; ++i) {
+            Print(ss, GetComponent(color, i));
+
+            if (i < kNumComponents - 1) {
+                ss << " ";
+            }
+        }
+
+        return ss.str();
+    }
+
+    bool AreEqual(const ColorType& lhs, const ColorType& rhs) const {
+        for (size_t i = 0; i < kNumComponents; ++i) {
+            if (Diff(GetComponent(lhs, i), GetComponent(rhs, i)) > mTolerance) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     std::vector<ColorType> mExpected;
-    ColorType mTolerance;
+    const CompRepType mTolerance;
 };
 
 class CopyTests {
@@ -644,52 +642,56 @@
         switch (textureSpec.format) {
             case wgpu::TextureFormat::R8Unorm:
                 DoTestImpl<Color<uint8_t, 1>>(textureSpec, bufferSpec, copySize, dimension,
-                                              /*tolerance=*/Color<uint8_t, 1>(1));
+                                              /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::RG8Unorm:
                 DoTestImpl<Color<uint8_t, 2>>(textureSpec, bufferSpec, copySize, dimension,
-                                              /*tolerance=*/Color<uint8_t, 2>(1));
+                                              /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::RGBA8Unorm:
             case wgpu::TextureFormat::BGRA8Unorm:
                 DoTestImpl<Color<uint8_t, 4>>(textureSpec, bufferSpec, copySize, dimension,
-                                              /*tolerance=*/Color<uint8_t, 4>(1));
+                                              /*tolerance=*/1);
+                break;
+            case wgpu::TextureFormat::RGB10A2Unorm:
+                DoTestImpl<ColorRGB10A2>(textureSpec, bufferSpec, copySize, dimension,
+                                         /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::R16Float:
                 DoTestImpl<ColorF16<1>>(textureSpec, bufferSpec, copySize, dimension,
-                                        /*tolerance=*/ColorF16<1>(0.001f));
+                                        /*tolerance=*/0.001f);
                 break;
             case wgpu::TextureFormat::R16Unorm:
                 DoTestImpl<Color<uint16_t, 1>>(textureSpec, bufferSpec, copySize, dimension,
-                                               /*tolerance=*/Color<uint16_t, 1>(1));
+                                               /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::RG16Float:
                 DoTestImpl<ColorF16<2>>(textureSpec, bufferSpec, copySize, dimension,
-                                        /*tolerance=*/ColorF16<2>(0.001f));
+                                        /*tolerance=*/0.001f);
                 break;
             case wgpu::TextureFormat::RG16Unorm:
                 DoTestImpl<Color<uint16_t, 2>>(textureSpec, bufferSpec, copySize, dimension,
-                                               /*tolerance=*/Color<uint16_t, 2>(1));
+                                               /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::RGBA16Float:
                 DoTestImpl<ColorF16<4>>(textureSpec, bufferSpec, copySize, dimension,
-                                        /*tolerance=*/ColorF16<4>(0.001f));
+                                        /*tolerance=*/0.001f);
                 break;
             case wgpu::TextureFormat::RGBA16Unorm:
                 DoTestImpl<Color<uint16_t, 4>>(textureSpec, bufferSpec, copySize, dimension,
-                                               /*tolerance=*/Color<uint16_t, 4>(1));
+                                               /*tolerance=*/1);
                 break;
             case wgpu::TextureFormat::R32Float:
                 DoTestImpl<Color<float, 1>>(textureSpec, bufferSpec, copySize, dimension,
-                                            /*tolerance=*/Color<float, 1>(0.0001f));
+                                            /*tolerance=*/0.0001f);
                 break;
             case wgpu::TextureFormat::RG32Float:
                 DoTestImpl<Color<float, 2>>(textureSpec, bufferSpec, copySize, dimension,
-                                            /*tolerance=*/Color<float, 2>(0.0001f));
+                                            /*tolerance=*/0.0001f);
                 break;
             case wgpu::TextureFormat::RGBA32Float:
                 DoTestImpl<Color<float, 4>>(textureSpec, bufferSpec, copySize, dimension,
-                                            /*tolerance=*/Color<float, 4>(0.0001f));
+                                            /*tolerance=*/0.0001f);
                 break;
             default:
                 DAWN_UNREACHABLE();
@@ -701,7 +703,7 @@
                     const BufferSpec& bufferSpec,
                     const wgpu::Extent3D& copySize,
                     wgpu::TextureDimension dimension,
-                    PixelType tolerance = {}) {
+                    PixelType::ComponentRepresentation tolerance = {}) {
         const uint32_t bytesPerTexel = PixelType::kDataSize;
         DAWN_ASSERT(bytesPerTexel == utils::GetTexelBlockSizeInBytes(textureSpec.format));
         const utils::TextureDataCopyLayout copyLayout =
@@ -2799,6 +2801,8 @@
                             wgpu::TextureFormat::RG8Unorm,
                             wgpu::TextureFormat::RGBA8Unorm,
 
+                            wgpu::TextureFormat::RGB10A2Unorm,
+
                             wgpu::TextureFormat::R16Float,
                             wgpu::TextureFormat::R16Unorm,