D3D12: Save sourceRegion in TextureCopySubresource::CopyInfo

This patch replaces `copySize` with `sourceRegion` in
`TextureCopySubresource::CopyInfo` so that we can directly use
`sourceRegion` in the D3D12 call `CopyTextureRegion`.

Bug: chromium:42241700
Change-Id: Id905a80847b67176a87780614d47815c569c2aab
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208596
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/d3d12/TextureCopySplitter.cpp b/src/dawn/native/d3d12/TextureCopySplitter.cpp
index dac691c..27c177b 100644
--- a/src/dawn/native/d3d12/TextureCopySplitter.cpp
+++ b/src/dawn/native/d3d12/TextureCopySplitter.cpp
@@ -57,14 +57,64 @@
 uint64_t AlignDownForDataPlacement(uint32_t offset) {
     return offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1);
 }
+
+void ComputeSourceRegionForCopyInfo(TextureCopySubresource::CopyInfo* copyInfo,
+                                    BufferTextureCopyDirection direction,
+                                    Origin3D bufferOffset,
+                                    Origin3D textureOffset,
+                                    Extent3D copySize) {
+    switch (direction) {
+        case BufferTextureCopyDirection::B2T:
+            copyInfo->sourceRegion = ComputeD3D12BoxFromOffsetAndSize(bufferOffset, copySize);
+            copyInfo->destinationOffset = textureOffset;
+            break;
+        case BufferTextureCopyDirection::T2B:
+            copyInfo->sourceRegion = ComputeD3D12BoxFromOffsetAndSize(textureOffset, copySize);
+            copyInfo->destinationOffset = bufferOffset;
+            break;
+        default:
+            DAWN_UNREACHABLE();
+    }
+}
+
 }  // namespace
 
+Extent3D TextureCopySubresource::CopyInfo::GetCopySize() const {
+    return {sourceRegion.right - sourceRegion.left, sourceRegion.bottom - sourceRegion.top,
+            sourceRegion.back - sourceRegion.front};
+}
+
+Origin3D TextureCopySubresource::CopyInfo::GetBufferOffset(
+    BufferTextureCopyDirection direction) const {
+    switch (direction) {
+        case BufferTextureCopyDirection::B2T:
+            return {sourceRegion.left, sourceRegion.top, sourceRegion.front};
+        case BufferTextureCopyDirection::T2B:
+            return destinationOffset;
+        default:
+            DAWN_UNREACHABLE();
+    }
+}
+
+Origin3D TextureCopySubresource::CopyInfo::GetTextureOffset(
+    BufferTextureCopyDirection direction) const {
+    switch (direction) {
+        case BufferTextureCopyDirection::B2T:
+            return destinationOffset;
+        case BufferTextureCopyDirection::T2B:
+            return {sourceRegion.left, sourceRegion.top, sourceRegion.front};
+        default:
+            DAWN_UNREACHABLE();
+    }
+}
+
 TextureCopySubresource::CopyInfo* TextureCopySubresource::AddCopy() {
     DAWN_ASSERT(this->count < kMaxTextureCopyRegions);
     return &this->copies[this->count++];
 }
 
-TextureCopySubresource Compute2DTextureCopySubresource(Origin3D origin,
+TextureCopySubresource Compute2DTextureCopySubresource(BufferTextureCopyDirection direction,
+                                                       Origin3D origin,
                                                        Extent3D copySize,
                                                        const TexelBlockInfo& blockInfo,
                                                        uint64_t offset,
@@ -83,11 +133,13 @@
         copy.count = 1;
 
         copy.copies[0].alignedOffset = alignedOffset;
-        copy.copies[0].textureOffset = origin;
-        copy.copies[0].copySize = copySize;
-        copy.copies[0].bufferOffset = {0, 0, 0};
+        Origin3D textureOffset = origin;
+        Origin3D bufferOffset = {0, 0, 0};
         copy.copies[0].bufferSize = copySize;
 
+        ComputeSourceRegionForCopyInfo(&copy.copies[0], direction, bufferOffset, textureOffset,
+                                       copySize);
+
         return copy;
     }
 
@@ -149,14 +201,16 @@
         copy.count = 1;
 
         copy.copies[0].alignedOffset = alignedOffset;
-        copy.copies[0].textureOffset = origin;
-        copy.copies[0].copySize = copySize;
-        copy.copies[0].bufferOffset = texelOffset;
+        Origin3D textureOffset = origin;
+        Origin3D bufferOffset = texelOffset;
 
         copy.copies[0].bufferSize.width = copySize.width + texelOffset.x;
         copy.copies[0].bufferSize.height = copySize.height + texelOffset.y;
         copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers;
 
+        ComputeSourceRegionForCopyInfo(&copy.copies[0], direction, bufferOffset, textureOffset,
+                                       copySize);
+
         return copy;
     }
 
@@ -197,21 +251,21 @@
     copy.count = 2;
 
     copy.copies[0].alignedOffset = alignedOffset;
-    copy.copies[0].textureOffset = origin;
+    Origin3D textureOffset0 = origin;
 
     DAWN_ASSERT(bytesPerRow > byteOffsetInRowPitch);
     uint32_t texelsPerRow = bytesPerRow / blockInfo.byteSize * blockInfo.width;
-    copy.copies[0].copySize.width = texelsPerRow - texelOffset.x;
-    copy.copies[0].copySize.height = copySize.height;
-    copy.copies[0].copySize.depthOrArrayLayers = copySize.depthOrArrayLayers;
+    Extent3D copySize0 = {texelsPerRow - texelOffset.x, copySize.height,
+                          copySize.depthOrArrayLayers};
 
