Implement buffer lazy initialization before CopyBufferToTexture()

This patch adds the check and implementations of buffer lazy
initialization before CopyBufferToTexture().

The support of buffer lazy initialization before CopyTextureToBuffer()
is much more complicated than what we do for CopyBufferToTexture(), so
we decide to put it in another CL instead of writing them together with
CopyBufferToTexture().

BUG=dawn:414
TEST=dawn_end2end_tests

Change-Id: I45fdcdde2c9a0dafff23623815fc35c877990ef1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/25140
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Jiawei Shao 2020-07-20 02:08:59 +00:00 committed by Commit Bot service account
parent 1233b66c90
commit d0dd661f18
5 changed files with 89 additions and 0 deletions

View File

@ -663,6 +663,8 @@ namespace dawn_native { namespace d3d12 {
Buffer* buffer = ToBackend(copy->source.buffer.Get()); Buffer* buffer = ToBackend(copy->source.buffer.Get());
Texture* texture = ToBackend(copy->destination.texture.Get()); Texture* texture = ToBackend(copy->destination.texture.Get());
DAWN_TRY(buffer->EnsureDataInitialized(commandContext));
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {copy->destination.mipLevel, 1, SubresourceRange subresources = {copy->destination.mipLevel, 1,
copy->destination.origin.z, copy->destination.origin.z,

View File

@ -601,6 +601,7 @@ namespace dawn_native { namespace metal {
Buffer* buffer = ToBackend(src.buffer.Get()); Buffer* buffer = ToBackend(src.buffer.Get());
Texture* texture = ToBackend(dst.texture.Get()); Texture* texture = ToBackend(dst.texture.Get());
buffer->EnsureDataInitialized(commandContext);
EnsureDestinationTextureInitialized(texture, copy->destination, copy->copySize); EnsureDestinationTextureInitialized(texture, copy->destination, copy->copySize);
TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit( TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit(

View File

@ -518,6 +518,8 @@ namespace dawn_native { namespace opengl {
GLenum target = texture->GetGLTarget(); GLenum target = texture->GetGLTarget();
const GLFormat& format = texture->GetGLFormat(); const GLFormat& format = texture->GetGLFormat();
buffer->EnsureDataInitialized();
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
SubresourceRange subresources = {dst.mipLevel, 1, dst.origin.z, SubresourceRange subresources = {dst.mipLevel, 1, dst.origin.z,
copy->copySize.depth}; copy->copySize.depth};

View File

@ -447,6 +447,8 @@ namespace dawn_native { namespace vulkan {
auto& src = copy->source; auto& src = copy->source;
auto& dst = copy->destination; auto& dst = copy->destination;
ToBackend(src.buffer)->EnsureDataInitialized(recordingContext);
VkBufferImageCopy region = VkBufferImageCopy region =
ComputeBufferImageCopyRegion(src, dst, copy->copySize); ComputeBufferImageCopyRegion(src, dst, copy->copySize);
VkImageSubresourceLayers subresource = region.imageSubresource; VkImageSubresourceLayers subresource = region.imageSubresource;

View File

@ -59,6 +59,25 @@ class BufferZeroInitTest : public DawnTest {
WaitABit(); WaitABit();
} }
} }
wgpu::Texture CreateAndInitialize2DTexture(const wgpu::Extent3D& size,
wgpu::TextureFormat format) {
wgpu::TextureDescriptor descriptor;
descriptor.size = size;
descriptor.format = format;
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::OutputAttachment;
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
utils::ComboRenderPassDescriptor renderPassDescriptor({texture.CreateView()});
wgpu::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDescriptor);
renderPass.EndPass();
wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
return texture;
}
}; };
// Test that calling writeBuffer to overwrite the entire buffer doesn't need to lazily initialize // Test that calling writeBuffer to overwrite the entire buffer doesn't need to lazily initialize
@ -379,6 +398,69 @@ TEST_P(BufferZeroInitTest, MapAtCreation) {
kExpectedData.size()); kExpectedData.size());
} }
// Test that the code path of CopyBufferToTexture clears the source buffer correctly when it is the
// first use of the buffer.
TEST_P(BufferZeroInitTest, CopyBufferToTexture) {
constexpr wgpu::Extent3D kTextureSize = {16u, 16u, 1u};
constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
wgpu::Texture texture = CreateAndInitialize2DTexture(kTextureSize, kTextureFormat);
const wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
const uint32_t requiredBufferSizeForCopy = utils::GetBytesInBufferTextureCopy(
kTextureFormat, kTextureSize.width, kTextureBytesPerRowAlignment, kTextureSize.width,
kTextureSize.depth);
constexpr wgpu::BufferUsage kBufferUsage =
wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
// bufferOffset == 0
{
constexpr uint64_t kOffset = 0;
const uint32_t totalBufferSize = requiredBufferSizeForCopy + kOffset;
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = totalBufferSize;
bufferDescriptor.usage = kBufferUsage;
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
const wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
buffer, kOffset, kTextureBytesPerRowAlignment, kTextureSize.height);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &kTextureSize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
std::vector<uint32_t> expectedValues(totalBufferSize / sizeof(uint32_t), 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedValues.data(), buffer, 0,
totalBufferSize / sizeof(uint32_t));
}
// bufferOffset > 0
{
constexpr uint64_t kOffset = 8u;
const uint32_t totalBufferSize = requiredBufferSizeForCopy + kOffset;
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = totalBufferSize;
bufferDescriptor.usage = kBufferUsage;
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
const wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
buffer, kOffset, kTextureBytesPerRowAlignment, kTextureSize.height);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &kTextureSize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
std::vector<uint32_t> expectedValues(totalBufferSize / sizeof(uint32_t), 0);
EXPECT_BUFFER_U32_RANGE_EQ(expectedValues.data(), buffer, 0,
totalBufferSize / sizeof(uint32_t));
}
}
DAWN_INSTANTIATE_TEST(BufferZeroInitTest, DAWN_INSTANTIATE_TEST(BufferZeroInitTest,
D3D12Backend({"nonzero_clear_resources_on_creation_for_testing", D3D12Backend({"nonzero_clear_resources_on_creation_for_testing",
"lazy_clear_buffer_on_first_use"}), "lazy_clear_buffer_on_first_use"}),