Implement copying between a buffer and a texture 2D array on Vulkan (#257)

Implement copying between a buffer and a texture 2D array on Vulkan

This patch implements the creation of a 2D array texture and data
copying between a buffer and a layer of a 2D array texture on
Vulkan back-ends.

TEST=dawn_end2end_tests
diff --git a/dawn.json b/dawn.json
index 0300bc6..b5cfc2b 100644
--- a/dawn.json
+++ b/dawn.json
@@ -345,7 +345,8 @@
                     {"name": "width", "type": "uint32_t"},
                     {"name": "height", "type": "uint32_t"},
                     {"name": "depth", "type": "uint32_t"},
-                    {"name": "level", "type": "uint32_t"}
+                    {"name": "level", "type": "uint32_t"},
+                    {"name": "slice", "type": "uint32_t"}
                 ],
                 "TODO": [
                     "Make pretty with Offset and Extents structures",
@@ -365,6 +366,7 @@
                     {"name": "height", "type": "uint32_t"},
                     {"name": "depth", "type": "uint32_t"},
                     {"name": "level", "type": "uint32_t"},
+                    {"name": "slice", "type": "uint32_t"},
                     {"name": "buffer", "type": "buffer"},
                     {"name": "buffer offset", "type": "uint32_t"},
                     {"name": "row pitch", "type": "uint32_t"}
diff --git a/examples/CppHelloTriangle.cpp b/examples/CppHelloTriangle.cpp
index bf331df..6563cc4 100644
--- a/examples/CppHelloTriangle.cpp
+++ b/examples/CppHelloTriangle.cpp
@@ -71,7 +71,7 @@
 
     dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::TransferSrc);
     dawn::CommandBuffer copy = device.CreateCommandBufferBuilder()
-        .CopyBufferToTexture(stagingBuffer, 0, 0, texture, 0, 0, 0, 1024, 1024, 1, 0)
+        .CopyBufferToTexture(stagingBuffer, 0, 0, texture, 0, 0, 0, 1024, 1024, 1, 0, 0)
         .GetResult();
 
     queue.Submit(1, &copy);
diff --git a/examples/glTFViewer/glTFViewer.cpp b/examples/glTFViewer/glTFViewer.cpp
index e80aab3..f133bce 100644
--- a/examples/glTFViewer/glTFViewer.cpp
+++ b/examples/glTFViewer/glTFViewer.cpp
@@ -434,7 +434,7 @@
 
             dawn::Buffer staging = utils::CreateBufferFromData(device, data, rowPitch * iImage.height, dawn::BufferUsageBit::TransferSrc);
             auto cmdbuf = device.CreateCommandBufferBuilder()
-                .CopyBufferToTexture(staging, 0, rowPitch, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0)
+                .CopyBufferToTexture(staging, 0, rowPitch, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0, 0)
                 .GetResult();
             queue.Submit(1, &cmdbuf);
 
diff --git a/src/dawn_native/CommandBuffer.cpp b/src/dawn_native/CommandBuffer.cpp
index a49ce6a..dafbac2 100644
--- a/src/dawn_native/CommandBuffer.cpp
+++ b/src/dawn_native/CommandBuffer.cpp
@@ -38,6 +38,10 @@
                 DAWN_RETURN_ERROR("Copy mip-level out of range");
             }
 
+            if (location.slice >= texture->GetArrayLayers()) {
+                DAWN_RETURN_ERROR("Copy array-layer out of range");
+            }
+
             // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
             // overflows.
             uint64_t level = location.level;
@@ -585,7 +589,8 @@
                                                    uint32_t width,
                                                    uint32_t height,
                                                    uint32_t depth,
-                                                   uint32_t level) {
+                                                   uint32_t level,
+                                                   uint32_t slice) {
         if (rowPitch == 0) {
             rowPitch = ComputeDefaultRowPitch(texture, width);
         }
@@ -602,6 +607,7 @@
         copy->destination.height = height;
         copy->destination.depth = depth;
         copy->destination.level = level;
+        copy->destination.slice = slice;
         copy->rowPitch = rowPitch;
     }
 