-    copy.copies[0].bufferOffset = texelOffset;
+    Origin3D bufferOffset0 = texelOffset;
     copy.copies[0].bufferSize.width = texelsPerRow;
     copy.copies[0].bufferSize.height = copySize.height + texelOffset.y;
     copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers;
+    ComputeSourceRegionForCopyInfo(&copy.copies[0], direction, bufferOffset0, textureOffset0,
+                                   copySize0);
 
-    uint64_t offsetForCopy1 =
-        offset + copy.copies[0].copySize.width / blockInfo.width * blockInfo.byteSize;
+    uint64_t offsetForCopy1 = offset + copySize0.width / blockInfo.width * blockInfo.byteSize;
     uint64_t alignedOffsetForCopy1 = AlignDownForDataPlacement(offsetForCopy1);
     Origin3D texelOffsetForCopy1 = ComputeTexelOffsets(
         blockInfo, static_cast<uint32_t>(offsetForCopy1 - alignedOffsetForCopy1), bytesPerRow);
@@ -220,24 +274,24 @@
     DAWN_ASSERT(texelOffsetForCopy1.z == 0);
 
     copy.copies[1].alignedOffset = alignedOffsetForCopy1;
-    copy.copies[1].textureOffset.x = origin.x + copy.copies[0].copySize.width;
-    copy.copies[1].textureOffset.y = origin.y;
-    copy.copies[1].textureOffset.z = origin.z;
+    Origin3D textureOffset1 = {origin.x + copySize0.width, origin.y, origin.z};
 
-    DAWN_ASSERT(copySize.width > copy.copies[0].copySize.width);
-    copy.copies[1].copySize.width = copySize.width - copy.copies[0].copySize.width;
-    copy.copies[1].copySize.height = copySize.height;
-    copy.copies[1].copySize.depthOrArrayLayers = copySize.depthOrArrayLayers;
+    DAWN_ASSERT(copySize.width > copySize0.width);
+    Extent3D copySize1 = {copySize.width - copySize0.width, copySize.height,
+                          copySize.depthOrArrayLayers};
 
-    copy.copies[1].bufferOffset = texelOffsetForCopy1;
-    copy.copies[1].bufferSize.width = copy.copies[1].copySize.width + texelOffsetForCopy1.x;
+    Origin3D bufferOffset1 = texelOffsetForCopy1;
+    copy.copies[1].bufferSize.width = copySize1.width + texelOffsetForCopy1.x;
     copy.copies[1].bufferSize.height = copySize.height + texelOffsetForCopy1.y;
     copy.copies[1].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers;
+    ComputeSourceRegionForCopyInfo(&copy.copies[1], direction, bufferOffset1, textureOffset1,
+                                   copySize1);
 
     return copy;
 }
 
-TextureCopySplits Compute2DTextureCopySplits(Origin3D origin,
+TextureCopySplits Compute2DTextureCopySplits(BufferTextureCopyDirection direction,
+                                             Origin3D origin,
                                              Extent3D copySize,
                                              const TexelBlockInfo& blockInfo,
                                              uint64_t offset,
@@ -264,7 +318,7 @@
     copyFirstLayerOrigin.z = 0;
 
     copies.copySubresources[0] = Compute2DTextureCopySubresource(
-        copyFirstLayerOrigin, copyOneLayerSize, blockInfo, offset, bytesPerRow);
+        direction, copyFirstLayerOrigin, copyOneLayerSize, blockInfo, offset, bytesPerRow);
 
     // When the copy only refers one texture 2D array layer,
     // copies.copySubresources[1] will never be used so we can safely early return here.
@@ -278,20 +332,23 @@
         copies.copySubresources[1].copies[1].alignedOffset += bytesPerLayer;
     } else {
         const uint64_t bufferOffsetNextLayer = offset + bytesPerLayer;
-        copies.copySubresources[1] = Compute2DTextureCopySubresource(
-            copyFirstLayerOrigin, copyOneLayerSize, blockInfo, bufferOffsetNextLayer, bytesPerRow);
+        copies.copySubresources[1] =
+            Compute2DTextureCopySubresource(direction, copyFirstLayerOrigin, copyOneLayerSize,
+                                            blockInfo, bufferOffsetNextLayer, bytesPerRow);
     }
 
     return copies;
 }
 
