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>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index bc5b533..09eb91f 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -654,19 +654,22 @@
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 @@
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 @@
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 {};
});
diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp
index 311d98a..9dbbbbd 100644
--- a/src/tests/end2end/CopyTests.cpp
+++ b/src/tests/end2end/CopyTests.cpp
@@ -88,6 +88,7 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
diff --git a/src/utils/TestUtils.cpp b/src/utils/TestUtils.cpp
index cdbe3b3..c56cb8d 100644
--- a/src/utils/TestUtils.cpp
+++ b/src/utils/TestUtils.cpp
@@ -87,6 +87,14 @@
}
}
+ 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};
diff --git a/src/utils/TestUtils.h b/src/utils/TestUtils.h
index d1ba25f..c75ca64 100644
--- a/src/utils/TestUtils.h
+++ b/src/utils/TestUtils.h
@@ -46,6 +46,11 @@
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