Add tests about clearing with big integer values

This patch adds several dawn_end2end_tests as a preparation to support
clearing color attachments with arbitrary 32-bit integer values on
D3D12.

Bug: dawn:537
Test: dawn_end2end_tests
Change-Id: I5e5232d4ebb2ed0e0da007fea101ed13f972ce9e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98103
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/tests/end2end/RenderPassLoadOpTests.cpp b/src/dawn/tests/end2end/RenderPassLoadOpTests.cpp
index cc989a7..5a2dce9 100644
--- a/src/dawn/tests/end2end/RenderPassLoadOpTests.cpp
+++ b/src/dawn/tests/end2end/RenderPassLoadOpTests.cpp
@@ -497,6 +497,225 @@
     }
 }
 
+// Test clearing multiple color attachments with different big integers can still work correctly.
+TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigInt32ValuesOnMultipleColorAttachments) {
+    // TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
+    // to large values on D3D12.
+    DAWN_SUPPRESS_TEST_IF(IsD3D12());
+
+    // TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
+    DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
+
+    // TODO(crbug.com/dawn/1463): Re-enable, might be the same as above just on
+    // 12.4 instead of 11.5.
+    DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(12, 4));
+
+    constexpr int32_t kMaxInt32RepresentableInFloat = 1 << std::numeric_limits<float>::digits;
+    constexpr int32_t kMinInt32RepresentableInFloat = -kMaxInt32RepresentableInFloat;
+
+    using TestCase = std::tuple<wgpu::TextureFormat, wgpu::Color, std::array<int32_t, 4>>;
+
+    constexpr std::array<TestCase, kMaxColorAttachments> kTestCases = {{
+        {wgpu::TextureFormat::R32Sint,
+         {kMaxInt32RepresentableInFloat, 0, 0, 0},
+         {kMaxInt32RepresentableInFloat, 0, 0, 0}},
+        {wgpu::TextureFormat::R32Sint,
+         {kMaxInt32RepresentableInFloat + 1, 0, 0, 0},
+         {kMaxInt32RepresentableInFloat + 1, 0, 0, 0}},
+        {wgpu::TextureFormat::R32Sint,
+         {kMinInt32RepresentableInFloat, 0, 0, 0},
+         {kMinInt32RepresentableInFloat, 0, 0, 0}},
+        {wgpu::TextureFormat::R32Sint,
+         {kMinInt32RepresentableInFloat - 1, 0, 0, 0},
+         {kMinInt32RepresentableInFloat - 1, 0, 0, 0}},
+        {wgpu::TextureFormat::RG32Sint,
+         {kMaxInt32RepresentableInFloat, kMaxInt32RepresentableInFloat + 1, 0, 0},
+         {kMaxInt32RepresentableInFloat, kMaxInt32RepresentableInFloat + 1, 0, 0}},
+        {wgpu::TextureFormat::RG32Sint,
+         {kMinInt32RepresentableInFloat, kMinInt32RepresentableInFloat - 1, 0, 0},
+         {kMinInt32RepresentableInFloat, kMinInt32RepresentableInFloat - 1, 0, 0}},
+        {wgpu::TextureFormat::RGBA32Sint,
+         {kMaxInt32RepresentableInFloat, kMinInt32RepresentableInFloat,
+          kMaxInt32RepresentableInFloat + 1, kMinInt32RepresentableInFloat - 1},
+         {kMaxInt32RepresentableInFloat, kMinInt32RepresentableInFloat,
+          kMaxInt32RepresentableInFloat + 1, kMinInt32RepresentableInFloat - 1}},
+        {wgpu::TextureFormat::RGBA32Sint,
+         {kMaxInt32RepresentableInFloat, kMinInt32RepresentableInFloat,
+          kMaxInt32RepresentableInFloat - 1, kMinInt32RepresentableInFloat + 1},
+         {kMaxInt32RepresentableInFloat, kMinInt32RepresentableInFloat,
+          kMaxInt32RepresentableInFloat - 1, kMinInt32RepresentableInFloat + 1}},
+    }};
+
+    std::array<wgpu::Texture, kMaxColorAttachments> textures;
+
+    wgpu::TextureDescriptor textureDescriptor = {};
+    textureDescriptor.size = {1, 1, 1};
+    textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
+
+    std::array<wgpu::RenderPassColorAttachment, kMaxColorAttachments> colorAttachmentsInfo;
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+        textureDescriptor.format = std::get<0>(kTestCases[i]);
+        textures[i] = device.CreateTexture(&textureDescriptor);
+
+        colorAttachmentsInfo[i].view = textures[i].CreateView();
+        colorAttachmentsInfo[i].loadOp = wgpu::LoadOp::Clear;
+        colorAttachmentsInfo[i].storeOp = wgpu::StoreOp::Store;
+        colorAttachmentsInfo[i].clearValue = std::get<1>(kTestCases[i]);
+    }
+
+    wgpu::RenderPassDescriptor renderPassDescriptor = {};
+    renderPassDescriptor.colorAttachmentCount = kMaxColorAttachments;
+    renderPassDescriptor.colorAttachments = colorAttachmentsInfo.data();
+    wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
+    renderPass.End();
+
+    std::array<wgpu::Buffer, kMaxColorAttachments> outputBuffers;
+    for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+        wgpu::BufferDescriptor bufferDescriptor = {};
+        bufferDescriptor.size = sizeof(int32_t) * 4;
+        bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+        outputBuffers[i] = device.CreateBuffer(&bufferDescriptor);
+
+        wgpu::ImageCopyTexture imageCopyTexture =
+            utils::CreateImageCopyTexture(textures[i], 0, {0, 0, 0});
+        wgpu::ImageCopyBuffer imageCopyBuffer =
+            utils::CreateImageCopyBuffer(outputBuffers[i], 0, kTextureBytesPerRowAlignment);
+        encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &textureDescriptor.size);
+    }
+
+    wgpu::CommandBuffer commandBuffer = encoder.Finish();
+    queue.Submit(1, &commandBuffer);
+
+    for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+        const uint8_t* expected =
+            reinterpret_cast<const uint8_t*>(std::get<2>(kTestCases[i]).data());
+        EXPECT_BUFFER_U8_RANGE_EQ(expected, outputBuffers[i], 0,
+                                  sizeof(std::get<2>(kTestCases[i])));
+    }
+}
+
+// Test clearing multiple color attachments with different big unsigned integers can still work
+// correctly.
+TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigUInt32ValuesOnMultipleColorAttachments) {
+    // TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
+    // to large values on D3D12.
+    DAWN_SUPPRESS_TEST_IF(IsD3D12());
+
+    // TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
+    DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
+
+    // TODO(crbug.com/dawn/1463): Re-enable, might be the same as above just on
+    // 12.4 instead of 11.5.
+    DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(12, 4));
+
+    constexpr int32_t kMaxUInt32RepresentableInFloat = 1 << std::numeric_limits<float>::digits;
+
+    using TestCase = std::tuple<wgpu::TextureFormat, wgpu::Color, std::array<uint32_t, 4>>;
+
+    std::array<float, 4> testColorForRGBA32Float = {
+        kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat - 1,
+        kMaxUInt32RepresentableInFloat - 2, kMaxUInt32RepresentableInFloat - 3};
+    std::array<uint32_t, 4> expectedDataForRGBA32Float;
+    for (uint32_t i = 0; i < expectedDataForRGBA32Float.size(); ++i) {
+        expectedDataForRGBA32Float[i] = *(reinterpret_cast<uint32_t*>(&testColorForRGBA32Float[i]));
+    }
+
+    const std::array<TestCase, kMaxColorAttachments> kTestCases = {{
+        {wgpu::TextureFormat::R32Uint,
+         {kMaxUInt32RepresentableInFloat, 0, 0, 0},
+         {kMaxUInt32RepresentableInFloat, 0, 0, 0}},
+        {wgpu::TextureFormat::R32Uint,
+         {kMaxUInt32RepresentableInFloat + 1, 0, 0, 0},
+         {kMaxUInt32RepresentableInFloat + 1, 0, 0, 0}},
+        {wgpu::TextureFormat::RG32Uint,
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat, 0, 0},
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat, 0, 0}},
+        {wgpu::TextureFormat::RG32Uint,
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat + 1, 0, 0},
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat + 1, 0, 0}},
+        {wgpu::TextureFormat::RGBA32Uint,
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat + 1,
+          kMaxUInt32RepresentableInFloat - 1, kMaxUInt32RepresentableInFloat - 2},
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat + 1,
+          kMaxUInt32RepresentableInFloat - 1, kMaxUInt32RepresentableInFloat - 2}},
+        {wgpu::TextureFormat::RGBA32Sint,
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat - 1,
+          kMaxUInt32RepresentableInFloat - 2, kMaxUInt32RepresentableInFloat - 3},
+         {static_cast<int32_t>(kMaxUInt32RepresentableInFloat),
+          static_cast<int32_t>(kMaxUInt32RepresentableInFloat - 1),
+          static_cast<int32_t>(kMaxUInt32RepresentableInFloat - 2),
+          static_cast<int32_t>(kMaxUInt32RepresentableInFloat - 3)}},
+        {wgpu::TextureFormat::RGBA32Float,
+         {kMaxUInt32RepresentableInFloat, kMaxUInt32RepresentableInFloat - 1,
+          kMaxUInt32RepresentableInFloat - 2, kMaxUInt32RepresentableInFloat - 3},
+         expectedDataForRGBA32Float},
+        {wgpu::TextureFormat::Undefined,
+         {kMaxUInt32RepresentableInFloat + 1, kMaxUInt32RepresentableInFloat + 1, 0, 0},
+         {0, 0, 0, 0}},
+    }};
+
+    std::array<wgpu::Texture, kMaxColorAttachments> textures;
+
+    wgpu::TextureDescriptor textureDescriptor = {};
+    textureDescriptor.size = {1, 1, 1};
+    textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
+
+    std::array<wgpu::RenderPassColorAttachment, kMaxColorAttachments> colorAttachmentsInfo;
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+        wgpu::TextureFormat format = std::get<0>(kTestCases[i]);
+        if (format == wgpu::TextureFormat::Undefined) {
+            textures[i] = nullptr;
+            colorAttachmentsInfo[i].view = nullptr;
+            continue;
+        }
+
+        textureDescriptor.format = format;
+        textures[i] = device.CreateTexture(&textureDescriptor);
+
+        colorAttachmentsInfo[i].view = textures[i].CreateView();
+        colorAttachmentsInfo[i].loadOp = wgpu::LoadOp::Clear;
+        colorAttachmentsInfo[i].storeOp = wgpu::StoreOp::Store;
+        colorAttachmentsInfo[i].clearValue = std::get<1>(kTestCases[i]);
+    }
+
+    wgpu::RenderPassDescriptor renderPassDescriptor = {};
+    renderPassDescriptor.colorAttachmentCount = kMaxColorAttachments;
+    renderPassDescriptor.colorAttachments = colorAttachmentsInfo.data();
+    wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
+    renderPass.End();
+
+    std::array<wgpu::Buffer, kMaxColorAttachments> outputBuffers;
+    for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
+        wgpu::TextureFormat format = std::get<0>(kTestCases[i]);
+        if (format == wgpu::TextureFormat::Undefined) {
+            continue;
+        }
+
+        wgpu::BufferDescriptor bufferDescriptor = {};
+        bufferDescriptor.size = sizeof(int32_t) * 4;
+        bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+        outputBuffers[i] = device.CreateBuffer(&bufferDescriptor);
+
+        wgpu::ImageCopyTexture imageCopyTexture =
+            utils::CreateImageCopyTexture(textures[i], 0, {0, 0, 0});
+        wgpu::ImageCopyBuffer imageCopyBuffer =
+            utils::CreateImageCopyBuffer(outputBuffers[i], 0, kTextureBytesPerRowAlignment);
+        encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &textureDescriptor.size);
+    }
+
+    wgpu::CommandBuffer commandBuffer = encoder.Finish();
+    queue.Submit(1, &commandBuffer);
+
+    for (uint32_t i = 0; i < kMaxColorAttachments - 1; ++i) {
+        const uint8_t* expected =
+            reinterpret_cast<const uint8_t*>(std::get<2>(kTestCases[i]).data());
+        EXPECT_BUFFER_U8_RANGE_EQ(expected, outputBuffers[i], 0,
+                                  sizeof(std::get<2>(kTestCases[i])));
+    }
+}
+
 DAWN_INSTANTIATE_TEST(RenderPassLoadOpTests,
                       D3D12Backend(),
                       MetalBackend(),