-void Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight(Origin3D origin,
-                                                                    Extent3D copySize,
-                                                                    const TexelBlockInfo& blockInfo,
-                                                                    uint32_t bytesPerRow,
-                                                                    uint32_t rowsPerImage,
-                                                                    TextureCopySubresource& copy,
-                                                                    uint32_t i) {
+void Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight(
+    BufferTextureCopyDirection direction,
+    Origin3D origin,
+    Extent3D copySize,
+    const TexelBlockInfo& blockInfo,
+    uint32_t bytesPerRow,
+    uint32_t rowsPerImage,
+    TextureCopySubresource& copy,
+    uint32_t i) {
     // Let's assign data and show why copy region generated by ComputeTextureCopySubresource
     // is incorrect if there is an empty row at the beginning of the copy block.
     // Assuming that bytesPerRow is 256 and we are doing a B2T copy, and copy size is {width: 2,
@@ -384,29 +441,37 @@
 
     // Copy 0: copy copySize.height - 1 rows
     TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
-    copy0.copySize.height = copySize.height - blockInfo.height;
+    Extent3D copySize0 = copy0.GetCopySize();
+    copySize0.height = copySize.height - blockInfo.height;
     copy0.bufferSize.height = rowsPerImage * blockInfo.height;  // rowsPerImageInTexels
+    const Origin3D bufferOffset0 = copy0.GetBufferOffset(direction);
+    const Origin3D textureOffset0 = copy0.GetTextureOffset(direction);
+    ComputeSourceRegionForCopyInfo(&copy0, direction, bufferOffset0, textureOffset0, copySize0);
 
     // Copy 1: move down 2 rows and copy the last row on image 0, and expand to all depth slices
     // but the last one.
     TextureCopySubresource::CopyInfo* copy1 = copy.AddCopy();
     *copy1 = copy0;
     copy1->alignedOffset += 2 * bytesPerRow;
-    copy1->textureOffset.y += copySize.height - blockInfo.height;
+    Origin3D textureOffset1 = textureOffset0;
+    Origin3D bufferOffset1 = bufferOffset0;
+    textureOffset1.y += copySize.height - blockInfo.height;
     // Offset two rows from the copy height for the bufferOffset (See the figure above):
     //   - one for the row we advanced in the buffer: row (N + 4).
     //   - one for the last row we want to copy: row (N + 3) itself.
-    copy1->bufferOffset.y = copySize.height - 2 * blockInfo.height;
-    copy1->copySize.height = blockInfo.height;
-    copy1->copySize.depthOrArrayLayers--;
+    bufferOffset1.y = copySize.height - 2 * blockInfo.height;
+    Extent3D copySize1 = copySize0;
+    copySize1.height = blockInfo.height;
+    copySize1.depthOrArrayLayers--;
     copy1->bufferSize.depthOrArrayLayers--;
+    ComputeSourceRegionForCopyInfo(copy1, direction, bufferOffset1, textureOffset1, copySize1);
 
     // Copy 2: copy the last row of the last image.
     uint64_t offsetForCopy0 =
-        OffsetToFirstCopiedTexel(blockInfo, bytesPerRow, copy0.alignedOffset, copy0.bufferOffset);
+        OffsetToFirstCopiedTexel(blockInfo, bytesPerRow, copy0.alignedOffset, bufferOffset0);
     uint64_t offsetForLastRowOfLastImage =
         offsetForCopy0 +
-        bytesPerRow * (copy0.copySize.height + rowsPerImage * (copySize.depthOrArrayLayers - 1));
+        bytesPerRow * (copySize0.height + rowsPerImage * (copySize.depthOrArrayLayers - 1));
     uint64_t alignedOffsetForLastRowOfLastImage =
         AlignDownForDataPlacement(offsetForLastRowOfLastImage);
     Origin3D texelOffsetForLastRowOfLastImage = ComputeTexelOffsets(
@@ -416,21 +481,25 @@
 
     TextureCopySubresource::CopyInfo* copy2 = copy.AddCopy();
     copy2->alignedOffset = alignedOffsetForLastRowOfLastImage;
-    copy2->textureOffset = copy1->textureOffset;
-    copy2->textureOffset.z = origin.z + copySize.depthOrArrayLayers - 1;
-    copy2->copySize = copy1->copySize;
-    copy2->copySize.depthOrArrayLayers = 1;
-    copy2->bufferOffset = texelOffsetForLastRowOfLastImage;
+    Origin3D textureOffset2 = textureOffset1;
+    textureOffset2.z = origin.z + copySize.depthOrArrayLayers - 1;
+    Extent3D copySize2 = copySize1;
+    copySize2.depthOrArrayLayers = 1;
+    Origin3D bufferOffset2 = bufferOffset1;
+    bufferOffset2 = texelOffsetForLastRowOfLastImage;
     copy2->bufferSize.width = copy1->bufferSize.width;
-    DAWN_ASSERT(copy2->copySize.height == 1);
-    copy2->bufferSize.height = copy2->bufferOffset.y + copy2->copySize.height;
+    DAWN_ASSERT(copySize2.height == 1);
+    copy2->bufferSize.height = bufferOffset2.y + copySize2.height;
     copy2->bufferSize.depthOrArrayLayers = 1;
+    ComputeSourceRegionForCopyInfo(copy2, direction, bufferOffset2, textureOffset2, copySize2);
 }
 
-void Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(Extent3D copySize,
-                                                                   uint32_t bytesPerRow,
-                                                                   TextureCopySubresource& copy,
-                                                                   uint32_t i) {
+void Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(
+    BufferTextureCopyDirection direction,
+    Extent3D copySize,
+    uint32_t bytesPerRow,
+    TextureCopySubresource& copy,
+    uint32_t i) {
     // Read the comments of Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight() for
     // the reason why it is incorrect if we simply extend the copy region to all depth slices
     // when there is an empty first row at the copy region.
@@ -443,8 +512,12 @@
 
     // Copy 0: copy the first depth slice (image 0)
     TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
-    copy0.copySize.depthOrArrayLayers = 1;
+    Extent3D copySize0 = copy0.GetCopySize();
+    copySize0.depthOrArrayLayers = 1;
     copy0.bufferSize.depthOrArrayLayers = 1;
+    const Origin3D bufferOffset0 = copy0.GetBufferOffset(direction);
+    const Origin3D textureOffset0 = copy0.GetTextureOffset(direction);
+    ComputeSourceRegionForCopyInfo(&copy0, direction, bufferOffset0, textureOffset0, copySize0);
 
     // Copy 1: copy the rest depth slices in one shot
     TextureCopySubresource::CopyInfo* copy1 = copy.AddCopy();
@@ -453,17 +526,22 @@
     copy1->alignedOffset += (copySize.height + 1) * bytesPerRow;
     DAWN_ASSERT(copy1->alignedOffset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0);
     // textureOffset.z should add one because the first slice has already been copied in copy0.
-    copy1->textureOffset.z++;
+    Origin3D textureOffset1 = textureOffset0;
+    textureOffset1.z++;
     // bufferOffset.y should be 0 because we skipped the first depth slice and there is no empty
     // row in this copy region.
-    copy1->bufferOffset.y = 0;
-    copy1->copySize.height = copySize.height;
-    copy1->copySize.depthOrArrayLayers = copySize.depthOrArrayLayers - 1;
+    Origin3D bufferOffset1 = bufferOffset0;
+    bufferOffset1.y = 0;
+    Extent3D copySize1 = copySize0;
+    copySize1.height = copySize.height;
+    copySize1.depthOrArrayLayers = copySize.depthOrArrayLayers - 1;
     copy1->bufferSize.height = copySize.height;
     copy1->bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers - 1;
+    ComputeSourceRegionForCopyInfo(copy1, direction, bufferOffset1, textureOffset1, copySize1);
 }
 
-TextureCopySubresource Compute3DTextureCopySplits(Origin3D origin,
+TextureCopySubresource Compute3DTextureCopySplits(BufferTextureCopyDirection direction,
+                                                  Origin3D origin,
                                                   Extent3D copySize,
                                                   const TexelBlockInfo& blockInfo,
                                                   uint64_t offset,
@@ -483,8 +561,8 @@
 
     // Call Compute2DTextureCopySubresource and get copy regions. This function has already
     // forwarded "copySize.depthOrArrayLayers" to all depth slices.
-    TextureCopySubresource copySubresource =
-        Compute2DTextureCopySubresource(origin, copySize, blockInfo, offset, bytesPerRow);
+    TextureCopySubresource copySubresource = Compute2DTextureCopySubresource(
+        direction, origin, copySize, blockInfo, offset, bytesPerRow);
 
     DAWN_ASSERT(copySubresource.count <= 2);
     // If copySize.depth is 1, we can return copySubresource. Because we don't need to extend
@@ -531,7 +609,8 @@
                 // an empty row at each depth slice. We need a totally different approach to
                 // split the copy region.
                 Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight(
-                    origin, copySize, blockInfo, bytesPerRow, rowsPerImage, copySubresource, i);
+                    direction, origin, copySize, blockInfo, bytesPerRow, rowsPerImage,
+                    copySubresource, i);
             } else {
                 // If copySize.height is odd and there is an empty row at the beginning of the
                 // first slice of the copy region, we can split the copy region into two copies:
@@ -539,8 +618,8 @@
                 // offset of slice 1 is aligned to D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512)
                 // without an empty row. This is an easier case relative to cases with even copy
                 // height.
-                Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(copySize, bytesPerRow,
-                                                                              copySubresource, i);
+                Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(
+                    direction, copySize, bytesPerRow, copySubresource, i);
             }
         }
     }
diff --git a/src/dawn/native/d3d12/TextureCopySplitter.h b/src/dawn/native/d3d12/TextureCopySplitter.h
index e73225c..90c6333 100644
--- a/src/dawn/native/d3d12/TextureCopySplitter.h
+++ b/src/dawn/native/d3d12/TextureCopySplitter.h
@@ -30,6 +30,7 @@
 
 #include <array>
 
+#include "dawn/native/d3d12/UtilsD3D12.h"
 #include "dawn/native/dawn_platform.h"
 
 namespace dawn::native {
@@ -45,11 +46,14 @@
 
     struct CopyInfo {
         uint64_t alignedOffset = 0;
-        Origin3D textureOffset;
-        Origin3D bufferOffset;
+        Origin3D destinationOffset;
         Extent3D bufferSize;
 
-        Extent3D copySize;
+        D3D12_BOX sourceRegion;
+
+        Origin3D GetBufferOffset(BufferTextureCopyDirection direction) const;
+        Origin3D GetTextureOffset(BufferTextureCopyDirection direction) const;
+        Extent3D GetCopySize() const;
     };
 
     CopyInfo* AddCopy();
@@ -86,20 +90,23 @@
 //   - Copy region(s) combined should exactly be equivalent to the texture region to be copied.
 //   - Every pixel accessed by every copy region should not be out of the bound of the copied
 //     texture and buffer.
-TextureCopySubresource Compute2DTextureCopySubresource(Origin3D origin,
+TextureCopySubresource Compute2DTextureCopySubresource(BufferTextureCopyDirection direction,
+                                                       Origin3D origin,
                                                        Extent3D copySize,
                                                        const TexelBlockInfo& blockInfo,
                                                        uint64_t offset,
                                                        uint32_t bytesPerRow);
 
-TextureCopySplits Compute2DTextureCopySplits(Origin3D origin,
+TextureCopySplits Compute2DTextureCopySplits(BufferTextureCopyDirection direction,
+                                             Origin3D origin,
                                              Extent3D copySize,
                                              const TexelBlockInfo& blockInfo,
                                              uint64_t offset,
                                              uint32_t bytesPerRow,
                                              uint32_t rowsPerImage);
 
-TextureCopySubresource Compute3DTextureCopySplits(Origin3D origin,
+TextureCopySubresource Compute3DTextureCopySplits(BufferTextureCopyDirection direction,
+                                                  Origin3D origin,
                                                   Extent3D copySize,
                                                   const TexelBlockInfo& blockInfo,
                                                   uint64_t offset,
diff --git a/src/dawn/native/d3d12/UtilsD3D12.cpp b/src/dawn/native/d3d12/UtilsD3D12.cpp
index 613bdca..0397bfd 100644
--- a/src/dawn/native/d3d12/UtilsD3D12.cpp
+++ b/src/dawn/native/d3d12/UtilsD3D12.cpp
@@ -38,6 +38,7 @@
 #include "dawn/native/d3d12/BufferD3D12.h"
 #include "dawn/native/d3d12/CommandRecordingContext.h"
 #include "dawn/native/d3d12/DeviceD3D12.h"
+#include "dawn/native/d3d12/TextureCopySplitter.h"
 
 namespace dawn::native::d3d12 {
 
@@ -193,27 +194,21 @@
     for (uint32_t i = 0; i < baseCopySplit.count; ++i) {
         const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i];
 
-        // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as
-        // members in TextureCopySubresource::CopyInfo.
+        // TODO(jiawei.shao@intel.com): pre-compute bufferLocation as a member in
+        // TextureCopySubresource::CopyInfo.
         const uint64_t offsetBytes = info.alignedOffset + baseOffset;
         const D3D12_TEXTURE_COPY_LOCATION bufferLocation =
             ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize,
                                                       offsetBytes, bufferBytesPerRow, aspect);
         if (direction == BufferTextureCopyDirection::B2T) {
-            const D3D12_BOX sourceRegion =
-                ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize);
-
-            commandList->CopyTextureRegion(&textureLocation, info.textureOffset.x,
-                                           info.textureOffset.y, info.textureOffset.z,
-                                           &bufferLocation, &sourceRegion);
+            commandList->CopyTextureRegion(&textureLocation, info.destinationOffset.x,
+                                           info.destinationOffset.y, info.destinationOffset.z,
+                                           &bufferLocation, &info.sourceRegion);
         } else {
             DAWN_ASSERT(direction == BufferTextureCopyDirection::T2B);
-            const D3D12_BOX sourceRegion =
-                ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize);
-
-            commandList->CopyTextureRegion(&bufferLocation, info.bufferOffset.x,
-                                           info.bufferOffset.y, info.bufferOffset.z,
-                                           &textureLocation, &sourceRegion);
+            commandList->CopyTextureRegion(&bufferLocation, info.destinationOffset.x,
+                                           info.destinationOffset.y, info.destinationOffset.z,
+                                           &textureLocation, &info.sourceRegion);
         }
     }
 }
@@ -229,7 +224,7 @@
                                         const Extent3D& copySize) {
     // See comments in Compute2DTextureCopySplits() for more details.
     const TextureCopySplits copySplits = Compute2DTextureCopySplits(
-        textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage);
+        direction, textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage);
 
     const uint64_t bytesPerLayer = bytesPerRow * rowsPerImage;
 
@@ -283,7 +278,7 @@
             DAWN_ASSERT(texture->GetArrayLayers() == 1);
 
             TextureCopySubresource copyRegions = Compute2DTextureCopySubresource(
-                textureCopy.origin, copySize, blockInfo, offset, bytesPerRow);
+                direction, textureCopy.origin, copySize, blockInfo, offset, bytesPerRow);
             RecordBufferTextureCopyFromSplits(direction, commandList, copyRegions, bufferResource,
                                               0, bytesPerRow, texture, textureCopy.mipLevel, 0,
                                               textureCopy.aspect);