@@ -613,6 +619,7 @@
                                                    uint32_t height,
                                                    uint32_t depth,
                                                    uint32_t level,
+                                                   uint32_t slice,
                                                    BufferBase* buffer,
                                                    uint32_t bufferOffset,
                                                    uint32_t rowPitch) {
@@ -630,6 +637,7 @@
         copy->source.height = height;
         copy->source.depth = depth;
         copy->source.level = level;
+        copy->source.slice = slice;
         copy->destination.buffer = buffer;
         copy->destination.offset = bufferOffset;
         copy->rowPitch = rowPitch;
diff --git a/src/dawn_native/CommandBuffer.h b/src/dawn_native/CommandBuffer.h
index d829ba0..5ec9e6e 100644
--- a/src/dawn_native/CommandBuffer.h
+++ b/src/dawn_native/CommandBuffer.h
@@ -77,7 +77,8 @@
                                  uint32_t width,
                                  uint32_t height,
                                  uint32_t depth,
-                                 uint32_t level);
+                                 uint32_t level,
+                                 uint32_t slice);
         void CopyTextureToBuffer(TextureBase* texture,
                                  uint32_t x,
                                  uint32_t y,
@@ -86,6 +87,7 @@
                                  uint32_t height,
                                  uint32_t depth,
                                  uint32_t level,
+                                 uint32_t slice,
                                  BufferBase* buffer,
                                  uint32_t bufferOffset,
                                  uint32_t rowPitch);
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index e0a9558..e4598ad 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -64,6 +64,7 @@
         uint32_t x, y, z;
         uint32_t width, height, depth;
         uint32_t level;
+        uint32_t slice;
     };
 
     struct CopyBufferToBufferCmd {
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 324d57b..fa07a9c5 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -53,7 +53,7 @@
 
             region.imageSubresource.aspectMask = texture->GetVkAspectMask();
             region.imageSubresource.mipLevel = textureLocation.level;
-            region.imageSubresource.baseArrayLayer = 0;
+            region.imageSubresource.baseArrayLayer = textureLocation.slice;
             region.imageSubresource.layerCount = 1;
 
             region.imageOffset.x = textureLocation.x;
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index ae66277..6f9632e 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -248,7 +248,7 @@
         createInfo.format = VulkanImageFormat(GetFormat());
         createInfo.extent = VkExtent3D{GetWidth(), GetHeight(), GetDepth()};
         createInfo.mipLevels = GetNumMipLevels();
-        createInfo.arrayLayers = 1;
+        createInfo.arrayLayers = GetArrayLayers();
         createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
         createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
         createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat());
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index 6000f0c..327d4a9 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -259,7 +259,7 @@
     // the texture might have been modified.
     dawn::CommandBuffer commands =
         device.CreateCommandBufferBuilder()
