Support depth-only/stencil-only copies on D3D12 Bug: dawn:439 Change-Id: I919a5e7bcb46f1817f9b15aaf49a1a72680aa47a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24960 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 8fd4a5a..684a5e9 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -118,7 +118,7 @@ const D3D12_TEXTURE_COPY_LOCATION bufferLocation = ComputeBufferLocationForCopyTextureRegion(texture, buffer->GetD3D12Resource(), info.bufferSize, offset, - bufferBytesPerRow); + bufferBytesPerRow, aspect); const D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(info.textureOffset, info.copySize); @@ -706,15 +706,17 @@ subresources); buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst); + const TexelBlockInfo& blockInfo = + texture->GetFormat().GetTexelBlockInfo(copy->source.aspect); + // See comments around ComputeTextureCopySplits() for more details. const TextureCopySplits copySplits = ComputeTextureCopySplits( - copy->source.origin, copy->copySize, texture->GetFormat(), - copy->destination.offset, copy->destination.bytesPerRow, - copy->destination.rowsPerImage); + copy->source.origin, copy->copySize, blockInfo, copy->destination.offset, + copy->destination.bytesPerRow, copy->destination.rowsPerImage); const uint64_t bytesPerSlice = copy->destination.bytesPerRow * - (copy->destination.rowsPerImage / texture->GetFormat().blockHeight); + (copy->destination.rowsPerImage / blockInfo.blockHeight); // copySplits.copies2D[1] is always calculated for the second copy slice with // extra "bytesPerSlice" copy offset compared with the first copy slice. So
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 2e2e60e..b040b1d 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -17,6 +17,7 @@ #include "common/Assert.h" #include "dawn_native/BackendConnection.h" #include "dawn_native/ErrorData.h" +#include "dawn_native/Format.h" #include "dawn_native/Instance.h" #include "dawn_native/d3d12/AdapterD3D12.h" #include "dawn_native/d3d12/BackendD3D12.h"
diff --git a/src/dawn_native/d3d12/TextureCopySplitter.cpp b/src/dawn_native/d3d12/TextureCopySplitter.cpp index 07da049..e1d380c 100644 --- a/src/dawn_native/d3d12/TextureCopySplitter.cpp +++ b/src/dawn_native/d3d12/TextureCopySplitter.cpp
@@ -21,7 +21,7 @@ namespace dawn_native { namespace d3d12 { namespace { - Origin3D ComputeTexelOffsets(const Format& format, + Origin3D ComputeTexelOffsets(const TexelBlockInfo& blockInfo, uint32_t offset, uint32_t bytesPerRow, uint32_t slicePitch) { @@ -32,20 +32,20 @@ uint32_t byteOffsetY = offset % slicePitch; uint32_t byteOffsetZ = offset - byteOffsetY; - return {byteOffsetX / format.blockByteSize * format.blockWidth, - byteOffsetY / bytesPerRow * format.blockHeight, byteOffsetZ / slicePitch}; + return {byteOffsetX / blockInfo.blockByteSize * blockInfo.blockWidth, + byteOffsetY / bytesPerRow * blockInfo.blockHeight, byteOffsetZ / slicePitch}; } } // namespace Texture2DCopySplit ComputeTextureCopySplit(Origin3D origin, Extent3D copySize, - const Format& format, + const TexelBlockInfo& blockInfo, uint64_t offset, uint32_t bytesPerRow, uint32_t rowsPerImage) { Texture2DCopySplit copy; - ASSERT(bytesPerRow % format.blockByteSize == 0); + ASSERT(bytesPerRow % blockInfo.blockByteSize == 0); uint64_t alignedOffset = offset & ~static_cast<uint64_t>(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1); @@ -71,12 +71,14 @@ ASSERT(alignedOffset < offset); ASSERT(offset - alignedOffset < D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - uint32_t slicePitch = bytesPerRow * (rowsPerImage / format.blockHeight); + uint32_t slicePitch = bytesPerRow * (rowsPerImage / blockInfo.blockHeight); Origin3D texelOffset = ComputeTexelOffsets( - format, static_cast<uint32_t>(offset - alignedOffset), bytesPerRow, slicePitch); + blockInfo, static_cast<uint32_t>(offset - alignedOffset), bytesPerRow, slicePitch); - uint32_t copyBytesPerRowPitch = copySize.width / format.blockWidth * format.blockByteSize; - uint32_t byteOffsetInRowPitch = texelOffset.x / format.blockWidth * format.blockByteSize; + uint32_t copyBytesPerRowPitch = + copySize.width / blockInfo.blockWidth * blockInfo.blockByteSize; + uint32_t byteOffsetInRowPitch = + texelOffset.x / blockInfo.blockWidth * blockInfo.blockByteSize; if (copyBytesPerRowPitch + byteOffsetInRowPitch <= bytesPerRow) { // The region's rows fit inside the bytes per row. In this case, extend the width of the // PlacedFootprint and copy the buffer with an offset location @@ -154,7 +156,7 @@ copy.copies[0].textureOffset = origin; ASSERT(bytesPerRow > byteOffsetInRowPitch); - uint32_t texelsPerRow = bytesPerRow / format.blockByteSize * format.blockWidth; + uint32_t texelsPerRow = bytesPerRow / blockInfo.blockByteSize * blockInfo.blockWidth; copy.copies[0].copySize.width = texelsPerRow - texelOffset.x; copy.copies[0].copySize.height = copySize.height; copy.copies[0].copySize.depth = copySize.depth; @@ -174,10 +176,10 @@ copy.copies[1].copySize.depth = copySize.depth; copy.copies[1].bufferOffset.x = 0; - copy.copies[1].bufferOffset.y = texelOffset.y + format.blockHeight; + copy.copies[1].bufferOffset.y = texelOffset.y + blockInfo.blockHeight; copy.copies[1].bufferOffset.z = texelOffset.z; copy.copies[1].bufferSize.width = copy.copies[1].copySize.width; - copy.copies[1].bufferSize.height = rowsPerImage + texelOffset.y + format.blockHeight; + copy.copies[1].bufferSize.height = rowsPerImage + texelOffset.y + blockInfo.blockHeight; copy.copies[1].bufferSize.depth = copySize.depth + texelOffset.z; return copy; @@ -185,13 +187,13 @@ TextureCopySplits ComputeTextureCopySplits(Origin3D origin, Extent3D copySize, - const Format& format, + const TexelBlockInfo& blockInfo, uint64_t offset, uint32_t bytesPerRow, uint32_t rowsPerImage) { TextureCopySplits copies; - const uint64_t bytesPerSlice = bytesPerRow * (rowsPerImage / format.blockHeight); + const uint64_t bytesPerSlice = bytesPerRow * (rowsPerImage / blockInfo.blockHeight); // The function ComputeTextureCopySplit() decides how to split the copy based on: // - the alignment of the buffer offset with D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT (512) @@ -207,8 +209,8 @@ const dawn_native::Extent3D copyOneLayerSize = {copySize.width, copySize.height, 1}; const dawn_native::Origin3D copyFirstLayerOrigin = {origin.x, origin.y, 0}; - copies.copies2D[0] = ComputeTextureCopySplit(copyFirstLayerOrigin, copyOneLayerSize, format, - offset, bytesPerRow, rowsPerImage); + copies.copies2D[0] = ComputeTextureCopySplit(copyFirstLayerOrigin, copyOneLayerSize, + blockInfo, offset, bytesPerRow, rowsPerImage); // When the copy only refers one texture 2D array layer copies.copies2D[1] will never be // used so we can safely early return here. @@ -222,7 +224,7 @@ } else { const uint64_t bufferOffsetNextLayer = offset + bytesPerSlice; copies.copies2D[1] = - ComputeTextureCopySplit(copyFirstLayerOrigin, copyOneLayerSize, format, + ComputeTextureCopySplit(copyFirstLayerOrigin, copyOneLayerSize, blockInfo, bufferOffsetNextLayer, bytesPerRow, rowsPerImage); }
diff --git a/src/dawn_native/d3d12/TextureCopySplitter.h b/src/dawn_native/d3d12/TextureCopySplitter.h index f9f4b36..962c332 100644 --- a/src/dawn_native/d3d12/TextureCopySplitter.h +++ b/src/dawn_native/d3d12/TextureCopySplitter.h
@@ -21,7 +21,7 @@ namespace dawn_native { - struct Format; + struct TexelBlockInfo; } // namespace dawn_native @@ -51,14 +51,14 @@ Texture2DCopySplit ComputeTextureCopySplit(Origin3D origin, Extent3D copySize, - const Format& format, + const TexelBlockInfo& blockInfo, uint64_t offset, uint32_t bytesPerRow, uint32_t rowsPerImage); TextureCopySplits ComputeTextureCopySplits(Origin3D origin, Extent3D copySize, - const Format& format, + const TexelBlockInfo& blockInfo, uint64_t offset, uint32_t bytesPerRow, uint32_t rowsPerImage);
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index 7767aa8..048822c 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -548,6 +548,26 @@ return mResourceAllocation.GetD3D12Resource(); } + DXGI_FORMAT Texture::GetD3D12CopyableSubresourceFormat(Aspect aspect) const { + ASSERT(GetFormat().aspects & aspect); + + switch (GetFormat().format) { + case wgpu::TextureFormat::Depth24PlusStencil8: + switch (aspect) { + case Aspect::Depth: + return DXGI_FORMAT_R32_FLOAT; + case Aspect::Stencil: + return DXGI_FORMAT_R8_UINT; + default: + UNREACHABLE(); + return GetD3D12Format(); + } + default: + ASSERT(HasOneBit(GetFormat().aspects)); + return GetD3D12Format(); + } + } + void Texture::TrackUsageAndTransitionNow(CommandRecordingContext* commandContext, wgpu::TextureUsage usage, const SubresourceRange& range) { @@ -967,7 +987,7 @@ D3D12_TEXTURE_COPY_LOCATION bufferLocation = ComputeBufferLocationForCopyTextureRegion( this, ToBackend(uploadHandle.stagingBuffer)->GetResource(), - info.bufferSize, copySplit.offset, bytesPerRow); + info.bufferSize, copySplit.offset, bytesPerRow, Aspect::Color); D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize);
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h index ef17bf4..d2df6be 100644 --- a/src/dawn_native/d3d12/TextureD3D12.h +++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -48,6 +48,7 @@ DXGI_FORMAT GetD3D12Format() const; ID3D12Resource* GetD3D12Resource() const; + DXGI_FORMAT GetD3D12CopyableSubresourceFormat(Aspect aspect) const; D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(uint32_t mipLevel, uint32_t baseArrayLayer,
diff --git a/src/dawn_native/d3d12/UtilsD3D12.cpp b/src/dawn_native/d3d12/UtilsD3D12.cpp index 6a3b4bc..2837274 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.cpp +++ b/src/dawn_native/d3d12/UtilsD3D12.cpp
@@ -68,7 +68,7 @@ D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, uint32_t level, uint32_t slice, - const Aspect& aspect) { + Aspect aspect) { D3D12_TEXTURE_COPY_LOCATION copyLocation; copyLocation.pResource = texture->GetD3D12Resource(); copyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; @@ -82,12 +82,14 @@ ID3D12Resource* bufferResource, const Extent3D& bufferSize, const uint64_t offset, - const uint32_t rowPitch) { + const uint32_t rowPitch, + Aspect aspect) { D3D12_TEXTURE_COPY_LOCATION bufferLocation; bufferLocation.pResource = bufferResource; bufferLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; bufferLocation.PlacedFootprint.Offset = offset; - bufferLocation.PlacedFootprint.Footprint.Format = texture->GetD3D12Format(); + bufferLocation.PlacedFootprint.Footprint.Format = + texture->GetD3D12CopyableSubresourceFormat(aspect); bufferLocation.PlacedFootprint.Footprint.Width = bufferSize.width; bufferLocation.PlacedFootprint.Footprint.Height = bufferSize.height; bufferLocation.PlacedFootprint.Footprint.Depth = bufferSize.depth; @@ -147,7 +149,8 @@ Texture* texture, uint32_t textureMiplevel, uint32_t textureSlice, - const Aspect& aspect) { + Aspect aspect) { + ASSERT(HasOneBit(aspect)); const D3D12_TEXTURE_COPY_LOCATION textureLocation = ComputeTextureCopyLocationForTexture(texture, textureMiplevel, textureSlice, aspect); @@ -160,7 +163,7 @@ // members in Texture2DCopySplit::CopyInfo. const D3D12_TEXTURE_COPY_LOCATION bufferLocation = ComputeBufferLocationForCopyTextureRegion(texture, bufferResource, info.bufferSize, - offsetBytes, bufferBytesPerRow); + offsetBytes, bufferBytesPerRow, aspect); const D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize(info.bufferOffset, info.copySize); @@ -178,14 +181,14 @@ const uint64_t offsetBytes, const uint32_t bytesPerRow, const uint32_t rowsPerImage, - const Aspect& aspects) { + Aspect aspect) { + ASSERT(HasOneBit(aspect)); // See comments in ComputeTextureCopySplits() for more details. - const TextureCopySplits copySplits = - ComputeTextureCopySplits(textureCopy.origin, copySize, texture->GetFormat(), - offsetBytes, bytesPerRow, rowsPerImage); + const TexelBlockInfo& blockInfo = texture->GetFormat().GetTexelBlockInfo(aspect); + const TextureCopySplits copySplits = ComputeTextureCopySplits( + textureCopy.origin, copySize, blockInfo, offsetBytes, bytesPerRow, rowsPerImage); - const uint64_t bytesPerSlice = - bytesPerRow * (rowsPerImage / texture->GetFormat().blockHeight); + const uint64_t bytesPerSlice = bytesPerRow * (rowsPerImage / blockInfo.blockHeight); // copySplits.copies2D[1] is always calculated for the second copy slice with // extra "bytesPerSlice" copy offset compared with the first copy slice. So @@ -207,7 +210,7 @@ RecordCopyBufferToTextureFromTextureCopySplit( commandContext->GetCommandList(), copySplitPerLayerBase, bufferResource, bufferOffsetForNextSlice, bytesPerRow, texture, textureCopy.mipLevel, - copyTextureLayer, aspects); + copyTextureLayer, aspect); bufferOffsetsForNextSlice[splitIndex] += bytesPerSlice * copySplits.copies2D.size(); }
diff --git a/src/dawn_native/d3d12/UtilsD3D12.h b/src/dawn_native/d3d12/UtilsD3D12.h index ad47570..6109c0f 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.h +++ b/src/dawn_native/d3d12/UtilsD3D12.h
@@ -31,14 +31,15 @@ D3D12_TEXTURE_COPY_LOCATION ComputeTextureCopyLocationForTexture(const Texture* texture, uint32_t level, uint32_t slice, - const Aspect& aspect); + Aspect aspect); D3D12_TEXTURE_COPY_LOCATION ComputeBufferLocationForCopyTextureRegion( const Texture* texture, ID3D12Resource* bufferResource, const Extent3D& bufferSize, const uint64_t offset, - const uint32_t rowPitch); + const uint32_t rowPitch, + Aspect aspect); D3D12_BOX ComputeD3D12BoxFromOffsetAndSize(const Origin3D& offset, const Extent3D& copySize); bool IsTypeless(DXGI_FORMAT format); @@ -51,7 +52,7 @@ Texture* texture, uint32_t textureMiplevel, uint32_t textureSlice, - const Aspect& aspect); + Aspect aspect); void CopyBufferToTextureWithCopySplit(CommandRecordingContext* commandContext, const TextureCopy& textureCopy, @@ -61,7 +62,7 @@ const uint64_t offset, const uint32_t bytesPerRow, const uint32_t rowsPerImage, - const Aspect& aspect); + Aspect aspect); }} // namespace dawn_native::d3d12
diff --git a/src/tests/end2end/DepthStencilCopyTests.cpp b/src/tests/end2end/DepthStencilCopyTests.cpp index 72c9e66..22e3e63 100644 --- a/src/tests/end2end/DepthStencilCopyTests.cpp +++ b/src/tests/end2end/DepthStencilCopyTests.cpp
@@ -320,4 +320,4 @@ } } -DAWN_INSTANTIATE_TEST(DepthStencilCopyTests, MetalBackend(), VulkanBackend()); +DAWN_INSTANTIATE_TEST(DepthStencilCopyTests, D3D12Backend(), MetalBackend(), VulkanBackend());
diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp index 7289757..bca410f 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp
@@ -651,10 +651,12 @@ depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly)); // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms - if (IsMetal() || IsVulkan()) { + if (IsMetal() || IsVulkan() || IsD3D12()) { // Check by copy that the stencil data is 2. - EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(2), depthStencilTexture, 0, 0, 0, 0, - wgpu::TextureAspect::StencilOnly)); + std::vector<uint8_t> expected(kSize * kSize, 2); + EXPECT_LAZY_CLEAR( + 0u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, 0, 0, kSize, kSize, 0, + 0, wgpu::TextureAspect::StencilOnly)); } } @@ -722,10 +724,12 @@ depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly)); // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms - if (IsMetal() || IsVulkan()) { + if (IsMetal() || IsVulkan() || IsD3D12()) { // Check by copy that the stencil data is 0. - EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0, - wgpu::TextureAspect::StencilOnly)); + std::vector<uint8_t> expected(kSize * kSize, 0); + EXPECT_LAZY_CLEAR( + 0u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, 0, 0, kSize, kSize, 0, + 0, wgpu::TextureAspect::StencilOnly)); } } } @@ -734,7 +738,7 @@ // Lazy clear of the stencil aspect via copy should not touch depth. TEST_P(TextureZeroInitTest, IndependentDepthStencilCopyAfterDiscard) { // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms - DAWN_SKIP_TEST_IF(!(IsMetal() || IsVulkan())); + DAWN_SKIP_TEST_IF(!(IsMetal() || IsVulkan() || IsD3D12())); // TODO(enga): Figure out why this fails on Metal Intel. DAWN_SKIP_TEST_IF(IsMetal() && IsIntel()); @@ -767,8 +771,9 @@ depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly)); // Check by copy that the stencil data is lazily cleared to 0. - EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_EQ(uint8_t(0), depthStencilTexture, 0, 0, 0, 0, - wgpu::TextureAspect::StencilOnly)); + std::vector<uint8_t> expected(kSize * kSize, 0); + EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, 0, 0, kSize, + kSize, 0, 0, wgpu::TextureAspect::StencilOnly)); // Everything is initialized now EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,