Align offset to 512 when writing into depth stencil textures on some platforms

On the D3D12 platforms that don't support programmable sample positions,
the source box specifying a portion of the depth texture must all be 0,
or an error and a device lost will occur. This patch adds a workaround
for this issue by alignning the offset of internal staging buffer to 512
when calling Queue.WriteTexture() with depth stencil textures

Bug: dawn:727
Test: dawn_end2end_tests
Change-Id: I6bc5843d62d0aec3964ee5b544a06c0b2657031a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98601
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao 2022-08-10 05:12:16 +00:00 committed by Dawn LUCI CQ
parent 7267d99251
commit 76eeb828c8
6 changed files with 94 additions and 4 deletions

View File

@ -1928,4 +1928,10 @@ bool DeviceBase::ShouldDuplicateParametersForDrawIndirect(
return false;
}
uint64_t DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil() const {
// For depth-stencil texture, buffer offset must be a multiple of 4, which is required
// by WebGPU and Vulkan SPEC.
return 4u;
}
} // namespace dawn::native

View File

@ -362,6 +362,7 @@ class DeviceBase : public RefCountedWithExternalCount {
// BackendMetadata that we can query from the device.
virtual uint32_t GetOptimalBytesPerRowAlignment() const = 0;
virtual uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const = 0;
virtual uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const;
virtual float GetTimestampPeriodInNS() const = 0;

View File

@ -97,11 +97,11 @@ ResultOrError<UploadHandle> UploadTextureDataAligningBytesPerRowAndOffset(
// since both of them are powers of two, we only need to align to the max value.
uint64_t offsetAlignment = std::max(optimalOffsetAlignment, uint64_t(blockInfo.byteSize));
// For depth-stencil texture, buffer offset must be a multiple of 4, which is required
// by WebGPU and Vulkan SPEC.
// Buffer offset alignments must follow additional restrictions when we copy with depth stencil
// formats.
if (hasDepthOrStencil) {
constexpr uint64_t kOffsetAlignmentForDepthStencil = 4;
offsetAlignment = std::max(offsetAlignment, kOffsetAlignmentForDepthStencil);
offsetAlignment =
std::max(offsetAlignment, device->GetBufferCopyOffsetAlignmentForDepthStencil());
}
UploadHandle uploadHandle;

View File

@ -899,4 +899,17 @@ bool Device::ShouldDuplicateParametersForDrawIndirect(
return ToBackend(renderPipelineBase)->UsesVertexOrInstanceIndex();
}
uint64_t Device::GetBufferCopyOffsetAlignmentForDepthStencil() const {
// On the D3D12 platforms where programmable MSAA is not supported, the source box specifying a
// portion of the depth texture must all be 0, or an error and a device lost will occur, so on
// these platforms the buffer copy offset must be a multiple of 512 when the texture is created
// with D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL. See https://crbug.com/dawn/727 for more
// details.
if (IsToggleEnabled(
Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset)) {
return D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
}
return DeviceBase::GetBufferCopyOffsetAlignmentForDepthStencil();
}
} // namespace dawn::native::d3d12

View File

@ -162,6 +162,8 @@ class Device final : public DeviceBase {
bool IsFeatureEnabled(Feature feature) const override;
uint64_t GetBufferCopyOffsetAlignmentForDepthStencil() const override;
// Dawn APIs
void SetLabelImpl() override;

View File

@ -704,8 +704,76 @@ TEST_P(QueueWriteTextureTests, WriteStencilAspectWithSourceOffsetUnalignedTo4) {
EXPECT_BUFFER_U8_RANGE_EQ(expectedData.data(), outputBuffer, 0, 8);
}
// Tests calling queue.writeTexture() to a depth texture after calling queue.writeTexture() on
// another texture always works. On some D3D12 backends the buffer offset of buffer-to-texture
// copies must be a multiple of 512 when the destination texture is a depth stencil texture.
TEST_P(QueueWriteTextureTests, WriteDepthAspectAfterOtherQueueWriteTextureCalls) {
// Copies to a single aspect are unsupported on OpenGL.
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
wgpu::TextureDescriptor textureDescriptor;
textureDescriptor.format = wgpu::TextureFormat::Depth16Unorm;
textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
textureDescriptor.size = {1, 1, 1};
wgpu::Texture depthTexture1 = device.CreateTexture(&textureDescriptor);
wgpu::Texture depthTexture2 = device.CreateTexture(&textureDescriptor);
constexpr uint16_t kExpectedData1 = (204 << 8) | 205;
wgpu::ImageCopyTexture imageCopyTexture1 = utils::CreateImageCopyTexture(depthTexture1);
wgpu::TextureDataLayout textureDataLayout =
utils::CreateTextureDataLayout(0, sizeof(kExpectedData1));
queue.WriteTexture(&imageCopyTexture1, &kExpectedData1, sizeof(kExpectedData1),
&textureDataLayout, &textureDescriptor.size);
constexpr uint16_t kExpectedData2 = (206 << 8) | 207;
wgpu::ImageCopyTexture imageCopyTexture2 = utils::CreateImageCopyTexture(depthTexture2);
queue.WriteTexture(&imageCopyTexture2, &kExpectedData2, sizeof(kExpectedData2),
&textureDataLayout, &textureDescriptor.size);
EXPECT_TEXTURE_EQ(&kExpectedData1, depthTexture1, {0, 0}, {1, 1}, 0,
wgpu::TextureAspect::DepthOnly);
EXPECT_TEXTURE_EQ(&kExpectedData2, depthTexture2, {0, 0}, {1, 1}, 0,
wgpu::TextureAspect::DepthOnly);
}
// Tests calling queue.writeTexture() to the stencil aspect after calling queue.writeTexture() on
// another texture always works. On some D3D12 backends the buffer offset of buffer-to-texture
// copies must be a multiple of 512 when the destination texture is a depth stencil texture.
TEST_P(QueueWriteTextureTests, WriteStencilAspectAfterOtherQueueWriteTextureCalls) {
// Copies to a single aspect are unsupported on OpenGL.
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
wgpu::TextureDescriptor textureDescriptor;
textureDescriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
textureDescriptor.size = {1, 1, 1};
wgpu::Texture depthStencilTexture1 = device.CreateTexture(&textureDescriptor);
wgpu::Texture depthStencilTexture2 = device.CreateTexture(&textureDescriptor);
constexpr uint8_t kExpectedData1 = 204u;
wgpu::ImageCopyTexture imageCopyTexture1 = utils::CreateImageCopyTexture(
depthStencilTexture1, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
wgpu::TextureDataLayout textureDataLayout =
utils::CreateTextureDataLayout(0, sizeof(kExpectedData1));
queue.WriteTexture(&imageCopyTexture1, &kExpectedData1, sizeof(kExpectedData1),
&textureDataLayout, &textureDescriptor.size);
constexpr uint8_t kExpectedData2 = 205;
wgpu::ImageCopyTexture imageCopyTexture2 = utils::CreateImageCopyTexture(
depthStencilTexture2, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
queue.WriteTexture(&imageCopyTexture2, &kExpectedData2, sizeof(kExpectedData2),
&textureDataLayout, &textureDescriptor.size);
EXPECT_TEXTURE_EQ(&kExpectedData1, depthStencilTexture1, {0, 0}, {1, 1}, 0,
wgpu::TextureAspect::StencilOnly);
EXPECT_TEXTURE_EQ(&kExpectedData2, depthStencilTexture2, {0, 0}, {1, 1}, 0,
wgpu::TextureAspect::StencilOnly);
}
DAWN_INSTANTIATE_TEST(QueueWriteTextureTests,
D3D12Backend(),
D3D12Backend({"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_"
"copy_with_non_zero_buffer_offset"}),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),