-            .CopyTextureToBuffer(source, x, y, 0, width, height, 1, level, readback.buffer,
+            .CopyTextureToBuffer(source, x, y, 0, width, height, 1, level, 0, readback.buffer,
                                  readback.offset, rowPitch)
             .GetResult();
 
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index 2968c81..44a1334 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -31,6 +31,7 @@
             uint32_t copyWidth;
             uint32_t copyHeight;
             uint32_t level;
+            uint32_t arrayLayer = 1u;
         };
 
         struct BufferSpec {
@@ -57,13 +58,13 @@
 
 class CopyTests_T2B : public CopyTests {
     protected:
-        static void FillTextureData(uint32_t width, uint32_t height, uint32_t texelsPerRow, RGBA8* data) {
+        static void FillTextureData(uint32_t width, uint32_t height, uint32_t texelsPerRow, RGBA8* data, uint32_t layer) {
             for (unsigned int y = 0; y < height; ++y) {
                 for (unsigned int x = 0; x < width; ++x) {
                     unsigned int i = x + y * texelsPerRow;
                     data[i] = RGBA8(
-                        static_cast<uint8_t>(x % 256),
-                        static_cast<uint8_t>(y % 256),
+                        static_cast<uint8_t>((x + layer * x)% 256),
+                        static_cast<uint8_t>((y + layer * y)% 256),
                         static_cast<uint8_t>(x / 256),
                         static_cast<uint8_t>(y / 256));
                 }
@@ -77,7 +78,7 @@
             descriptor.width = textureSpec.width;
             descriptor.height = textureSpec.height;
             descriptor.depth = 1;
-            descriptor.arrayLayer = 1;
+            descriptor.arrayLayer = textureSpec.arrayLayer;
             descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;
             descriptor.mipLevel = textureSpec.level + 1;
             descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc;
@@ -87,51 +88,62 @@
             uint32_t height = textureSpec.height >> textureSpec.level;
             uint32_t rowPitch = Align(kBytesPerTexel * width, kTextureRowPitchAlignment);
             uint32_t texelsPerRow = rowPitch / kBytesPerTexel;
-            uint32_t texelCount = texelsPerRow * (height - 1) + width;
+            uint32_t texelCountPerLayer = texelsPerRow * (height - 1) + width;
 
-            // Create an upload buffer and use it to populate the `level` mip of the texture
-            std::vector<RGBA8> textureData(texelCount);
-            FillTextureData(width, height, rowPitch / kBytesPerTexel, textureData.data());
-            dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, textureData.data(), static_cast<uint32_t>(sizeof(RGBA8) * textureData.size()), dawn::BufferUsageBit::TransferSrc);
+            dawn::CommandBufferBuilder cmdBuilder = device.CreateCommandBufferBuilder();
 
-            dawn::CommandBuffer commands[2];
+            std::vector<std::vector<RGBA8>> textureArrayData(textureSpec.arrayLayer);
+            for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++slice) {
+                textureArrayData[slice].resize(texelCountPerLayer);
+                FillTextureData(width, height, rowPitch / kBytesPerTexel, textureArrayData[slice].data(), slice);
 
-            commands[0] = device.CreateCommandBufferBuilder()
-                .CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level)
-                .GetResult();
+                // Create an upload buffer and use it to populate the current slice of the texture in `level` mip level
+                dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, textureArrayData[slice].data(),
+                    static_cast<uint32_t>(sizeof(RGBA8) * textureArrayData[slice].size()), dawn::BufferUsageBit::TransferSrc);
 
-            // Create a buffer of size `size` and populate it with empty data (0,0,0,0)
+                cmdBuilder.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level, slice);
+            }
+
+            // Create a buffer of size `size * textureSpec.arrayLayer` and populate it with empty data (0,0,0,0)
             // Note: Prepopulating the buffer with empty data ensures that there is not random data in the expectation
             // and helps ensure that the padding due to the row pitch is not modified by the copy
             dawn::BufferDescriptor bufDescriptor;
-            bufDescriptor.size = bufferSpec.size;
+            bufDescriptor.size = bufferSpec.size * textureSpec.arrayLayer;
             bufDescriptor.usage = dawn::BufferUsageBit::TransferSrc | dawn::BufferUsageBit::TransferDst;
             dawn::Buffer buffer = device.CreateBuffer(&bufDescriptor);
-
-            std::vector<RGBA8> emptyData(bufferSpec.size / kBytesPerTexel);
+            std::vector<RGBA8> emptyData(bufferSpec.size / kBytesPerTexel * textureSpec.arrayLayer);
             buffer.SetSubData(0, static_cast<uint32_t>(emptyData.size() * sizeof(RGBA8)), reinterpret_cast<const uint8_t*>(emptyData.data()));
 
