D3D12: Allow relaxed B2T copy pitch and offset alignment on 3D textures
This patch implements the buffer-texture copy with relaxed copy pitch
and offset alignment (not required to be a multiple of 512 or 256) on
3D textures when `UnrestrictedBufferTextureCopyPitchSupported` is true
on the current D3D12 device so that we just need to implement such copy
with at most two buffer-texture copies.
Bug: chromium:381000081
Test: dawn_end2end_tests
Change-Id: Id438da4ca209d742ae3243b53fc08c118fc82f46
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/216875
Reviewed-by: Loko Kung <lokokung@google.com>
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 9c80fc4..016ec8f 100644
--- a/src/dawn/native/d3d12/TextureCopySplitter.cpp
+++ b/src/dawn/native/d3d12/TextureCopySplitter.cpp
@@ -718,4 +718,97 @@
return copy;
}
+
+TextureCopySubresource Compute3DTextureCopySubresourceWithRelaxedRowPitchAndOffset(
+ BufferTextureCopyDirection direction,
+ Origin3D origin,
+ Extent3D copySize,
+ const TexelBlockInfo& blockInfo,
+ uint64_t offset,
+ uint32_t bytesPerRow,
+ uint32_t rowsPerImage) {
+ TextureCopySubresource copy;
+
+ Origin3D bufferOffset = {0, 0, 0};
+
+ // You can visualize the data in the buffer (bufferLocation) like the inline comments.
+ // * copy data is visualized as '+'.
+ uint32_t depthInCopy1 = copySize.depthOrArrayLayers - 1;
+ if (depthInCopy1 > 0) {
+ // `bufferLocation` in the 1st copy (first `depthInCopy1` images, optional):
+ //
+ // bufferOffset(0, 0, 0)
+ // ^
+ // |
+ // |<-------Offset1------>|<-----------RowPitch----------->|----------|------------|
+ // |----------------------|++++++++++++++++++++++~~~~~~~~~~| | | | |
+ // |++++++++++++++++++++++~~~~~~~~~~|CopyHeight| | |
+ // |++++++++++++++++++++++~~~~~~~~~~| | |RowsPerImage|
+ // |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|----------| | |
+ // |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | |
+ // |---End of 1st image-->|--------------------------------|----------|------------|
+ // |++++++++++++++++++++++~~~~~~~~~~| | | |
+ // |++++++++++++++++++++++~~~~~~~~~~| | | |
+ // |++++++++++++++++++++++~~~~~~~~~~| |RowsPerImage|
+ // |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | |
+ // |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | |
+ // |---End of 2nd image-->|--------------------------------|----------|------------|
+ // |<-----CopyWidth------>|
+ //
+
+ Origin3D textureOffset1 = origin;
+ uint32_t offset1 = offset;
+
+ uint32_t rowsPerImage1 = rowsPerImage;
+
+ auto* copyInfo1 = copy.AddCopy();
+ Extent3D copySize1 = {copySize.width, copySize.height, depthInCopy1};
+ ComputeSourceRegionForCopyInfo(copyInfo1, direction, bufferOffset, textureOffset1,
+ copySize1);
+
+ Extent3D bufferSize1 = {copySize.width, rowsPerImage1, depthInCopy1};
+
+ FillFootprintAndOffsetOfBufferLocation(©Info1->bufferLocation, offset1, bufferSize1,
+ bytesPerRow);
+ }
+
+ {
+ // We have to use the 2nd copy because there may not be enough memory to hold
+ // (RowPitch * RowsPerImage) data for the last image in the buffer.
+ //
+ // `bufferLocation` in the 2nd copy (the last image):
+ //
+ // bufferOffset (0, 0, 0)
+ // Begin of the last image
+ // ^
+ // |
+ // |<-------Offset2------>|<-----------RowPitch----------->|----------|
+ // |----------------------|++++++++++++++++++++++~~~~~~~~~~| | |
+ // |++++++++++++++++++++++~~~~~~~~~~|CopyHeight|
+ // |++++++++++++++++++++++| | | |
+ // |----------------------|---------|----------|
+ // |<-----CopyWidth------>|
+ // ^
+ // End of all buffer data
+ //
+ DAWN_ASSERT(copySize.depthOrArrayLayers >= 1);
+ Origin3D textureOffset2 = {origin.x, origin.y, origin.z + depthInCopy1};
+ uint32_t offset2 = offset + bytesPerRow * rowsPerImage * depthInCopy1;
+ uint32_t depthInCopy2 = 1;
+ uint32_t rowsPerImage2 = copySize.height;
+
+ auto* copyInfo2 = copy.AddCopy();
+ Extent3D copySize2 = {copySize.width, copySize.height, depthInCopy2};
+ ComputeSourceRegionForCopyInfo(copyInfo2, direction, bufferOffset, textureOffset2,
+ copySize2);
+
+ Extent3D bufferSize2 = {copySize.width, rowsPerImage2, depthInCopy2};
+
+ FillFootprintAndOffsetOfBufferLocation(©Info2->bufferLocation, offset2, bufferSize2,
+ bytesPerRow);
+ }
+
+ return copy;
+}
+
} // namespace dawn::native::d3d12
diff --git a/src/dawn/native/d3d12/TextureCopySplitter.h b/src/dawn/native/d3d12/TextureCopySplitter.h
index 5c6939d..18e9f48 100644
--- a/src/dawn/native/d3d12/TextureCopySplitter.h
+++ b/src/dawn/native/d3d12/TextureCopySplitter.h
@@ -128,6 +128,17 @@
uint64_t offset,
uint32_t bytesPerRow);
+// Compute the `TextureCopySubresource` for one subresource of a 3D texture with relaxed row pitch
+// and offset.
+TextureCopySubresource Compute3DTextureCopySubresourceWithRelaxedRowPitchAndOffset(
+ BufferTextureCopyDirection direction,
+ Origin3D origin,
+ Extent3D copySize,
+ const TexelBlockInfo& blockInfo,
+ uint64_t offset,
+ uint32_t bytesPerRow,
+ uint32_t rowsPerImage);
+
} // namespace dawn::native::d3d12
#endif // SRC_DAWN_NATIVE_D3D12_TEXTURECOPYSPLITTER_H_
diff --git a/src/dawn/native/d3d12/UtilsD3D12.cpp b/src/dawn/native/d3d12/UtilsD3D12.cpp
index 50602da..f79591a 100644
--- a/src/dawn/native/d3d12/UtilsD3D12.cpp
+++ b/src/dawn/native/d3d12/UtilsD3D12.cpp
@@ -312,11 +312,17 @@
break;
case wgpu::TextureDimension::e3D: {
- // See comments in Compute3DTextureCopySplits() for more details.
- TextureCopySubresource copyRegions =
- Compute3DTextureCopySplits(direction, textureCopy.origin, copySize, blockInfo,
- offset, bytesPerRow, rowsPerImage);
-
+ TextureCopySubresource copyRegions;
+ if (useRelaxedRowPitchAndOffset) {
+ copyRegions = Compute3DTextureCopySubresourceWithRelaxedRowPitchAndOffset(
+ direction, textureCopy.origin, copySize, blockInfo, offset, bytesPerRow,
+ rowsPerImage);
+ } else {
+ // See comments in Compute3DTextureCopySplits() for more details.
+ copyRegions =
+ Compute3DTextureCopySplits(direction, textureCopy.origin, copySize, blockInfo,
+ offset, bytesPerRow, rowsPerImage);
+ }
RecordBufferTextureCopyFromSplits(direction, commandList, copyRegions, bufferResource,
0, bytesPerRow, texture, textureCopy.mipLevel, 0,
textureCopy.aspect);