@@ -300,8 +295,9 @@
 
         case wgpu::TextureDimension::e3D: {
             // See comments in Compute3DTextureCopySplits() for more details.
-            TextureCopySubresource copyRegions = Compute3DTextureCopySplits(
-                textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage);
+            TextureCopySubresource copyRegions =
+                Compute3DTextureCopySplits(direction, textureCopy.origin, copySize, blockInfo,
+                                           offset, bytesPerRow, rowsPerImage);
 
             RecordBufferTextureCopyFromSplits(direction, commandList, copyRegions, bufferResource,
                                               0, bytesPerRow, texture, textureCopy.mipLevel, 0,
diff --git a/src/dawn/native/d3d12/UtilsD3D12.h b/src/dawn/native/d3d12/UtilsD3D12.h
index e73c4a7..60a66ef 100644
--- a/src/dawn/native/d3d12/UtilsD3D12.h
+++ b/src/dawn/native/d3d12/UtilsD3D12.h
@@ -33,7 +33,6 @@
 #include "dawn/native/Commands.h"
 #include "dawn/native/d3d/UtilsD3D.h"
 #include "dawn/native/d3d12/BufferD3D12.h"
-#include "dawn/native/d3d12/TextureCopySplitter.h"
 #include "dawn/native/d3d12/TextureD3D12.h"
 #include "dawn/native/d3d12/d3d12_platform.h"
 #include "dawn/native/dawn_platform.h"
diff --git a/src/dawn/tests/unittests/d3d12/CopySplitTests.cpp b/src/dawn/tests/unittests/d3d12/CopySplitTests.cpp
index 7956e42..2eded9b 100644
--- a/src/dawn/tests/unittests/d3d12/CopySplitTests.cpp
+++ b/src/dawn/tests/unittests/d3d12/CopySplitTests.cpp
@@ -32,6 +32,7 @@
 #include "dawn/common/Math.h"
 #include "dawn/native/Format.h"
 #include "dawn/native/d3d12/TextureCopySplitter.h"
+#include "dawn/native/d3d12/UtilsD3D12.h"
 #include "dawn/native/d3d12/d3d12_platform.h"
 #include "dawn/utils/TestUtils.h"
 #include "dawn/webgpu_cpp_print.h"
@@ -61,14 +62,16 @@
 // Check that each copy region fits inside the buffer footprint
 void ValidateFootprints(const TextureSpec& textureSpec,
                         const BufferSpec& bufferSpec,
+                        BufferTextureCopyDirection direction,
                         const TextureCopySubresource& copySplit,
                         wgpu::TextureDimension dimension) {
     for (uint32_t i = 0; i < copySplit.count; ++i) {
         const auto& copy = copySplit.copies[i];
-        ASSERT_LE(copy.bufferOffset.x + copy.copySize.width, copy.bufferSize.width);
-        ASSERT_LE(copy.bufferOffset.y + copy.copySize.height, copy.bufferSize.height);
-        ASSERT_LE(copy.bufferOffset.z + copy.copySize.depthOrArrayLayers,
-                  copy.bufferSize.depthOrArrayLayers);
+        Extent3D copySize = copy.GetCopySize();
+        Origin3D bufferOffset = copy.GetBufferOffset(direction);
+        ASSERT_LE(bufferOffset.x + copySize.width, copy.bufferSize.width);
+        ASSERT_LE(bufferOffset.y + copySize.height, copy.bufferSize.height);
+        ASSERT_LE(bufferOffset.z + copySize.depthOrArrayLayers, copy.bufferSize.depthOrArrayLayers);
 
         // If there are multiple layers, 2D texture splitter actually splits each layer
         // independently. See the details in Compute2DTextureCopySplits(). As a result,
@@ -89,15 +92,15 @@
             // The last pixel (buffer footprint) of each copy region depends on its
             // bufferOffset and copySize. It is not the last pixel where the bufferSize
             // ends.
-            ASSERT_EQ(copy.bufferOffset.x % textureSpec.blockWidth, 0u);
-            ASSERT_EQ(copy.copySize.width % textureSpec.blockWidth, 0u);
-            uint32_t footprintWidth = copy.bufferOffset.x + copy.copySize.width;
+            ASSERT_EQ(bufferOffset.x % textureSpec.blockWidth, 0u);
+            ASSERT_EQ(copySize.width % textureSpec.blockWidth, 0u);
+            uint32_t footprintWidth = bufferOffset.x + copySize.width;
             ASSERT_EQ(footprintWidth % textureSpec.blockWidth, 0u);
             uint32_t footprintWidthInBlocks = footprintWidth / textureSpec.blockWidth;
 
-            ASSERT_EQ(copy.bufferOffset.y % textureSpec.blockHeight, 0u);
-            ASSERT_EQ(copy.copySize.height % textureSpec.blockHeight, 0u);
-            uint32_t footprintHeight = copy.bufferOffset.y + copy.copySize.height;
+            ASSERT_EQ(bufferOffset.y % textureSpec.blockHeight, 0u);
+            ASSERT_EQ(copySize.height % textureSpec.blockHeight, 0u);
+            uint32_t footprintHeight = bufferOffset.y + copySize.height;
             ASSERT_EQ(footprintHeight % textureSpec.blockHeight, 0u);
             uint32_t footprintHeightInBlocks = footprintHeight / textureSpec.blockHeight;
 
@@ -129,24 +132,29 @@
 }
 
 // Check that no pair of copy regions intersect each other
-void ValidateDisjoint(const TextureCopySubresource& copySplit) {
+void ValidateDisjoint(const TextureCopySubresource& copySplit,
+                      BufferTextureCopyDirection direction) {
     for (uint32_t i = 0; i < copySplit.count; ++i) {
         const auto& a = copySplit.copies[i];
+        Extent3D copySizeA = a.GetCopySize();
+        Origin3D textureOffsetA = a.GetTextureOffset(direction);
         for (uint32_t j = i + 1; j < copySplit.count; ++j) {
             const auto& b = copySplit.copies[j];
             // If textureOffset.x is 0, and copySize.width is 2, we are copying pixel 0 and
             // 1. We never touch pixel 2 on x-axis. So the copied range on x-axis should be
             // [textureOffset.x, textureOffset.x + copySize.width - 1] and both ends are
             // included.
+            Extent3D copySizeB = b.GetCopySize();
+            Origin3D textureOffsetB = b.GetTextureOffset(direction);
             bool overlapX =
-                InclusiveRangesOverlap(a.textureOffset.x, a.textureOffset.x + a.copySize.width - 1,
-                                       b.textureOffset.x, b.textureOffset.x + b.copySize.width - 1);
-            bool overlapY = InclusiveRangesOverlap(
-                a.textureOffset.y, a.textureOffset.y + a.copySize.height - 1, b.textureOffset.y,
-                b.textureOffset.y + b.copySize.height - 1);
+                InclusiveRangesOverlap(textureOffsetA.x, textureOffsetA.x + copySizeA.width - 1,
+                                       textureOffsetB.x, textureOffsetB.x + copySizeB.width - 1);
+            bool overlapY =
+                InclusiveRangesOverlap(textureOffsetA.y, textureOffsetA.y + copySizeA.height - 1,
+                                       textureOffsetB.y, textureOffsetB.y + copySizeB.height - 1);
             bool overlapZ = InclusiveRangesOverlap(
-                a.textureOffset.z, a.textureOffset.z + a.copySize.depthOrArrayLayers - 1,
-                b.textureOffset.z, b.textureOffset.z + b.copySize.depthOrArrayLayers - 1);
+                textureOffsetA.z, textureOffsetA.z + copySizeA.depthOrArrayLayers - 1,
+                textureOffsetB.z, textureOffsetB.z + copySizeB.depthOrArrayLayers - 1);
             ASSERT_TRUE(!overlapX || !overlapY || !overlapZ);
         }
     }
@@ -154,25 +162,29 @@
 
 // Check that the union of the copy regions exactly covers the texture region
 void ValidateTextureBounds(const TextureSpec& textureSpec,
+                           BufferTextureCopyDirection direction,
                            const TextureCopySubresource& copySplit) {
     ASSERT_GT(copySplit.count, 0u);
 
-    uint32_t minX = copySplit.copies[0].textureOffset.x;
-    uint32_t minY = copySplit.copies[0].textureOffset.y;
-    uint32_t minZ = copySplit.copies[0].textureOffset.z;
-    uint32_t maxX = copySplit.copies[0].textureOffset.x + copySplit.copies[0].copySize.width;
-    uint32_t maxY = copySplit.copies[0].textureOffset.y + copySplit.copies[0].copySize.height;
-    uint32_t maxZ =
-        copySplit.copies[0].textureOffset.z + copySplit.copies[0].copySize.depthOrArrayLayers;
+    Extent3D copySize0 = copySplit.copies[0].GetCopySize();
+    Origin3D textureOffset0 = copySplit.copies[0].GetTextureOffset(direction);
+    uint32_t minX = textureOffset0.x;
+    uint32_t minY = textureOffset0.y;
+    uint32_t minZ = textureOffset0.z;
+    uint32_t maxX = textureOffset0.x + copySize0.width;
+    uint32_t maxY = textureOffset0.y + copySize0.height;
+    uint32_t maxZ = textureOffset0.z + copySize0.depthOrArrayLayers;
 
     for (uint32_t i = 1; i < copySplit.count; ++i) {
         const auto& copy = copySplit.copies[i];
-        minX = std::min(minX, copy.textureOffset.x);
-        minY = std::min(minY, copy.textureOffset.y);
-        minZ = std::min(minZ, copy.textureOffset.z);
-        maxX = std::max(maxX, copy.textureOffset.x + copy.copySize.width);
-        maxY = std::max(maxY, copy.textureOffset.y + copy.copySize.height);
-        maxZ = std::max(maxZ, copy.textureOffset.z + copy.copySize.depthOrArrayLayers);
+        Origin3D textureOffset = copy.GetTextureOffset(direction);
+        minX = std::min(minX, textureOffset.x);
+        minY = std::min(minY, textureOffset.y);
+        minZ = std::min(minZ, textureOffset.z);
+        Extent3D copySize = copy.GetCopySize();
+        maxX = std::max(maxX, textureOffset.x + copySize.width);
+        maxY = std::max(maxY, textureOffset.y + copySize.height);
+        maxZ = std::max(maxZ, textureOffset.z + copySize.depthOrArrayLayers);
     }
 
     ASSERT_EQ(minX, textureSpec.x);
@@ -189,8 +201,8 @@
     uint32_t count = 0;
     for (uint32_t i = 0; i < copySplit.count; ++i) {
         const auto& copy = copySplit.copies[i];
-        uint32_t copiedPixels =
-            copy.copySize.width * copy.copySize.height * copy.copySize.depthOrArrayLayers;
+        Extent3D copySize = copy.GetCopySize();
+        uint32_t copiedPixels = copySize.width * copySize.height * copySize.depthOrArrayLayers;
         ASSERT_GT(copiedPixels, 0u);
         count += copiedPixels;
     }
@@ -200,6 +212,7 @@
 // Check that every buffer offset is at the correct pixel location
 void ValidateBufferOffset(const TextureSpec& textureSpec,
                           const BufferSpec& bufferSpec,
+                          BufferTextureCopyDirection direction,
                           const TextureCopySubresource& copySplit,
                           wgpu::TextureDimension dimension) {
     ASSERT_GT(copySplit.count, 0u);
@@ -207,6 +220,8 @@
     uint32_t texelsPerBlock = textureSpec.blockWidth * textureSpec.blockHeight;
     for (uint32_t i = 0; i < copySplit.count; ++i) {
         const auto& copy = copySplit.copies[i];
+        Origin3D bufferOffset = copy.GetBufferOffset(direction);
+        Origin3D textureOffset = copy.GetTextureOffset(direction);
 
         uint32_t bytesPerRowInTexels =
             bufferSpec.bytesPerRow / textureSpec.texelBlockSizeInBytes * texelsPerBlock;
@@ -214,16 +229,16 @@
             bytesPerRowInTexels * (bufferSpec.rowsPerImage / textureSpec.blockHeight);
         uint32_t absoluteTexelOffset =
             copy.alignedOffset / textureSpec.texelBlockSizeInBytes * texelsPerBlock +
-            copy.bufferOffset.x / textureSpec.blockWidth * texelsPerBlock +
-            copy.bufferOffset.y / textureSpec.blockHeight * bytesPerRowInTexels;
+            bufferOffset.x / textureSpec.blockWidth * texelsPerBlock +
+            bufferOffset.y / textureSpec.blockHeight * bytesPerRowInTexels;
 
         // There is one empty row at most in a 2D copy region. However, it is not true for
         // a 3D texture copy region when we are copying the last row of each slice. We may
         // need to offset a lot rows and copy.bufferOffset.y may be big.
         if (dimension == wgpu::TextureDimension::e2D) {
-            ASSERT_LE(copy.bufferOffset.y, textureSpec.blockHeight);
+            ASSERT_LE(bufferOffset.y, textureSpec.blockHeight);
         }
-        ASSERT_EQ(copy.bufferOffset.z, 0u);
+        ASSERT_EQ(bufferOffset.z, 0u);
 
         ASSERT_GE(absoluteTexelOffset,
                   bufferSpec.offset / textureSpec.texelBlockSizeInBytes * texelsPerBlock);
@@ -235,22 +250,23 @@
         uint32_t y = (relativeTexelOffset % slicePitchInTexels) / bytesPerRowInTexels;
         uint32_t x = relativeTexelOffset % bytesPerRowInTexels;
 
-        ASSERT_EQ(copy.textureOffset.x - textureSpec.x, x);
-        ASSERT_EQ(copy.textureOffset.y - textureSpec.y, y);
-        ASSERT_EQ(copy.textureOffset.z - textureSpec.z, z);
+        ASSERT_EQ(textureOffset.x - textureSpec.x, x);
+        ASSERT_EQ(textureOffset.y - textureSpec.y, y);
+        ASSERT_EQ(textureOffset.z - textureSpec.z, z);
     }
 }
 
 void ValidateCopySplit(const TextureSpec& textureSpec,
                        const BufferSpec& bufferSpec,
+                       BufferTextureCopyDirection direction,
                        const TextureCopySubresource& copySplit,
                        wgpu::TextureDimension dimension) {
-    ValidateFootprints(textureSpec, bufferSpec, copySplit, dimension);
+    ValidateFootprints(textureSpec, bufferSpec, direction, copySplit, dimension);
     ValidateOffset(copySplit);
-    ValidateDisjoint(copySplit);
-    ValidateTextureBounds(textureSpec, copySplit);
+    ValidateDisjoint(copySplit, direction);
+    ValidateTextureBounds(textureSpec, direction, copySplit);
     ValidatePixelCount(textureSpec, copySplit);
-    ValidateBufferOffset(textureSpec, bufferSpec, copySplit, dimension);
+    ValidateBufferOffset(textureSpec, bufferSpec, direction, copySplit, dimension);
 }
 
 std::ostream& operator<<(std::ostream& os, const TextureSpec& textureSpec) {
@@ -270,12 +286,15 @@
     os << "CopySplit\n";
     for (uint32_t i = 0; i < copySplit.count; ++i) {
         const auto& copy = copySplit.copies[i];
-        os << "  " << i << ": Texture at (" << copy.textureOffset.x << ", " << copy.textureOffset.y
-           << ", " << copy.textureOffset.z << "), size (" << copy.copySize.width << ", "
-           << copy.copySize.height << ", " << copy.copySize.depthOrArrayLayers << ")\n";
-        os << "  " << i << ": Buffer at (" << copy.bufferOffset.x << ", " << copy.bufferOffset.y
-           << ", " << copy.bufferOffset.z << "), footprint (" << copy.bufferSize.width << ", "
-           << copy.bufferSize.height << ", " << copy.bufferSize.depthOrArrayLayers << ")\n";
+        os << "  " << i << ": destinationOffset at (" << copy.destinationOffset.x << ", "
+           << copy.destinationOffset.y << ", " << copy.destinationOffset.z << "), sourceRegion ("
+           << copy.sourceRegion.left << ", " << copy.sourceRegion.top << ", "
+           << copy.sourceRegion.front << ", " << copy.sourceRegion.right << ", "
+           << copy.sourceRegion.bottom << ", " << copy.sourceRegion.back << ")\n";
+        os << "  " << i << ": sourceOffset at (" << copy.sourceRegion.left << ", "
+           << copy.sourceRegion.top << ", " << copy.sourceRegion.front << "), footprint ("
+           << copy.bufferSize.width << ", " << copy.bufferSize.height << ", "
+           << copy.bufferSize.depthOrArrayLayers << ")\n";
     }
     return os;
 }
@@ -380,18 +399,25 @@
                                      15, 31, 63, 127, 257, 511, 1023, 2047,  // misalignments
                                      17, 33, 65, 129, 257, 513, 1025, 2049};
 
-class CopySplitTest : public testing::TestWithParam<wgpu::TextureDimension> {
+struct CopySplitTestParam {
+    wgpu::TextureDimension dimension;
+    BufferTextureCopyDirection direction;
+};
+
+class CopySplitTest : public testing::TestWithParam<CopySplitTestParam> {
   protected:
     void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
         DAWN_ASSERT(textureSpec.width % textureSpec.blockWidth == 0 &&
                     textureSpec.height % textureSpec.blockHeight == 0);
 
-        wgpu::TextureDimension dimension = GetParam();
+        wgpu::TextureDimension dimension = GetParam().dimension;
+        BufferTextureCopyDirection direction = GetParam().direction;
         TextureCopySubresource copySplit;
         switch (dimension) {
+            case wgpu::TextureDimension::e1D:
             case wgpu::TextureDimension::e2D: {
                 copySplit = Compute2DTextureCopySubresource(
-                    {textureSpec.x, textureSpec.y, textureSpec.z},
+                    direction, {textureSpec.x, textureSpec.y, textureSpec.z},
                     {textureSpec.width, textureSpec.height, textureSpec.depthOrArrayLayers},
                     {textureSpec.texelBlockSizeInBytes, textureSpec.blockWidth,
                      textureSpec.blockHeight},
@@ -400,7 +426,7 @@
             }
             case wgpu::TextureDimension::e3D: {
                 copySplit = Compute3DTextureCopySplits(
-                    {textureSpec.x, textureSpec.y, textureSpec.z},
+                    direction, {textureSpec.x, textureSpec.y, textureSpec.z},
                     {textureSpec.width, textureSpec.height, textureSpec.depthOrArrayLayers},
                     {textureSpec.texelBlockSizeInBytes, textureSpec.blockWidth,
                      textureSpec.blockHeight},
@@ -412,7 +438,7 @@
                 break;
         }
 
-        ValidateCopySplit(textureSpec, bufferSpec, copySplit, dimension);
+        ValidateCopySplit(textureSpec, bufferSpec, direction, copySplit, dimension);
 
         if (HasFatalFailure()) {
             std::ostringstream message;
@@ -530,9 +556,16 @@
     }
 }
 
-INSTANTIATE_TEST_SUITE_P(,
-                         CopySplitTest,
-                         testing::Values(wgpu::TextureDimension::e2D, wgpu::TextureDimension::e3D));
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    CopySplitTest,
+    testing::Values(
+        CopySplitTestParam(wgpu::TextureDimension::e1D, BufferTextureCopyDirection::B2T),
+        CopySplitTestParam(wgpu::TextureDimension::e1D, BufferTextureCopyDirection::T2B),
+        CopySplitTestParam(wgpu::TextureDimension::e2D, BufferTextureCopyDirection::B2T),
+        CopySplitTestParam(wgpu::TextureDimension::e2D, BufferTextureCopyDirection::T2B),
+        CopySplitTestParam(wgpu::TextureDimension::e3D, BufferTextureCopyDirection::B2T),
+        CopySplitTestParam(wgpu::TextureDimension::e3D, BufferTextureCopyDirection::T2B)));
 
 }  // anonymous namespace
 }  // namespace dawn::native::d3d12