-            // Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` mip into the buffer at the specified `offset` and `rowPitch`
-            commands[1] = device.CreateCommandBufferBuilder()
-                .CopyTextureToBuffer(texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, buffer, bufferSpec.offset, bufferSpec.rowPitch)
-                .GetResult();
+            uint32_t bufferOffset = bufferSpec.offset;
+            for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++slice) {
+                // Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` mip into the buffer at `offset + bufferSpec.size * slice` and `rowPitch`
+                cmdBuilder.CopyTextureToBuffer(texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, slice, buffer, bufferOffset, bufferSpec.rowPitch);
+                bufferOffset += bufferSpec.size;
+            }
 
-            queue.Submit(2, commands);
+            dawn::CommandBuffer commands = cmdBuilder.GetResult();
+            queue.Submit(1, &commands);
 
-            // Pack the data used to create the upload buffer in the specified copy region to have the same format as the expected buffer data.
+            bufferOffset = bufferSpec.offset;
             std::vector<RGBA8> expected(bufferSpec.rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth);
-            PackTextureData(
-                &textureData[textureSpec.x + textureSpec.y * (rowPitch / kBytesPerTexel)],
-                textureSpec.copyWidth,
-                textureSpec.copyHeight,
-                rowPitch / kBytesPerTexel,
-                expected.data(),
-                bufferSpec.rowPitch / kBytesPerTexel);
+            for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++slice) {
+                // Pack the data used to create the upload buffer in the specified copy region to have the same format as the expected buffer data.
+                std::fill(expected.begin(), expected.end(), RGBA8());
+                PackTextureData(
+                    &textureArrayData[slice][textureSpec.x + textureSpec.y * (rowPitch / kBytesPerTexel)],
+                    textureSpec.copyWidth,
+                    textureSpec.copyHeight,
+                    rowPitch / kBytesPerTexel,
+                    expected.data(),
+                    bufferSpec.rowPitch / kBytesPerTexel);
 
-            EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, bufferSpec.offset, static_cast<uint32_t>(expected.size())) <<
-                "Texture to Buffer copy failed copying region [(" << textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight <<
-                ")) from " << textureSpec.width << " x " << textureSpec.height << " texture at mip level " << textureSpec.level <<
-                " to " << bufferSpec.size << "-byte buffer with offset " << bufferSpec.offset << " and row pitch " << bufferSpec.rowPitch << std::endl;
+                EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, bufferOffset, static_cast<uint32_t>(expected.size())) <<
+                    "Texture to Buffer copy failed copying region [(" << textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight <<
+                    ")) from " << textureSpec.width << " x " << textureSpec.height << " texture at mip level " << textureSpec.level << " layer " << slice <<
+                    " to " << bufDescriptor.size << "-byte buffer with offset " << bufferOffset << " and row pitch " << bufferSpec.rowPitch << std::endl;
+
+                bufferOffset += bufferSpec.size;
+            }
         }
 
 
@@ -172,7 +184,7 @@
         descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc;
         dawn::Texture texture = device.CreateTexture(&descriptor);
 
-        dawn::CommandBuffer commands[2];
+        dawn::CommandBufferBuilder cmdBuilder = device.CreateCommandBufferBuilder();
 
         // Create an upload buffer filled with empty data and use it to populate the `level` mip of the texture
         // Note: Prepopulating the texture with empty data ensures that there is not random data in the expectation
@@ -187,17 +199,14 @@
             std::vector<RGBA8> emptyData(texelCount);
             dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, emptyData.data(), static_cast<uint32_t>(sizeof(RGBA8) * emptyData.size()), dawn::BufferUsageBit::TransferSrc);
 
-            commands[0] = device.CreateCommandBufferBuilder()
-                .CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level)
-                .GetResult();
+            cmdBuilder.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level, 0);
         }
 
         // Copy to the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] at the `level` mip from the buffer at the specified `offset` and `rowPitch`
-        commands[1] = device.CreateCommandBufferBuilder()
-            .CopyBufferToTexture(buffer, bufferSpec.offset, bufferSpec.rowPitch, texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level)
-            .GetResult();
+        cmdBuilder.CopyBufferToTexture(buffer, bufferSpec.offset, bufferSpec.rowPitch, texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, 0);
 
