Implement 3D texture copy splitter on D3D12: preparation

This change mainly is a preparation for 3D texture copy splitter,
which will be based on 2D texture copy splitter and then revise
or recompute incorrect copy regions if needed.

The change itself mainly rename some variables and comments and
distiguish 3D texture copies from 2D (array) texture copies. For
example, term slice is changed to layer if it only refers to layer
slices in 2D textures and it is not shared by depth slices in 3D
textures.

Bug: dawn:547

Change-Id: I6f84134a4fbcb90708901a1059b60e78e1a25ca5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/51900
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2021-06-01 19:55:33 +00:00 committed by Dawn LUCI CQ
parent 39633e2da2
commit 88097989d0
5 changed files with 175 additions and 106 deletions

View File

@ -33,12 +33,12 @@ namespace dawn_native { namespace d3d12 {
} }
} // namespace } // namespace
TextureCopySubresource ComputeTextureCopySubresource(Origin3D origin, TextureCopySubresource Compute2DTextureCopySubresource(Origin3D origin,
Extent3D copySize, Extent3D copySize,
const TexelBlockInfo& blockInfo, const TexelBlockInfo& blockInfo,
uint64_t offset, uint64_t offset,
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage) { uint32_t rowsPerImage) {
TextureCopySubresource copy; TextureCopySubresource copy;
ASSERT(bytesPerRow % blockInfo.byteSize == 0); ASSERT(bytesPerRow % blockInfo.byteSize == 0);
@ -48,20 +48,15 @@ namespace dawn_native { namespace d3d12 {
uint64_t alignedOffset = uint64_t alignedOffset =
offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1); offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1);
copy.offset = alignedOffset;
// If the provided offset to the data was already 512-aligned, we can simply copy the data // If the provided offset to the data was already 512-aligned, we can simply copy the data
// without further translation. // without further translation.
if (offset == alignedOffset) { if (offset == alignedOffset) {
copy.count = 1; copy.count = 1;
copy.copies[0].alignedOffset = alignedOffset;
copy.copies[0].textureOffset = origin; copy.copies[0].textureOffset = origin;
copy.copies[0].copySize = copySize; copy.copies[0].copySize = copySize;
copy.copies[0].bufferOffset = {0, 0, 0};
copy.copies[0].bufferOffset.x = 0;
copy.copies[0].bufferOffset.y = 0;
copy.copies[0].bufferOffset.z = 0;
copy.copies[0].bufferSize = copySize; copy.copies[0].bufferSize = copySize;
return copy; return copy;
@ -124,11 +119,11 @@ namespace dawn_native { namespace d3d12 {
copy.count = 1; copy.count = 1;
copy.copies[0].alignedOffset = alignedOffset;
copy.copies[0].textureOffset = origin; copy.copies[0].textureOffset = origin;
copy.copies[0].copySize = copySize; copy.copies[0].copySize = copySize;
copy.copies[0].bufferOffset = texelOffset; copy.copies[0].bufferOffset = texelOffset;
copy.copies[0].bufferSize.width = copySize.width + texelOffset.x; copy.copies[0].bufferSize.width = copySize.width + texelOffset.x;
copy.copies[0].bufferSize.height = rowsPerImageInTexels + texelOffset.y; copy.copies[0].bufferSize.height = rowsPerImageInTexels + texelOffset.y;
copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers; copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers;
@ -172,6 +167,7 @@ namespace dawn_native { namespace d3d12 {
copy.count = 2; copy.count = 2;
copy.copies[0].alignedOffset = alignedOffset;
copy.copies[0].textureOffset = origin; copy.copies[0].textureOffset = origin;
ASSERT(bytesPerRow > byteOffsetInRowPitch); ASSERT(bytesPerRow > byteOffsetInRowPitch);
@ -185,6 +181,7 @@ namespace dawn_native { namespace d3d12 {
copy.copies[0].bufferSize.height = rowsPerImageInTexels + texelOffset.y; copy.copies[0].bufferSize.height = rowsPerImageInTexels + texelOffset.y;
copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers; copy.copies[0].bufferSize.depthOrArrayLayers = copySize.depthOrArrayLayers;
copy.copies[1].alignedOffset = alignedOffset;
copy.copies[1].textureOffset.x = origin.x + copy.copies[0].copySize.width; copy.copies[1].textureOffset.x = origin.x + copy.copies[0].copySize.width;
copy.copies[1].textureOffset.y = origin.y; copy.copies[1].textureOffset.y = origin.y;
copy.copies[1].textureOffset.z = origin.z; copy.copies[1].textureOffset.z = origin.z;
@ -204,55 +201,102 @@ namespace dawn_native { namespace d3d12 {
return copy; return copy;
} }
TextureCopySplits ComputeTextureCopySplits(Origin3D origin, TextureCopySplits Compute2DTextureCopySplits(Origin3D origin,
Extent3D copySize, Extent3D copySize,
const TexelBlockInfo& blockInfo, const TexelBlockInfo& blockInfo,
uint64_t offset, uint64_t offset,
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage, uint32_t rowsPerImage) {
bool is3DTexture) {
TextureCopySplits copies; TextureCopySplits copies;
const uint64_t bytesPerSlice = bytesPerRow * rowsPerImage; const uint64_t bytesPerLayer = bytesPerRow * rowsPerImage;
// The function ComputeTextureCopySubresource() decides how to split the copy based on: // The function Compute2DTextureCopySubresource() decides how to split the copy based on:
// - the alignment of the buffer offset with D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512) // - the alignment of the buffer offset with D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512)
// - the alignment of the buffer offset with D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256) // - the alignment of the buffer offset with D3D12_TEXTURE_DATA_PITCH_ALIGNMENT (256)
// Each slice of a 2D array or 3D copy might need to be split, but because of the WebGPU // Each layer of a 2D array might need to be split, but because of the WebGPU
// constraint that "bytesPerRow" must be a multiple of 256, all odd (resp. all even) slices // constraint that "bytesPerRow" must be a multiple of 256, all odd (resp. all even) layers
// will be at an offset multiple of 512 of each other, which means they will all result in // will be at an offset multiple of 512 of each other, which means they will all result in
// the same 2D split. Thus we can just compute the copy splits for the first and second // the same 2D split. Thus we can just compute the copy splits for the first and second
// slices, and reuse them for the remaining slices by adding the related offset of each // layers, and reuse them for the remaining layers by adding the related offset of each
// slice. Moreover, if "rowsPerImage" is even, both the first and second copy layers can // layer. Moreover, if "rowsPerImage" is even, both the first and second copy layers can
// share the same copy split, so in this situation we just need to compute copy split once // share the same copy split, so in this situation we just need to compute copy split once
// and reuse it for all the slices. // and reuse it for all the layers.
Extent3D copyOneLayerSize = copySize; Extent3D copyOneLayerSize = copySize;
Origin3D copyFirstLayerOrigin = origin; Origin3D copyFirstLayerOrigin = origin;
if (!is3DTexture) { copyOneLayerSize.depthOrArrayLayers = 1;
copyOneLayerSize.depthOrArrayLayers = 1; copyFirstLayerOrigin.z = 0;
copyFirstLayerOrigin.z = 0;
}
copies.copySubresources[0] = ComputeTextureCopySubresource( copies.copySubresources[0] = Compute2DTextureCopySubresource(
copyFirstLayerOrigin, copyOneLayerSize, blockInfo, offset, bytesPerRow, rowsPerImage); copyFirstLayerOrigin, copyOneLayerSize, blockInfo, offset, bytesPerRow, rowsPerImage);
// When the copy only refers one texture 2D array layer or a 3D texture, // When the copy only refers one texture 2D array layer,
// copies.copySubresources[1] will never be used so we can safely early return here. // copies.copySubresources[1] will never be used so we can safely early return here.
if (copySize.depthOrArrayLayers == 1 || is3DTexture) { if (copySize.depthOrArrayLayers == 1) {
return copies; return copies;
} }
if (bytesPerSlice % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0) { if (bytesPerLayer % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT == 0) {
copies.copySubresources[1] = copies.copySubresources[0]; copies.copySubresources[1] = copies.copySubresources[0];
copies.copySubresources[1].offset += bytesPerSlice; copies.copySubresources[1].copies[0].alignedOffset += bytesPerLayer;
copies.copySubresources[1].copies[1].alignedOffset += bytesPerLayer;
} else { } else {
const uint64_t bufferOffsetNextLayer = offset + bytesPerSlice; const uint64_t bufferOffsetNextLayer = offset + bytesPerLayer;
copies.copySubresources[1] = copies.copySubresources[1] =
ComputeTextureCopySubresource(copyFirstLayerOrigin, copyOneLayerSize, blockInfo, Compute2DTextureCopySubresource(copyFirstLayerOrigin, copyOneLayerSize, blockInfo,
bufferOffsetNextLayer, bytesPerRow, rowsPerImage); bufferOffsetNextLayer, bytesPerRow, rowsPerImage);
} }
return copies; return copies;
} }
TextureCopySubresource Compute3DTextureCopySplits(Origin3D origin,
Extent3D copySize,
const TexelBlockInfo& blockInfo,
uint64_t offset,
uint32_t bytesPerRow,
uint32_t rowsPerImage) {
// To compute the copy region(s) for 3D textures, we call Compute2DTextureCopySubresource
// and get copy region(s) for the first slice of the copy, then extend to all depth slices
// and become a 3D copy. However, this doesn't work as easily as that due to some corner
// cases.
//
// For example, if bufferSize.height is greater than rowsPerImage in the generated copy
// region and we simply extend the 2D copy region to all copied depth slices, copied data
// will be incorrectly offset for each depth slice except the first one. This situation
// can be introduced by 2 special cases:
// - If there is an empty row at the beginning of the copy region due to alignment.
// - If copySize.height is 1 and one row of data straddle two rows.
//
// For these special cases, we need to recompute the copy regions for 3D textures like
// 1) split and modify the incorrect copy region to a few more copy regions, or 2) abandon
// the old copy region and regenerate the copy regions in different approach.
// 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, rowsPerImage);
// If copySize.depth is 1, we can return copySubresource. Because we don't need to extend
// the copy region(s) to other depth slice(s).
if (copySize.depthOrArrayLayers == 1) {
return copySubresource;
}
bool needRecompute = false;
for (uint32_t i = 0; i < copySubresource.count; ++i) {
if (copySubresource.copies[i].bufferSize.height > rowsPerImage) {
needRecompute = true;
break;
}
}
if (!needRecompute) {
return copySubresource;
}
// TODO(yunchao.he@intel.com): recompute copy regions for special cases for 3D textures,
// and return the revised copy regions.
return copySubresource;
}
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -31,6 +31,7 @@ namespace dawn_native { namespace d3d12 {
static constexpr unsigned int kMaxTextureCopyRegions = 2; static constexpr unsigned int kMaxTextureCopyRegions = 2;
struct CopyInfo { struct CopyInfo {
uint64_t alignedOffset = 0;
Origin3D textureOffset; Origin3D textureOffset;
Origin3D bufferOffset; Origin3D bufferOffset;
Extent3D bufferSize; Extent3D bufferSize;
@ -38,7 +39,6 @@ namespace dawn_native { namespace d3d12 {
Extent3D copySize; Extent3D copySize;
}; };
uint64_t offset = 0;
uint32_t count = 0; uint32_t count = 0;
std::array<CopyInfo, kMaxTextureCopyRegions> copies; std::array<CopyInfo, kMaxTextureCopyRegions> copies;
}; };
@ -49,20 +49,44 @@ namespace dawn_native { namespace d3d12 {
std::array<TextureCopySubresource, kMaxTextureCopySubresources> copySubresources; std::array<TextureCopySubresource, kMaxTextureCopySubresources> copySubresources;
}; };
TextureCopySubresource ComputeTextureCopySubresource(Origin3D origin, // This function is shared by 2D and 3D texture copy splitter. But it only knows how to handle
Extent3D copySize, // 2D non-arrayed textures correctly, and just forwards "copySize.depthOrArrayLayers". See
const TexelBlockInfo& blockInfo, // details in Compute{2D|3D}TextureCopySplits about how we generate copy regions for 2D array
uint64_t offset, // and 3D textures based on this function.
uint32_t bytesPerRow, // The resulting copies triggered by API like CopyTextureRegion are equivalent to the copy
uint32_t rowsPerImage); // regions defines by the arguments of TextureCopySubresource returned by this function and its
// counterparts. These arguments should strictly conform to particular invariants. Otherwise,
// D3D12 driver may report validation errors when we call CopyTextureRegion. Some important
// invariants are listed below. For more details
// of these invariants, see src/tests/unittests/d3d12/CopySplitTests.cpp.
// - Inside each copy region, its buffer offset plus copy size should be less than its buffer
// size.
// - each region has an offset (aka alignedOffset) aligned to
// D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT
// - If there are multiple copy regions, each copy region should not overlap with the others.
// - 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,
Extent3D copySize,
const TexelBlockInfo& blockInfo,
uint64_t offset,
uint32_t bytesPerRow,
uint32_t rowsPerImage);
TextureCopySplits ComputeTextureCopySplits(Origin3D origin, TextureCopySplits Compute2DTextureCopySplits(Origin3D origin,
Extent3D copySize, Extent3D copySize,
const TexelBlockInfo& blockInfo, const TexelBlockInfo& blockInfo,
uint64_t offset, uint64_t offset,
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage, uint32_t rowsPerImage);
bool is3DTexture = false);
TextureCopySubresource Compute3DTextureCopySplits(Origin3D origin,
Extent3D copySize,
const TexelBlockInfo& blockInfo,
uint64_t offset,
uint32_t bytesPerRow,
uint32_t rowsPerImage);
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_ #endif // DAWNNATIVE_D3D12_TEXTURECOPYSPLITTER_H_

View File

@ -984,7 +984,7 @@ namespace dawn_native { namespace d3d12 {
Extent3D copySize = GetMipLevelPhysicalSize(level); Extent3D copySize = GetMipLevelPhysicalSize(level);
uint32_t rowsPerImage = copySize.height / blockInfo.height; uint32_t rowsPerImage = copySize.height / blockInfo.height;
TextureCopySubresource copySplit = ComputeTextureCopySubresource( TextureCopySubresource copySplit = Compute2DTextureCopySubresource(
{0, 0, 0}, copySize, blockInfo, uploadHandle.startOffset, bytesPerRow, {0, 0, 0}, copySize, blockInfo, uploadHandle.startOffset, bytesPerRow,
rowsPerImage); rowsPerImage);

View File

@ -155,13 +155,12 @@ namespace dawn_native { namespace d3d12 {
const D3D12_TEXTURE_COPY_LOCATION textureLocation = const D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect); ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect);
const uint64_t offsetBytes = baseCopySplit.offset + baseOffset;
for (uint32_t i = 0; i < baseCopySplit.count; ++i) { for (uint32_t i = 0; i < baseCopySplit.count; ++i) {
const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i]; const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i];
// TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as
// members in TextureCopySubresource::CopyInfo. // members in TextureCopySubresource::CopyInfo.
const uint64_t offsetBytes = info.alignedOffset + baseOffset;
const D3D12_TEXTURE_COPY_LOCATION bufferLocation = const D3D12_TEXTURE_COPY_LOCATION bufferLocation =
ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize, ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize,
offsetBytes, bufferBytesPerRow, aspect); offsetBytes, bufferBytesPerRow, aspect);
@ -184,38 +183,38 @@ namespace dawn_native { namespace d3d12 {
Texture* texture, Texture* texture,
Aspect aspect) { Aspect aspect) {
ASSERT(HasOneBit(aspect)); ASSERT(HasOneBit(aspect));
// See comments in ComputeTextureCopySplits() for more details. // See comments in Compute2DTextureCopySplits() for more details.
const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block; const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block;
const TextureCopySplits copySplits = ComputeTextureCopySplits( const TextureCopySplits copySplits = Compute2DTextureCopySplits(
textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage); textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage);
const uint64_t bytesPerSlice = bytesPerRow * rowsPerImage; const uint64_t bytesPerLayer = bytesPerRow * rowsPerImage;
// copySplits.copySubresources[1] is always calculated for the second copy slice with // copySplits.copySubresources[1] is always calculated for the second copy layer with
// extra "bytesPerSlice" copy offset compared with the first copy slice. So // extra "bytesPerLayer" copy offset compared with the first copy layer. So
// here we use an array bufferOffsetsForNextSlice to record the extra offsets // here we use an array bufferOffsetsForNextLayer to record the extra offsets
// for each copy slice: bufferOffsetsForNextSlice[0] is the extra offset for // for each copy layer: bufferOffsetsForNextLayer[0] is the extra offset for
// the next copy slice that uses copySplits.copySubresources[0], and // the next copy layer that uses copySplits.copySubresources[0], and
// bufferOffsetsForNextSlice[1] is the extra offset for the next copy slice // bufferOffsetsForNextLayer[1] is the extra offset for the next copy layer
// that uses copySplits.copySubresources[1]. // that uses copySplits.copySubresources[1].
std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources> std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources>
bufferOffsetsForNextSlice = {{0u, 0u}}; bufferOffsetsForNextLayer = {{0u, 0u}};
for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) { for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) {
const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size(); const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size();
const TextureCopySubresource& copySplitPerLayerBase = const TextureCopySubresource& copySplitPerLayerBase =
copySplits.copySubresources[splitIndex]; copySplits.copySubresources[splitIndex];
const uint64_t bufferOffsetForNextSlice = bufferOffsetsForNextSlice[splitIndex]; const uint64_t bufferOffsetForNextLayer = bufferOffsetsForNextLayer[splitIndex];
const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z; const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z;
RecordCopyBufferToTextureFromTextureCopySplit( RecordCopyBufferToTextureFromTextureCopySplit(
commandContext->GetCommandList(), copySplitPerLayerBase, bufferResource, commandContext->GetCommandList(), copySplitPerLayerBase, bufferResource,
bufferOffsetForNextSlice, bytesPerRow, texture, textureCopy.mipLevel, bufferOffsetForNextLayer, bytesPerRow, texture, textureCopy.mipLevel,
copyTextureLayer, aspect); copyTextureLayer, aspect);
bufferOffsetsForNextSlice[splitIndex] += bufferOffsetsForNextLayer[splitIndex] +=
bytesPerSlice * copySplits.copySubresources.size(); bytesPerLayer * copySplits.copySubresources.size();
} }
} }
@ -229,14 +228,14 @@ namespace dawn_native { namespace d3d12 {
Texture* texture, Texture* texture,
Aspect aspect) { Aspect aspect) {
ASSERT(HasOneBit(aspect)); ASSERT(HasOneBit(aspect));
// See comments in ComputeTextureCopySplits() for more details. // See comments in Compute3DTextureCopySplits() for more details.
const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block; const TexelBlockInfo& blockInfo = texture->GetFormat().GetAspectInfo(aspect).block;
const TextureCopySplits copySplits = ComputeTextureCopySplits( const TextureCopySubresource copyRegions = Compute3DTextureCopySplits(
textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage, true); textureCopy.origin, copySize, blockInfo, offset, bytesPerRow, rowsPerImage);
RecordCopyBufferToTextureFromTextureCopySplit( RecordCopyBufferToTextureFromTextureCopySplit(commandContext->GetCommandList(), copyRegions,
commandContext->GetCommandList(), copySplits.copySubresources[0], bufferResource, 0, bufferResource, 0, bytesPerRow, texture,
bytesPerRow, texture, textureCopy.mipLevel, 0, aspect); textureCopy.mipLevel, 0, aspect);
} }
void RecordCopyBufferToTexture(CommandRecordingContext* commandContext, void RecordCopyBufferToTexture(CommandRecordingContext* commandContext,
@ -274,16 +273,15 @@ namespace dawn_native { namespace d3d12 {
const D3D12_TEXTURE_COPY_LOCATION textureLocation = const D3D12_TEXTURE_COPY_LOCATION textureLocation =
ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect); ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureLayer, aspect);
const uint64_t offset = baseCopySplit.offset + baseOffset;
for (uint32_t i = 0; i < baseCopySplit.count; ++i) { for (uint32_t i = 0; i < baseCopySplit.count; ++i) {
const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i]; const TextureCopySubresource::CopyInfo& info = baseCopySplit.copies[i];
// TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as // TODO(jiawei.shao@intel.com): pre-compute bufferLocation and sourceRegion as
// members in TextureCopySubresource::CopyInfo. // members in TextureCopySubresource::CopyInfo.
const uint64_t offsetBytes = info.alignedOffset + baseOffset;
const D3D12_TEXTURE_COPY_LOCATION bufferLocation = const D3D12_TEXTURE_COPY_LOCATION bufferLocation =
ComputeBufferLocationForCopyTextureRegion(texture, buffer->GetD3D12Resource(), ComputeBufferLocationForCopyTextureRegion(texture, buffer->GetD3D12Resource(),
info.bufferSize, offset, info.bufferSize, offsetBytes,
bufferBytesPerRow, aspect); bufferBytesPerRow, aspect);
const D3D12_BOX sourceRegion = const D3D12_BOX sourceRegion =
ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize); ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize);
@ -304,37 +302,37 @@ namespace dawn_native { namespace d3d12 {
const TexelBlockInfo& blockInfo = const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(textureCopy.aspect).block; texture->GetFormat().GetAspectInfo(textureCopy.aspect).block;
// See comments around ComputeTextureCopySplits() for more details. // See comments around Compute2DTextureCopySplits() for more details.
const TextureCopySplits copySplits = const TextureCopySplits copySplits =
ComputeTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset, Compute2DTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset,
bufferCopy.bytesPerRow, bufferCopy.rowsPerImage); bufferCopy.bytesPerRow, bufferCopy.rowsPerImage);
const uint64_t bytesPerSlice = bufferCopy.bytesPerRow * bufferCopy.rowsPerImage; const uint64_t bytesPerLayer = bufferCopy.bytesPerRow * bufferCopy.rowsPerImage;
// copySplits.copySubresources[1] is always calculated for the second copy slice with // copySplits.copySubresources[1] is always calculated for the second copy layer with
// extra "bytesPerSlice" copy offset compared with the first copy slice. So // extra "bytesPerLayer" copy offset compared with the first copy layer. So
// here we use an array bufferOffsetsForNextSlice to record the extra offsets // here we use an array bufferOffsetsForNextLayer to record the extra offsets
// for each copy slice: bufferOffsetsForNextSlice[0] is the extra offset for // for each copy layer: bufferOffsetsForNextLayer[0] is the extra offset for
// the next copy slice that uses copySplits.copySubresources[0], and // the next copy layer that uses copySplits.copySubresources[0], and
// bufferOffsetsForNextSlice[1] is the extra offset for the next copy slice // bufferOffsetsForNextLayer[1] is the extra offset for the next copy layer
// that uses copySplits.copySubresources[1]. // that uses copySplits.copySubresources[1].
std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources> std::array<uint64_t, TextureCopySplits::kMaxTextureCopySubresources>
bufferOffsetsForNextSlice = {{0u, 0u}}; bufferOffsetsForNextLayer = {{0u, 0u}};
for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) { for (uint32_t copyLayer = 0; copyLayer < copySize.depthOrArrayLayers; ++copyLayer) {
const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size(); const uint32_t splitIndex = copyLayer % copySplits.copySubresources.size();
const TextureCopySubresource& copySplitPerLayerBase = const TextureCopySubresource& copySplitPerLayerBase =
copySplits.copySubresources[splitIndex]; copySplits.copySubresources[splitIndex];
const uint64_t bufferOffsetForNextSlice = bufferOffsetsForNextSlice[splitIndex]; const uint64_t bufferOffsetForNextLayer = bufferOffsetsForNextLayer[splitIndex];
const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z; const uint32_t copyTextureLayer = copyLayer + textureCopy.origin.z;
RecordCopyTextureToBufferFromTextureCopySplit( RecordCopyTextureToBufferFromTextureCopySplit(
commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextSlice, commandList, copySplitPerLayerBase, buffer, bufferOffsetForNextLayer,
bufferCopy.bytesPerRow, texture, textureCopy.mipLevel, copyTextureLayer, bufferCopy.bytesPerRow, texture, textureCopy.mipLevel, copyTextureLayer,
textureCopy.aspect); textureCopy.aspect);
bufferOffsetsForNextSlice[splitIndex] += bufferOffsetsForNextLayer[splitIndex] +=
bytesPerSlice * copySplits.copySubresources.size(); bytesPerLayer * copySplits.copySubresources.size();
} }
} }
@ -348,13 +346,13 @@ namespace dawn_native { namespace d3d12 {
const TexelBlockInfo& blockInfo = const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(textureCopy.aspect).block; texture->GetFormat().GetAspectInfo(textureCopy.aspect).block;
// See comments around ComputeTextureCopySplits() for more details. // See comments around Compute3DTextureCopySplits() for more details.
const TextureCopySplits copySplits = const TextureCopySubresource copyRegions =
ComputeTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset, Compute3DTextureCopySplits(textureCopy.origin, copySize, blockInfo, bufferCopy.offset,
bufferCopy.bytesPerRow, bufferCopy.rowsPerImage, true); bufferCopy.bytesPerRow, bufferCopy.rowsPerImage);
RecordCopyTextureToBufferFromTextureCopySplit(commandList, copySplits.copySubresources[0], RecordCopyTextureToBufferFromTextureCopySplit(commandList, copyRegions, buffer, 0,
buffer, 0, bufferCopy.bytesPerRow, texture, bufferCopy.bytesPerRow, texture,
textureCopy.mipLevel, 0, textureCopy.aspect); textureCopy.mipLevel, 0, textureCopy.aspect);
} }

View File

@ -56,8 +56,11 @@ namespace {
// Check that the offset is aligned // Check that the offset is aligned
void ValidateOffset(const TextureCopySubresource& copySplit) { void ValidateOffset(const TextureCopySubresource& copySplit) {
ASSERT_TRUE(Align(copySplit.offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) == for (uint32_t i = 0; i < copySplit.count; ++i) {
copySplit.offset); ASSERT_TRUE(
Align(copySplit.copies[i].alignedOffset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) ==
copySplit.copies[i].alignedOffset);
}
} }
bool RangesOverlap(uint32_t minA, uint32_t maxA, uint32_t minB, uint32_t maxB) { bool RangesOverlap(uint32_t minA, uint32_t maxA, uint32_t minB, uint32_t maxB) {
@ -142,7 +145,7 @@ namespace {
uint32_t slicePitchInTexels = uint32_t slicePitchInTexels =
bytesPerRowInTexels * (bufferSpec.rowsPerImage / textureSpec.blockHeight); bytesPerRowInTexels * (bufferSpec.rowsPerImage / textureSpec.blockHeight);
uint32_t absoluteTexelOffset = uint32_t absoluteTexelOffset =
copySplit.offset / textureSpec.texelBlockSizeInBytes * texelsPerBlock + copy.alignedOffset / textureSpec.texelBlockSizeInBytes * texelsPerBlock +
copy.bufferOffset.x / textureSpec.blockWidth * texelsPerBlock + copy.bufferOffset.x / textureSpec.blockWidth * texelsPerBlock +
copy.bufferOffset.y / textureSpec.blockHeight * bytesPerRowInTexels; copy.bufferOffset.y / textureSpec.blockHeight * bytesPerRowInTexels;
@ -302,7 +305,7 @@ class CopySplitTest : public testing::Test {
blockInfo.width = textureSpec.blockWidth; blockInfo.width = textureSpec.blockWidth;
blockInfo.height = textureSpec.blockHeight; blockInfo.height = textureSpec.blockHeight;
blockInfo.byteSize = textureSpec.texelBlockSizeInBytes; blockInfo.byteSize = textureSpec.texelBlockSizeInBytes;
TextureCopySubresource copySplit = ComputeTextureCopySubresource( TextureCopySubresource copySplit = Compute2DTextureCopySubresource(
{textureSpec.x, textureSpec.y, textureSpec.z}, {textureSpec.x, textureSpec.y, textureSpec.z},
{textureSpec.width, textureSpec.height, textureSpec.depth}, blockInfo, {textureSpec.width, textureSpec.height, textureSpec.depth}, blockInfo,
bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage); bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);