Support Noop Copy for B2T, T2B and T2T Copies
In B2T, T2B and T2T copies, copySize has 0 in width, height or depth will trigger errors in D3D12 backend. This patch bypass the command record step for noop copy. But all validation rules still applies to the copy. BUG=dawn:255 Change-Id: I4d01cef2e3c1f78440014c2c6ac63a48310d99af Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28521 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
a3651d2fe0
commit
75e5ed6161
|
@ -654,19 +654,22 @@ namespace dawn_native {
|
|||
Align(copySize->width * blockInfo.blockByteSize, kTextureBytesPerRowAlignment);
|
||||
}
|
||||
|
||||
// Record the copy command.
|
||||
CopyBufferToTextureCmd* copy =
|
||||
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
||||
copy->source.buffer = source->buffer;
|
||||
copy->source.offset = source->layout.offset;
|
||||
copy->source.bytesPerRow = bytesPerRow;
|
||||
copy->source.rowsPerImage = defaultedRowsPerImage;
|
||||
copy->destination.texture = destination->texture;
|
||||
copy->destination.origin = destination->origin;
|
||||
copy->destination.mipLevel = destination->mipLevel;
|
||||
copy->destination.aspect =
|
||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||
copy->copySize = *copySize;
|
||||
// Skip noop copies.
|
||||
if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
|
||||
// Record the copy command.
|
||||
CopyBufferToTextureCmd* copy =
|
||||
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
||||
copy->source.buffer = source->buffer;
|
||||
copy->source.offset = source->layout.offset;
|
||||
copy->source.bytesPerRow = bytesPerRow;
|
||||
copy->source.rowsPerImage = defaultedRowsPerImage;
|
||||
copy->destination.texture = destination->texture;
|
||||
copy->destination.origin = destination->origin;
|
||||
copy->destination.mipLevel = destination->mipLevel;
|
||||
copy->destination.aspect =
|
||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||
copy->copySize = *copySize;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
@ -713,18 +716,21 @@ namespace dawn_native {
|
|||
Align(copySize->width * blockInfo.blockByteSize, kTextureBytesPerRowAlignment);
|
||||
}
|
||||
|
||||
// Record the copy command.
|
||||
CopyTextureToBufferCmd* copy =
|
||||
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->source.mipLevel = source->mipLevel;
|
||||
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
||||
copy->destination.buffer = destination->buffer;
|
||||
copy->destination.offset = destination->layout.offset;
|
||||
copy->destination.bytesPerRow = bytesPerRow;
|
||||
copy->destination.rowsPerImage = defaultedRowsPerImage;
|
||||
copy->copySize = *copySize;
|
||||
// Skip noop copies.
|
||||
if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
|
||||
// Record the copy command.
|
||||
CopyTextureToBufferCmd* copy =
|
||||
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->source.mipLevel = source->mipLevel;
|
||||
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
||||
copy->destination.buffer = destination->buffer;
|
||||
copy->destination.offset = destination->layout.offset;
|
||||
copy->destination.bytesPerRow = bytesPerRow;
|
||||
copy->destination.rowsPerImage = defaultedRowsPerImage;
|
||||
copy->copySize = *copySize;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
@ -754,18 +760,21 @@ namespace dawn_native {
|
|||
mTopLevelTextures.insert(destination->texture);
|
||||
}
|
||||
|
||||
CopyTextureToTextureCmd* copy =
|
||||
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->source.mipLevel = source->mipLevel;
|
||||
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
||||
copy->destination.texture = destination->texture;
|
||||
copy->destination.origin = destination->origin;
|
||||
copy->destination.mipLevel = destination->mipLevel;
|
||||
copy->destination.aspect =
|
||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||
copy->copySize = *copySize;
|
||||
// Skip noop copies.
|
||||
if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
|
||||
CopyTextureToTextureCmd* copy =
|
||||
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->source.mipLevel = source->mipLevel;
|
||||
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
||||
copy->destination.texture = destination->texture;
|
||||
copy->destination.origin = destination->origin;
|
||||
copy->destination.mipLevel = destination->mipLevel;
|
||||
copy->destination.aspect =
|
||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||
copy->copySize = *copySize;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
|
|
@ -88,6 +88,7 @@ class CopyTests_T2B : public CopyTests {
|
|||
void DoTest(const TextureSpec& textureSpec,
|
||||
const BufferSpec& bufferSpec,
|
||||
const wgpu::Extent3D& copySize) {
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat);
|
||||
// Create a texture that is `width` x `height` with (`level` + 1) mip levels.
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||
|
@ -121,13 +122,10 @@ class CopyTests_T2B : public CopyTests {
|
|||
// Prepopulating the buffer with empty data ensures that there is not random data in the
|
||||
// expectation and helps ensure that the padding due to the bytes per row is not modified
|
||||
// by the copy.
|
||||
// TODO(jiawei.shao@intel.com): remove the initialization of the buffer after we support
|
||||
// buffer lazy-initialization.
|
||||
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat);
|
||||
const std::vector<RGBA8> emptyData(bufferSpec.size / bytesPerTexel, RGBA8());
|
||||
wgpu::Buffer buffer =
|
||||
utils::CreateBufferFromData(device, emptyData.data(), bufferSpec.size,
|
||||
wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
|
||||
wgpu::BufferDescriptor bufferDesc;
|
||||
bufferDesc.size = bufferSpec.size;
|
||||
bufferDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||
wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
|
||||
|
||||
{
|
||||
wgpu::TextureCopyView textureCopyView =
|
||||
|
@ -141,8 +139,11 @@ class CopyTests_T2B : public CopyTests {
|
|||
queue.Submit(1, &commands);
|
||||
|
||||
uint64_t bufferOffset = bufferSpec.offset;
|
||||
const uint32_t texelCountInCopyRegion =
|
||||
bufferSpec.bytesPerRow / bytesPerTexel * (copySize.height - 1) + copySize.width;
|
||||
|
||||
const wgpu::Extent3D copySizePerSlice = {copySize.width, copySize.height, 1};
|
||||
// Texels in single slice.
|
||||
const uint32_t texelCountInCopyRegion = utils::GetTexelCountInCopyRegion(
|
||||
bufferSpec.bytesPerRow, bufferSpec.rowsPerImage, copySizePerSlice, kTextureFormat);
|
||||
const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth;
|
||||
std::vector<RGBA8> expected(texelCountInCopyRegion);
|
||||
for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) {
|
||||
|
@ -298,6 +299,7 @@ class CopyTests_T2T : public CopyTests {
|
|||
utils::CreateTextureCopyView(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z});
|
||||
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Layout.mipSize);
|
||||
|
||||
const wgpu::Extent3D copySizePerSlice = {copySize.width, copySize.height, 1};
|
||||
// Perform the texture to texture copy
|
||||
wgpu::TextureCopyView srcTextureCopyView =
|
||||
utils::CreateTextureCopyView(srcTexture, srcSpec.level, srcSpec.copyOrigin);
|
||||
|
@ -308,8 +310,10 @@ class CopyTests_T2T : public CopyTests {
|
|||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
const uint32_t texelCountInCopyRegion =
|
||||
copyLayout.texelBlocksPerRow * (copySize.height - 1) + copySize.width;
|
||||
// Texels in single slice.
|
||||
const uint32_t texelCountInCopyRegion = utils::GetTexelCountInCopyRegion(
|
||||
copyLayout.bytesPerRow, copyLayout.bytesPerImage / copyLayout.bytesPerRow,
|
||||
copySizePerSlice, kTextureFormat);
|
||||
std::vector<RGBA8> expected(texelCountInCopyRegion);
|
||||
for (uint32_t slice = 0; slice < copySize.depth; ++slice) {
|
||||
std::fill(expected.begin(), expected.end(), RGBA8());
|
||||
|
@ -395,6 +399,21 @@ TEST_P(CopyTests_T2B, FullTextureAligned) {
|
|||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
|
||||
}
|
||||
|
||||
// Test noop copies
|
||||
TEST_P(CopyTests_T2B, ZeroSizedCopy) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
|
||||
TextureSpec textureSpec;
|
||||
textureSpec.textureSize = {kWidth, kHeight, 1};
|
||||
textureSpec.copyOrigin = {0, 0, 0};
|
||||
textureSpec.level = 0;
|
||||
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {0, kHeight, 1});
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, 0, 1});
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 0});
|
||||
}
|
||||
|
||||
// Test that copying an entire texture without 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_T2B, FullTextureUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
|
@ -830,6 +849,21 @@ TEST_P(CopyTests_B2T, FullTextureAligned) {
|
|||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1});
|
||||
}
|
||||
|
||||
// Test noop copies.
|
||||
TEST_P(CopyTests_B2T, ZeroSizedCopy) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
|
||||
TextureSpec textureSpec;
|
||||
textureSpec.textureSize = {kWidth, kHeight, 1};
|
||||
textureSpec.copyOrigin = {0, 0, 0};
|
||||
textureSpec.level = 0;
|
||||
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {0, kHeight, 1});
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, 0, 1});
|
||||
DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 0});
|
||||
}
|
||||
|
||||
// Test that copying an entire texture without 256-byte aligned dimensions works
|
||||
TEST_P(CopyTests_B2T, FullTextureUnaligned) {
|
||||
constexpr uint32_t kWidth = 259;
|
||||
|
@ -1244,6 +1278,20 @@ TEST_P(CopyTests_T2T, Texture) {
|
|||
DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1});
|
||||
}
|
||||
|
||||
// Test noop copies.
|
||||
TEST_P(CopyTests_T2T, ZeroSizedCopy) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
|
||||
TextureSpec textureSpec;
|
||||
textureSpec.copyOrigin = {0, 0, 0};
|
||||
textureSpec.level = 0;
|
||||
textureSpec.textureSize = {kWidth, kHeight, 1};
|
||||
DoTest(textureSpec, textureSpec, {0, kHeight, 1});
|
||||
DoTest(textureSpec, textureSpec, {kWidth, 0, 1});
|
||||
DoTest(textureSpec, textureSpec, {kWidth, kHeight, 0});
|
||||
}
|
||||
|
||||
TEST_P(CopyTests_T2T, TextureRegion) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
|
|
|
@ -87,6 +87,14 @@ namespace utils {
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t GetTexelCountInCopyRegion(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat) {
|
||||
return RequiredBytesInCopy(bytesPerRow, rowsPerImage, copyExtent, textureFormat) /
|
||||
utils::GetTexelBlockSizeInBytes(textureFormat);
|
||||
}
|
||||
|
||||
void UnalignDynamicUploader(wgpu::Device device) {
|
||||
std::vector<uint8_t> data = {1};
|
||||
|
||||
|
|
|
@ -46,6 +46,11 @@ namespace utils {
|
|||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat);
|
||||
|
||||
uint64_t GetTexelCountInCopyRegion(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat);
|
||||
|
||||
// A helper function used for testing DynamicUploader offset alignment.
|
||||
// A call of this function will do a Queue::WriteTexture with 1 byte of data,
|
||||
// so that assuming that WriteTexture uses DynamicUploader, the first RingBuffer
|
||||
|
|
Loading…
Reference in New Issue