-        queue.Submit(2, commands);
+        dawn::CommandBuffer commands = cmdBuilder.GetResult();
+        queue.Submit(1, &commands);
 
         // Pack the data used to create the buffer in the specified copy region to have the same format as the expected texture data.
         uint32_t rowPitch = Align(kBytesPerTexel * textureSpec.copyWidth, kTextureRowPitchAlignment);
@@ -355,6 +364,36 @@
     }
 }
 
+// Test that copying regions of each texture 2D array layer works
+TEST_P(CopyTests_T2B, Texture2DArrayRegion)
+{
+    // TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
+    if (IsOpenGL() || IsD3D12() || IsMetal()) {
+        std::cout << "Test skipped on OpenGL, D3D12 and Metal" << std::endl;
+        return;
+    }
+
+    constexpr uint32_t kWidth = 256;
+    constexpr uint32_t kHeight = 128;
+    constexpr uint32_t kLayers = 6u;
+    DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0, kLayers }, MinimumBufferSpec(kWidth, kHeight));
+}
+
+// Test that copying texture 2D array mips with 256-byte aligned sizes works
+TEST_P(CopyTests_T2B, Texture2DArrayMip) {
+    // TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
+    if (IsOpenGL() || IsD3D12() || IsMetal()) {
+        std::cout << "Test skipped on OpenGL, D3D12 and Metal" << std::endl;
+        return;
+    }
+    constexpr uint32_t kWidth = 256;
+    constexpr uint32_t kHeight = 128;
+    constexpr uint32_t kLayers = 6u;
+    for (unsigned int i = 1; i < 4; ++i) {
+        DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i, kLayers }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
+    }
+}
+
 DAWN_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
 
 // Test that copying an entire texture with 256-byte aligned dimensions works
diff --git a/src/tests/end2end/SamplerTests.cpp b/src/tests/end2end/SamplerTests.cpp
index 72adfb4..f0de366 100644
--- a/src/tests/end2end/SamplerTests.cpp
+++ b/src/tests/end2end/SamplerTests.cpp
@@ -101,7 +101,7 @@
 
         dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data, sizeof(data), dawn::BufferUsageBit::TransferSrc);
         dawn::CommandBuffer copy = device.CreateCommandBufferBuilder()
-            .CopyBufferToTexture(stagingBuffer, 0, 256, texture, 0, 0, 0, 2, 2, 1, 0)
+            .CopyBufferToTexture(stagingBuffer, 0, 256, texture, 0, 0, 0, 2, 2, 1, 0, 0)
             .GetResult();
 
         queue.Submit(1, &copy);
diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
index 5410d44..dc2af0e 100644
--- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
+++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
@@ -26,14 +26,14 @@
             return device.CreateBuffer(&descriptor);
         }
 
-        dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t levels,
+        dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t levels, uint32_t arrayLayer,
                                          dawn::TextureFormat format, dawn::TextureUsageBit usage) {
             dawn::TextureDescriptor descriptor;
             descriptor.dimension = dawn::TextureDimension::e2D;
             descriptor.width = width;
             descriptor.height = height;
             descriptor.depth = 1;
-            descriptor.arrayLayer = 1;
+            descriptor.arrayLayer = arrayLayer;
             descriptor.format = format;
             descriptor.mipLevel = levels;
             descriptor.usage = usage;
@@ -124,20 +124,20 @@
 TEST_F(CopyCommandTest_B2T, Success) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
     dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
 
     // Different copies, including some that touch the OOB condition
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // Copy 4x4 block in corner of first mip.
-            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
             // Copy 4x4 block in opposite corner of first mip.
-            .CopyBufferToTexture(source, 0, 256, destination, 12, 12, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 12, 12, 0, 4, 4, 1, 0, 0)
             // Copy 4x4 block in the 4x4 mip.
-            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 2)
+            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 2, 0)
             // Copy with a buffer offset
