d3d12: Move functions in TextureCopySplitter to anonymous namespace
Bug: 424536624
Change-Id: If6846da88827dbd9f7916c0928dd2befe3a30f03
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/248094
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/d3d12/TextureCopySplitter.cpp b/src/dawn/native/d3d12/TextureCopySplitter.cpp
index e6a9437..5ec90658 100644
--- a/src/dawn/native/d3d12/TextureCopySplitter.cpp
+++ b/src/dawn/native/d3d12/TextureCopySplitter.cpp
@@ -58,6 +58,192 @@
return offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1);
}
+void Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight(
+ BlockOrigin3D origin,
+ BlockExtent3D copySize,
+ const TypedTexelBlockInfo& blockInfo,
+ BlockCount blocksPerRow,
+ BlockCount 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,
+ // height: 4, depthOrArrayLayers: 3}. Then the data layout in buffer is demonstrated
+ // as below:
+ //
+ // |<----- bytes per row ------>|
+ //
+ // |----------------------------|
+ // row (N - 1) | |
+ // row N | ++~~~~~~~~~|
+ // row (N + 1) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 2) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 3) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 4) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 5) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 6) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 7) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 8) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 9) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 10) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
+ // row (N + 11) |~~~~~~~~~~~~~~~~~++ |
+ // |----------------------------|
+
+ // The copy we mean to do is the following:
+ //
+ // - image 0: row N to row (N + 3),
+ // - image 1: row (N + 4) to row (N + 7),
+ // - image 2: row (N + 8) to row (N + 11).
+ //
+ // Note that alignedOffset is at the beginning of row (N - 1), while buffer offset makes
+ // the copy start at row N. Row (N - 1) is the empty row between alignedOffset and offset.
+ //
+ // The 2D copy region of image 0 we received from Compute2DTextureCopySubresource() is
+ // the following:
+ //
+ // |-------------------|
+ // row (N - 1) | |
+ // row N | ++|
+ // row (N + 1) |~~~~~~~~~~~~~~~~~++|
+ // row (N + 2) |~~~~~~~~~~~~~~~~~++|
+ // row (N + 3) |~~~~~~~~~~~~~~~~~++|
+ // |-------------------|
+ //
+ // However, if we simply expand the copy region of image 0 to all depth ranges of a 3D
+ // texture, we will copy 5 rows every time, and every first row of each slice will be
+ // skipped. As a result, the copied data will be:
+ //
+ // - image 0: row N to row (N + 3), which is correct. Row (N - 1) is skipped.
+ // - image 1: row (N + 5) to row (N + 8) because row (N + 4) is skipped. It is incorrect.
+ //
+ // Likewise, all other image followed will be incorrect because we wrongly keep skipping
+ // one row for each depth slice.
+ //
+ // Solution: split the copy region to two copies: copy 3 (rowsPerImage - 1) rows and
+ // expand to all depth slices in the first copy. 3 rows + one skipped rows = 4 rows, which
+ // equals to rowsPerImage. Then copy the last row in the second copy. However, the copy
+ // block of the last row of the last image may out-of-bound (see the details below), so
+ // we need an extra copy for the very last row.
+
+ // Copy 0: copy 3 rows, not 4 rows.
+ // _____________________
+ // / /|
+ // / / |
+ // |-------------------| |
+ // row (N - 1) | | |
+ // row N | ++| |
+ // row (N + 1) |~~~~~~~~~~~~~~~~~++| /
+ // row (N + 2) |~~~~~~~~~~~~~~~~~++|/
+ // |-------------------|
+
+ // Copy 1: move down two rows and copy the last row on image 0, and expand to
+ // copySize.depthOrArrayLayers - 1 depth slices. Note that if we expand it to all depth
+ // slices, the last copy block will be row (N + 9) to row (N + 12). Row (N + 11) might
+ // be the last row of the entire buffer. Then row (N + 12) will be out-of-bound.
+ // _____________________
+ // / /|
+ // / / |
+ // |-------------------| |
+ // row (N + 1) | | |
+ // row (N + 2) | | |
+ // row (N + 3) | ++| /
+ // row (N + 4) |~~~~~~~~~~~~~~~~~~~|/
+ // |-------------------|
+ //
+ // copy 2: copy the last row of the last image.
+ // |-------------------|
+ // row (N + 11)| ++|
+ // |-------------------|
+
+ // Copy 0: copy copySize0.height - 1 rows
+ TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
+ copy0.copySize.height = copySize.height - BlockCount{1};
+ copy0.bufferSize.height = rowsPerImage;
+
+ // 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 = copy1->alignedOffset + 2 * blockInfo.ToBytes(blocksPerRow);
+ copy1->textureOffset.y += copySize.height - BlockCount{1};
+ // Offset two rows from the copy height for bufferOffset1 (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 - BlockCount{2};
+ copy1->copySize.height = BlockCount{1};
+ copy1->copySize.depthOrArrayLayers--;
+ copy1->bufferSize.depthOrArrayLayers--;
+
+ // Copy 2: copy the last row of the last image.
+ uint64_t offsetForCopy0 =
+ OffsetToFirstCopiedTexel(blockInfo, blocksPerRow, copy0.alignedOffset, copy0.bufferOffset);
+ uint64_t offsetForLastRowOfLastImage =
+ offsetForCopy0 +
+ blockInfo.ToBytes(
+ blocksPerRow *
+ (copy0.copySize.height + rowsPerImage * (copySize.depthOrArrayLayers - BlockCount{1})));
+
+ uint64_t alignedOffsetForLastRowOfLastImage =
+ AlignDownForDataPlacement(offsetForLastRowOfLastImage);
+ BlockOrigin3D blockOffsetForLastRowOfLastImage = ComputeBlockOffsets(
+ blockInfo,
+ static_cast<uint32_t>(offsetForLastRowOfLastImage - alignedOffsetForLastRowOfLastImage),
+ blocksPerRow);
+
+ TextureCopySubresource::CopyInfo* copy2 = copy.AddCopy();
+ copy2->alignedOffset = alignedOffsetForLastRowOfLastImage;
+ copy2->textureOffset = copy1->textureOffset;
+ copy2->textureOffset.z = origin.z + copySize.depthOrArrayLayers - BlockCount{1};
+ copy2->copySize = copy1->copySize;
+ copy2->copySize.depthOrArrayLayers = BlockCount{1};
+ copy2->bufferOffset = blockOffsetForLastRowOfLastImage;
+ copy2->bufferSize.width = copy1->bufferSize.width;
+ DAWN_ASSERT(copy2->copySize.height == BlockCount{1});
+ copy2->bufferSize.height = copy2->bufferOffset.y + copy2->copySize.height;
+ copy2->bufferSize.depthOrArrayLayers = BlockCount{1};
+}
+
+void Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(
+ BlockExtent3D copySize,
+ const TypedTexelBlockInfo& blockInfo,
+ BlockCount blocksPerRow,
+ 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.
+ //
+ // If the copy height is odd, we can use two copies to make it correct:
+ // - copy 0: only copy the first depth slice. Keep other arguments the same.
+ // - copy 1: copy all rest depth slices because it will start without an empty row if
+ // copy height is odd. Odd height + one (empty row) is even. An even row number times
+ // bytesPerRow (256) will be aligned to D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512)
+
+ // Copy 0: copy the first depth slice (image 0)
+ TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
+ copy0.copySize.depthOrArrayLayers = BlockCount{1};
+ const BlockCount kBufferDepth0 = BlockCount{1};
+ copy0.bufferSize.depthOrArrayLayers = kBufferDepth0;
+
+ // Copy 1: copy the rest depth slices in one shot
+ TextureCopySubresource::CopyInfo* copy1 = copy.AddCopy();
+ *copy1 = copy0;
+ DAWN_ASSERT(copySize.height % BlockCount{2} == BlockCount{1});
+ copy1->alignedOffset += blockInfo.ToBytes((copySize.height + BlockCount{1}) * blocksPerRow);
+
+ DAWN_ASSERT(copy1->alignedOffset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0);
+ // textureOffset1.z should add one because the first slice has already been copied in copy0.
+ copy1->textureOffset.z++;
+ // bufferOffset1.y should be 0 because we skipped the first depth slice and there is no empty
+ // row in this copy region.
+ copy1->bufferOffset.y = BlockCount{0};
+ copy1->copySize.height = copySize.height;
+ copy1->copySize.depthOrArrayLayers = copySize.depthOrArrayLayers - BlockCount{1};
+ copy1->bufferSize.height = copySize.height;
+ copy1->bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers - BlockCount{1};
+}
+
} // namespace
TextureCopySubresource::CopyInfo* TextureCopySubresource::AddCopy() {
@@ -286,192 +472,6 @@
return copies;
}
-void Recompute3DTextureCopyRegionWithEmptyFirstRowAndEvenCopyHeight(
- BlockOrigin3D origin,
- BlockExtent3D copySize,
- const TypedTexelBlockInfo& blockInfo,
- BlockCount blocksPerRow,
- BlockCount 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,
- // height: 4, depthOrArrayLayers: 3}. Then the data layout in buffer is demonstrated
- // as below:
- //
- // |<----- bytes per row ------>|
- //
- // |----------------------------|
- // row (N - 1) | |
- // row N | ++~~~~~~~~~|
- // row (N + 1) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 2) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 3) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 4) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 5) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 6) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 7) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 8) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 9) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 10) |~~~~~~~~~~~~~~~~~++~~~~~~~~~|
- // row (N + 11) |~~~~~~~~~~~~~~~~~++ |
- // |----------------------------|
-
- // The copy we mean to do is the following:
- //
- // - image 0: row N to row (N + 3),
- // - image 1: row (N + 4) to row (N + 7),
- // - image 2: row (N + 8) to row (N + 11).
- //
- // Note that alignedOffset is at the beginning of row (N - 1), while buffer offset makes
- // the copy start at row N. Row (N - 1) is the empty row between alignedOffset and offset.
- //
- // The 2D copy region of image 0 we received from Compute2DTextureCopySubresource() is
- // the following:
- //
- // |-------------------|
- // row (N - 1) | |
- // row N | ++|
- // row (N + 1) |~~~~~~~~~~~~~~~~~++|
- // row (N + 2) |~~~~~~~~~~~~~~~~~++|
- // row (N + 3) |~~~~~~~~~~~~~~~~~++|
- // |-------------------|
- //
- // However, if we simply expand the copy region of image 0 to all depth ranges of a 3D
- // texture, we will copy 5 rows every time, and every first row of each slice will be
- // skipped. As a result, the copied data will be:
- //
- // - image 0: row N to row (N + 3), which is correct. Row (N - 1) is skipped.
- // - image 1: row (N + 5) to row (N + 8) because row (N + 4) is skipped. It is incorrect.
- //
- // Likewise, all other image followed will be incorrect because we wrongly keep skipping
- // one row for each depth slice.
- //
- // Solution: split the copy region to two copies: copy 3 (rowsPerImage - 1) rows and
- // expand to all depth slices in the first copy. 3 rows + one skipped rows = 4 rows, which
- // equals to rowsPerImage. Then copy the last row in the second copy. However, the copy
- // block of the last row of the last image may out-of-bound (see the details below), so
- // we need an extra copy for the very last row.
-
- // Copy 0: copy 3 rows, not 4 rows.
- // _____________________
- // / /|
- // / / |
- // |-------------------| |
- // row (N - 1) | | |
- // row N | ++| |
- // row (N + 1) |~~~~~~~~~~~~~~~~~++| /
- // row (N + 2) |~~~~~~~~~~~~~~~~~++|/
- // |-------------------|
-
- // Copy 1: move down two rows and copy the last row on image 0, and expand to
- // copySize.depthOrArrayLayers - 1 depth slices. Note that if we expand it to all depth
- // slices, the last copy block will be row (N + 9) to row (N + 12). Row (N + 11) might
- // be the last row of the entire buffer. Then row (N + 12) will be out-of-bound.
- // _____________________
- // / /|
- // / / |
- // |-------------------| |
- // row (N + 1) | | |
- // row (N + 2) | | |
- // row (N + 3) | ++| /
- // row (N + 4) |~~~~~~~~~~~~~~~~~~~|/
- // |-------------------|
- //
- // copy 2: copy the last row of the last image.
- // |-------------------|
- // row (N + 11)| ++|
- // |-------------------|
-
- // Copy 0: copy copySize0.height - 1 rows
- TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
- copy0.copySize.height = copySize.height - BlockCount{1};
- copy0.bufferSize.height = rowsPerImage;
-
- // 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 = copy1->alignedOffset + 2 * blockInfo.ToBytes(blocksPerRow);
- copy1->textureOffset.y += copySize.height - BlockCount{1};
- // Offset two rows from the copy height for bufferOffset1 (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 - BlockCount{2};
- copy1->copySize.height = BlockCount{1};
- copy1->copySize.depthOrArrayLayers--;
- copy1->bufferSize.depthOrArrayLayers--;
-
- // Copy 2: copy the last row of the last image.
- uint64_t offsetForCopy0 =
- OffsetToFirstCopiedTexel(blockInfo, blocksPerRow, copy0.alignedOffset, copy0.bufferOffset);
- uint64_t offsetForLastRowOfLastImage =
- offsetForCopy0 +
- blockInfo.ToBytes(
- blocksPerRow *
- (copy0.copySize.height + rowsPerImage * (copySize.depthOrArrayLayers - BlockCount{1})));
-
- uint64_t alignedOffsetForLastRowOfLastImage =
- AlignDownForDataPlacement(offsetForLastRowOfLastImage);
- BlockOrigin3D blockOffsetForLastRowOfLastImage = ComputeBlockOffsets(
- blockInfo,
- static_cast<uint32_t>(offsetForLastRowOfLastImage - alignedOffsetForLastRowOfLastImage),
- blocksPerRow);
-
- TextureCopySubresource::CopyInfo* copy2 = copy.AddCopy();
- copy2->alignedOffset = alignedOffsetForLastRowOfLastImage;
- copy2->textureOffset = copy1->textureOffset;
- copy2->textureOffset.z = origin.z + copySize.depthOrArrayLayers - BlockCount{1};
- copy2->copySize = copy1->copySize;
- copy2->copySize.depthOrArrayLayers = BlockCount{1};
- copy2->bufferOffset = blockOffsetForLastRowOfLastImage;
- copy2->bufferSize.width = copy1->bufferSize.width;
- DAWN_ASSERT(copy2->copySize.height == BlockCount{1});
- copy2->bufferSize.height = copy2->bufferOffset.y + copy2->copySize.height;
- copy2->bufferSize.depthOrArrayLayers = BlockCount{1};
-}
-
-void Recompute3DTextureCopyRegionWithEmptyFirstRowAndOddCopyHeight(
- BlockExtent3D copySize,
- const TypedTexelBlockInfo& blockInfo,
- BlockCount blocksPerRow,
- 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.
- //
- // If the copy height is odd, we can use two copies to make it correct:
- // - copy 0: only copy the first depth slice. Keep other arguments the same.
- // - copy 1: copy all rest depth slices because it will start without an empty row if
- // copy height is odd. Odd height + one (empty row) is even. An even row number times
- // bytesPerRow (256) will be aligned to D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512)
-
- // Copy 0: copy the first depth slice (image 0)
- TextureCopySubresource::CopyInfo& copy0 = copy.copies[i];
- copy0.copySize.depthOrArrayLayers = BlockCount{1};
- const BlockCount kBufferDepth0 = BlockCount{1};
- copy0.bufferSize.depthOrArrayLayers = kBufferDepth0;
-
- // Copy 1: copy the rest depth slices in one shot
- TextureCopySubresource::CopyInfo* copy1 = copy.AddCopy();
- *copy1 = copy0;
- DAWN_ASSERT(copySize.height % BlockCount{2} == BlockCount{1});
- copy1->alignedOffset += blockInfo.ToBytes((copySize.height + BlockCount{1}) * blocksPerRow);
-
- DAWN_ASSERT(copy1->alignedOffset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0);
- // textureOffset1.z should add one because the first slice has already been copied in copy0.
- copy1->textureOffset.z++;
- // bufferOffset1.y should be 0 because we skipped the first depth slice and there is no empty
- // row in this copy region.
- copy1->bufferOffset.y = BlockCount{0};
- copy1->copySize.height = copySize.height;
- copy1->copySize.depthOrArrayLayers = copySize.depthOrArrayLayers - BlockCount{1};
- copy1->bufferSize.height = copySize.height;
- copy1->bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers - BlockCount{1};
-}
-
TextureCopySubresource Compute3DTextureCopySplits(Origin3D origin_in,
Extent3D copySize_in,
const TexelBlockInfo& blockInfo_in,