-            .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0)
+            .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
             .GetResult();
     }
 
@@ -145,11 +145,11 @@
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // Unaligned region
-            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 3, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 3, 4, 1, 0, 0)
             // Unaligned region with texture offset
-            .CopyBufferToTexture(source, 0, 256, destination, 5, 7, 0, 2, 3, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 5, 7, 0, 2, 3, 1, 0, 0)
             // Unaligned region, with buffer offset
-            .CopyBufferToTexture(source, 31 * 4, 256, destination, 0, 0, 0, 3, 3, 1, 0)
+            .CopyBufferToTexture(source, 31 * 4, 256, destination, 0, 0, 0, 3, 3, 1, 0, 0)
             .GetResult();
     }
 
@@ -157,11 +157,11 @@
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // An empty copy
-            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0)
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0, 0)
             // An empty copy touching the end of the buffer
-            .CopyBufferToTexture(source, bufferSize, 0, destination, 0, 0, 0, 0, 0, 1, 0)
+            .CopyBufferToTexture(source, bufferSize, 0, destination, 0, 0, 0, 0, 0, 1, 0, 0)
             // An empty copy touching the side of the texture
-            .CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0)
+            .CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0, 0)
             .GetResult();
     }
 }
@@ -170,27 +170,27 @@
 TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
     dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
 
     // OOB on the buffer because we copy too many pixels
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 5, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 5, 1, 0, 0)
             .GetResult();
     }
 
     // OOB on the buffer because of the offset
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 4, 256, destination, 0, 0, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 4, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 
     // OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 512, destination, 0, 0, 0, 4, 3, 1, 0)
+            .CopyBufferToTexture(source, 0, 512, destination, 0, 0, 0, 4, 3, 1, 0, 0)
             .GetResult();
     }
 
@@ -201,7 +201,7 @@
         ASSERT_TRUE(256 * 3 > sourceBufferSize) << "row pitch * height should overflow buffer";
         dawn::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, dawn::BufferUsageBit::TransferSrc);
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(sourceBuffer, 0, 256, destination, 0, 0, 0, 7, 3, 1, 0)
+            .CopyBufferToTexture(sourceBuffer, 0, 256, destination, 0, 0, 0, 7, 3, 1, 0, 0)
             .GetResult();
     }
 }
@@ -210,34 +210,41 @@
 TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
     dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 2, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
 
     // OOB on the texture because x + width overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, destination, 13, 12, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 13, 12, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 
     // OOB on the texture because y + width overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, destination, 12, 13, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 12, 13, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 
     // OOB on the texture because we overflow a non-zero mip
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, destination, 1, 0, 0, 4, 4, 1, 2)
+            .CopyBufferToTexture(source, 0, 256, destination, 1, 0, 0, 4, 4, 1, 2, 0)
             .GetResult();
     }
 
     // OOB on the texture even on an empty copy when we copy to a non-existent mip.
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 5)
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 5, 0)
+            .GetResult();
+    }
+
+    // OOB on the texture because slice overflows
+    {
+        dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0, 2)
             .GetResult();
     }
 }
@@ -245,20 +252,20 @@
 // Test that we force Z=0 and Depth=1 on copies to 2D textures
 TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) {
     dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
 
     // Z=1 on an empty copy still errors
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 1, 0, 0, 1, 0)
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 1, 0, 0, 1, 0, 0)
             .GetResult();
     }
 
     // Depth=0 on an empty copy still errors
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 0, 0)
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 0, 0, 0)
             .GetResult();
     }
 }
@@ -267,22 +274,22 @@
 TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
     dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
     dawn::Buffer vertex = CreateBuffer(16 * 4, dawn::BufferUsageBit::Vertex);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
-    dawn::Texture sampled = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                  dawn::TextureUsageBit::Sampled);
 
     // Incorrect source usage
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(vertex, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(vertex, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 
     // Incorrect destination usage
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, sampled, 0, 0, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, sampled, 0, 0, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 }
@@ -290,27 +297,27 @@
 TEST_F(CopyCommandTest_B2T, IncorrectRowPitch) {
     uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
     dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
         dawn::TextureUsageBit::TransferDst);
 
     // Default row pitch is not 256-byte aligned
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 3, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 3, 4, 1, 0, 0)
             .GetResult();
     }
 
     // Row pitch is not 256-byte aligned
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 128, destination, 0, 0, 0, 4, 4, 1, 0)
+            .CopyBufferToTexture(source, 0, 128, destination, 0, 0, 0, 4, 4, 1, 0, 0)
             .GetResult();
     }
 
     // Row pitch is less than width * bytesPerPixel
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 65, 1, 1, 0)
+            .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 65, 1, 1, 0, 0)
             .GetResult();
     }
 }
@@ -319,29 +326,29 @@
 TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
     dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
-    dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                      dawn::TextureUsageBit::TransferDst);
 
     // Correct usage
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0)
+            .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
             .GetResult();
     }
     // Incorrect usages
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, bufferSize - 5, 256, destination, 0, 0, 0, 1, 1, 1, 0)
+            .CopyBufferToTexture(source, bufferSize - 5, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
             .GetResult();
     }
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, bufferSize - 6, 256, destination, 0, 0, 0, 1, 1, 1, 0)
+            .CopyBufferToTexture(source, bufferSize - 6, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
             .GetResult();
     }
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyBufferToTexture(source, bufferSize - 7, 256, destination, 0, 0, 0, 1, 1, 1, 0)
+            .CopyBufferToTexture(source, bufferSize - 7, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
             .GetResult();
     }
 }
@@ -352,7 +359,7 @@
 // Test a successfull T2B copy
 TEST_F(CopyCommandTest_T2B, Success) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
-    dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                 dawn::TextureUsageBit::TransferSrc);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
 
@@ -360,13 +367,13 @@
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // Copy from 4x4 block in corner of first mip.
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 256)
             // Copy from 4x4 block in opposite corner of first mip.
-            .CopyTextureToBuffer(source, 12, 12, 0, 4, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 12, 12, 0, 4, 4, 1, 0, 0, destination, 0, 256)
             // Copy from 4x4 block in the 4x4 mip.
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, 0, destination, 0, 256)
             // Copy with a buffer offset
-            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 4, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 4, 256)
             .GetResult();
     }
 
@@ -374,11 +381,11 @@
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // Unaligned region
-            .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, 0, destination, 0, 256)
             // Unaligned region with texture offset
-            .CopyTextureToBuffer(source, 5, 7, 0, 2, 3, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 5, 7, 0, 2, 3, 1, 0, 0, destination, 0, 256)
             // Unaligned region, with buffer offset
-            .CopyTextureToBuffer(source, 0, 0, 0, 3, 3, 1, 2, destination, 31 * 4, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 3, 3, 1, 2, 0, destination, 31 * 4, 256)
             .GetResult();
     }
 
@@ -386,11 +393,11 @@
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
             // An empty copy
-            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, 0, 0)
+            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, 0, destination, 0, 0)
             // An empty copy touching the end of the buffer
-            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, bufferSize, 0)
+            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, 0, destination, bufferSize, 0)
             // An empty copy touching the side of the texture
-            .CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, destination, 0, 0)
+            .CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, 0, destination, 0, 0)
             .GetResult();
     }
 }
@@ -398,35 +405,35 @@
 // Test OOB conditions on the texture
 TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
-    dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                 dawn::TextureUsageBit::TransferSrc);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
 
     // OOB on the texture because x + width overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 13, 12, 0, 4, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 13, 12, 0, 4, 4, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 
     // OOB on the texture because y + width overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 12, 13, 0, 4, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 12, 13, 0, 4, 4, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 
     // OOB on the texture because we overflow a non-zero mip
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 1, 0, 0, 4, 4, 1, 2, destination, 0, 256)
+            .CopyTextureToBuffer(source, 1, 0, 0, 4, 4, 1, 2, 0, destination, 0, 256)
             .GetResult();
     }
 
     // OOB on the texture even on an empty copy when we copy from a non-existent mip.
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 5, destination, 0, 0)
+            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 5, 0, destination, 0, 0)
             .GetResult();
     }
 }
@@ -434,28 +441,28 @@
 // Test OOB conditions on the buffer
 TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
-    dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                 dawn::TextureUsageBit::TransferSrc);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
 
     // OOB on the buffer because we copy too many pixels
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 5, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 5, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 
     // OOB on the buffer because of the offset
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 4, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 4, 256)
             .GetResult();
     }
 
     // OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 3, 1, 0, destination, 0, 512)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 3, 1, 0, 0, destination, 0, 512)
             .GetResult();
     }
 
@@ -466,7 +473,7 @@
         ASSERT_TRUE(256 * 3 > destinationBufferSize) << "row pitch * height should overflow buffer";
         dawn::Buffer destinationBuffer = CreateBuffer(destinationBufferSize, dawn::BufferUsageBit::TransferDst);
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 7, 3, 1, 0, destinationBuffer, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 7, 3, 1, 0, 0, destinationBuffer, 0, 256)
             .GetResult();
     }
 }
@@ -474,21 +481,21 @@
 // Test that we force Z=0 and Depth=1 on copies from to 2D textures
 TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
-    dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                 dawn::TextureUsageBit::TransferSrc);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
 
     // Z=1 on an empty copy still errors
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 1, 0, 0, 1, 0, destination, 0, 0)
+            .CopyTextureToBuffer(source, 0, 0, 1, 0, 0, 1, 0, 0, destination, 0, 0)
             .GetResult();
     }
 
     // Depth=0 on an empty copy still errors
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 0, 0, destination, 0, 0)
+            .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 0, 0, 0, destination, 0, 0)
             .GetResult();
     }
 }
@@ -496,9 +503,9 @@
 // Test T2B copies with incorrect buffer usage
 TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
     uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
-    dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                 dawn::TextureUsageBit::TransferSrc);
-    dawn::Texture sampled = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
                                                  dawn::TextureUsageBit::Sampled);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
     dawn::Buffer vertex = CreateBuffer(bufferSize, dawn::BufferUsageBit::Vertex);
@@ -506,42 +513,42 @@
     // Incorrect source usage
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(sampled, 0, 0, 0, 4, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(sampled, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 
     // Incorrect destination usage
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, vertex, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, vertex, 0, 256)
             .GetResult();
     }
 }
 
 TEST_F(CopyCommandTest_T2B, IncorrectRowPitch) {
     uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
-    dawn::Texture source = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
+    dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
         dawn::TextureUsageBit::TransferDst);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
 
     // Default row pitch is not 256-byte aligned
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 
     // Row pitch is not 256-byte aligned
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 0, 257)
+            .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 257)
             .GetResult();
     }
 
     // Row pitch is less than width * bytesPerPixel
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 65, 1, 1, 0, destination, 0, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 65, 1, 1, 0, 0, destination, 0, 256)
             .GetResult();
     }
 }
@@ -549,30 +556,30 @@
 // Test T2B copies with incorrect buffer offset usage
 TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) {
     uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
-    dawn::Texture source = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm,
-        dawn::TextureUsageBit::TransferSrc);
+    dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
+                                           dawn::TextureUsageBit::TransferSrc);
     dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
 
     // Correct usage
     {
         dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 4, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 4, 256)
             .GetResult();
     }
     // Incorrect usages
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 5, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 5, 256)
             .GetResult();
     }
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 6, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 6, 256)
             .GetResult();
     }
     {
         dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
-            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 7, 256)
+            .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 7, 256)
             .GetResult();
     }
 }