diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index a483b4285c..8d0056adf6 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -178,15 +178,15 @@ namespace dawn_native { namespace d3d12 { bufferCopy.offset = 0; bufferCopy.bytesPerRow = bytesPerRow; bufferCopy.rowsPerImage = rowsPerImage; - Copy2DTextureToBufferWithCopySplit(recordingContext->GetCommandList(), srcCopy, - bufferCopy, srcTexture, tempBuffer.Get(), copySize); + RecordCopyTextureToBuffer(recordingContext->GetCommandList(), srcCopy, bufferCopy, + srcTexture, tempBuffer.Get(), copySize); // Copy from tempBuffer into destination texture tempBuffer->TrackUsageAndTransitionNow(recordingContext, wgpu::BufferUsage::CopySrc); Texture* dstTexture = ToBackend(dstCopy.texture).Get(); - CopyBufferTo2DTextureWithCopySplit(recordingContext, dstCopy, - tempBuffer->GetD3D12Resource(), 0, bytesPerRow, - rowsPerImage, copySize, dstTexture, dstCopy.aspect); + RecordCopyBufferToTexture(recordingContext, dstCopy, tempBuffer->GetD3D12Resource(), 0, + bytesPerRow, rowsPerImage, copySize, dstTexture, + dstCopy.aspect); // Save tempBuffer into recordingContext recordingContext->AddToTempBuffers(std::move(tempBuffer)); @@ -756,22 +756,10 @@ namespace dawn_native { namespace d3d12 { texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst, subresources); - // Record the CopyTextureRegion commands for 3D textures. Multiple depths of 3D - // textures can be copied in one shot and copySplits are not needed. - if (texture->GetDimension() == wgpu::TextureDimension::e3D) { - CopyBufferTo3DTexture(commandContext, copy->destination, + RecordCopyBufferToTexture(commandContext, copy->destination, buffer->GetD3D12Resource(), copy->source.offset, copy->source.bytesPerRow, copy->source.rowsPerImage, copy->copySize, texture, subresources.aspects); - } else { - // Compute the copySplits and record the CopyTextureRegion commands for 2D - // textures. - CopyBufferTo2DTextureWithCopySplit( - commandContext, copy->destination, buffer->GetD3D12Resource(), - copy->source.offset, copy->source.bytesPerRow, - copy->source.rowsPerImage, copy->copySize, texture, - subresources.aspects); - } break; } @@ -793,14 +781,8 @@ namespace dawn_native { namespace d3d12 { subresources); buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::CopyDst); - if (texture->GetDimension() == wgpu::TextureDimension::e3D) { - Copy3DTextureToBuffer(commandList, copy->source, copy->destination, texture, + RecordCopyTextureToBuffer(commandList, copy->source, copy->destination, texture, buffer, copy->copySize); - } else { - Copy2DTextureToBufferWithCopySplit(commandList, copy->source, - copy->destination, texture, buffer, - copy->copySize); - } break; } diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 2c09181ccb..fc56302365 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -405,7 +405,7 @@ namespace dawn_native { namespace d3d12 { CommandRecordingContext* commandContext; DAWN_TRY_ASSIGN(commandContext, GetPendingCommandContext()); Texture* texture = ToBackend(dst->texture.Get()); - ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D); + ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D); SubresourceRange range = GetSubresourcesAffectedByCopy(*dst, copySizePixels); @@ -417,10 +417,9 @@ namespace dawn_native { namespace d3d12 { texture->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopyDst, range); - // compute the copySplits and record the CopyTextureRegion commands - CopyBufferTo2DTextureWithCopySplit(commandContext, *dst, ToBackend(source)->GetResource(), - src.offset, src.bytesPerRow, src.rowsPerImage, - copySizePixels, texture, range.aspects); + RecordCopyBufferToTexture(commandContext, *dst, ToBackend(source)->GetResource(), + src.offset, src.bytesPerRow, src.rowsPerImage, copySizePixels, + texture, range.aspects); return {}; } diff --git a/src/dawn_native/d3d12/UtilsD3D12.cpp b/src/dawn_native/d3d12/UtilsD3D12.cpp index 4aea0ffd96..b190210078 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.cpp +++ b/src/dawn_native/d3d12/UtilsD3D12.cpp @@ -237,6 +237,29 @@ namespace dawn_native { namespace d3d12 { bytesPerRow, texture, textureCopy.mipLevel, textureCopy.origin.z, aspect); } + void RecordCopyBufferToTexture(CommandRecordingContext* commandContext, + const TextureCopy& textureCopy, + ID3D12Resource* bufferResource, + const uint64_t offset, + const uint32_t bytesPerRow, + const uint32_t rowsPerImage, + const Extent3D& copySize, + Texture* texture, + Aspect aspect) { + // Record the CopyTextureRegion commands for 3D textures. Multiple depths of 3D + // textures can be copied in one shot and copySplits are not needed. + if (texture->GetDimension() == wgpu::TextureDimension::e3D) { + CopyBufferTo3DTexture(commandContext, textureCopy, bufferResource, offset, bytesPerRow, + rowsPerImage, copySize, texture, aspect); + } else { + // Compute the copySplits and record the CopyTextureRegion commands for 2D + // textures. + CopyBufferTo2DTextureWithCopySplit(commandContext, textureCopy, bufferResource, offset, + bytesPerRow, rowsPerImage, copySize, texture, + aspect); + } + } + void RecordCopyTextureToBufferFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, const Texture2DCopySplit& baseCopySplit, Buffer* buffer, @@ -331,4 +354,18 @@ namespace dawn_native { namespace d3d12 { textureCopy.mipLevel, textureCopy.origin.z, textureCopy.aspect); } + void RecordCopyTextureToBuffer(ID3D12GraphicsCommandList* commandList, + const TextureCopy& textureCopy, + const BufferCopy& bufferCopy, + Texture* texture, + Buffer* buffer, + const Extent3D& copySize) { + if (texture->GetDimension() == wgpu::TextureDimension::e3D) { + Copy3DTextureToBuffer(commandList, textureCopy, bufferCopy, texture, buffer, copySize); + } else { + Copy2DTextureToBufferWithCopySplit(commandList, textureCopy, bufferCopy, texture, + buffer, copySize); + } + } + }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/UtilsD3D12.h b/src/dawn_native/d3d12/UtilsD3D12.h index fd9be666b0..719a19a854 100644 --- a/src/dawn_native/d3d12/UtilsD3D12.h +++ b/src/dawn_native/d3d12/UtilsD3D12.h @@ -54,25 +54,15 @@ namespace dawn_native { namespace d3d12 { uint32_t textureSlice, Aspect aspect); - void CopyBufferTo2DTextureWithCopySplit(CommandRecordingContext* commandContext, - const TextureCopy& textureCopy, - ID3D12Resource* bufferResource, - const uint64_t offset, - const uint32_t bytesPerRow, - const uint32_t rowsPerImage, - const Extent3D& copySize, - Texture* texture, - Aspect aspect); - - void CopyBufferTo3DTexture(CommandRecordingContext* commandContext, - const TextureCopy& textureCopy, - ID3D12Resource* bufferResource, - const uint64_t offset, - const uint32_t bytesPerRow, - const uint32_t rowsPerImage, - const Extent3D& copySize, - Texture* texture, - Aspect aspect); + void RecordCopyBufferToTexture(CommandRecordingContext* commandContext, + const TextureCopy& textureCopy, + ID3D12Resource* bufferResource, + const uint64_t offset, + const uint32_t bytesPerRow, + const uint32_t rowsPerImage, + const Extent3D& copySize, + Texture* texture, + Aspect aspect); void RecordCopyTextureToBufferFromTextureCopySplit(ID3D12GraphicsCommandList* commandList, const Texture2DCopySplit& baseCopySplit, @@ -84,19 +74,12 @@ namespace dawn_native { namespace d3d12 { uint32_t textureSlice, Aspect aspect); - void Copy2DTextureToBufferWithCopySplit(ID3D12GraphicsCommandList* commandList, - const TextureCopy& textureCopy, - const BufferCopy& bufferCopy, - Texture* texture, - Buffer* buffer, - const Extent3D& copySize); - - void Copy3DTextureToBuffer(ID3D12GraphicsCommandList* commandList, - const TextureCopy& textureCopy, - const BufferCopy& bufferCopy, - Texture* texture, - Buffer* buffer, - const Extent3D& copySize); + void RecordCopyTextureToBuffer(ID3D12GraphicsCommandList* commandList, + const TextureCopy& textureCopy, + const BufferCopy& bufferCopy, + Texture* texture, + Buffer* buffer, + const Extent3D& copySize); }} // namespace dawn_native::d3d12 diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp index 92230d641b..1903652c9d 100644 --- a/src/tests/end2end/CopyTests.cpp +++ b/src/tests/end2end/CopyTests.cpp @@ -130,14 +130,15 @@ class CopyTests_T2B : public CopyTests { protected: void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec, - const wgpu::Extent3D& copySize) { + const wgpu::Extent3D& copySize, + wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D) { // TODO(jiawei.shao@intel.com): support testing arbitrary formats ASSERT_EQ(kDefaultFormat, textureSpec.format); const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(textureSpec.format); // Create a texture that is `width` x `height` with (`level` + 1) mip levels. wgpu::TextureDescriptor descriptor; - descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.dimension = dimension; descriptor.size = textureSpec.textureSize; descriptor.sampleCount = 1; descriptor.format = textureSpec.format; @@ -186,11 +187,18 @@ class CopyTests_T2B : public CopyTests { uint64_t bufferOffset = bufferSpec.offset; - const wgpu::Extent3D copySizePerSlice = {copySize.width, copySize.height, 1}; + uint32_t copyLayer = copySize.depthOrArrayLayers; + uint32_t copyDepth = 1; + if (dimension == wgpu::TextureDimension::e3D) { + copyLayer = 1; + copyDepth = copySize.depthOrArrayLayers; + } + + const wgpu::Extent3D copySizePerLayer = {copySize.width, copySize.height, copyDepth}; // Texels in single slice. const uint32_t texelCountInCopyRegion = utils::GetTexelCountInCopyRegion( - bufferSpec.bytesPerRow, bufferSpec.rowsPerImage, copySizePerSlice, textureSpec.format); - const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depthOrArrayLayers; + bufferSpec.bytesPerRow, bufferSpec.rowsPerImage, copySizePerLayer, textureSpec.format); + const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copyLayer; std::vector expected(texelCountInCopyRegion); for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { // Pack the data used to create the upload buffer in the specified copy region to have @@ -203,7 +211,7 @@ class CopyTests_T2B : public CopyTests { PackTextureData(bytesPerTexel, textureArrayData.data() + expectedTexelArrayDataStartIndex, - copySize.width, copySize.height, 1, copyLayout.bytesPerRow, + copySize.width, copySize.height, copyDepth, copyLayout.bytesPerRow, expected.data(), bufferSpec.bytesPerRow); EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast(expected.data()), buffer, @@ -314,12 +322,13 @@ class CopyTests_T2T : public CopyTests { void DoTest(const TextureSpec& srcSpec, const TextureSpec& dstSpec, const wgpu::Extent3D& copySize, - bool copyWithinSameTexture = false) { + bool copyWithinSameTexture = false, + wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D) { ASSERT_EQ(srcSpec.format, dstSpec.format); const wgpu::TextureFormat format = srcSpec.format; wgpu::TextureDescriptor srcDescriptor; - srcDescriptor.dimension = wgpu::TextureDimension::e2D; + srcDescriptor.dimension = dimension; srcDescriptor.size = srcSpec.textureSize; srcDescriptor.sampleCount = 1; srcDescriptor.format = format; @@ -332,7 +341,7 @@ class CopyTests_T2T : public CopyTests { dstTexture = srcTexture; } else { wgpu::TextureDescriptor dstDescriptor; - dstDescriptor.dimension = wgpu::TextureDimension::e2D; + dstDescriptor.dimension = dimension; dstDescriptor.size = dstSpec.textureSize; dstDescriptor.sampleCount = 1; dstDescriptor.format = format; @@ -393,14 +402,21 @@ class CopyTests_T2T : public CopyTests { // Validate if the data in outputBuffer is what we expected, including the untouched data // outside of the copy. { + uint32_t copyLayer = copySize.depthOrArrayLayers; + uint32_t copyDepth = 1; + if (dimension == wgpu::TextureDimension::e3D) { + copyLayer = 1; + copyDepth = copySize.depthOrArrayLayers; + } + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); const uint64_t validDataSizePerDstTextureLayer = utils::RequiredBytesInCopy( dstDataCopyLayout.bytesPerRow, dstDataCopyLayout.mipSize.height, - dstDataCopyLayout.mipSize.width, dstDataCopyLayout.mipSize.height, 1, + dstDataCopyLayout.mipSize.width, dstDataCopyLayout.mipSize.height, copyDepth, bytesPerTexel); std::vector expectedDstDataPerSlice(validDataSizePerDstTextureLayer); - for (uint32_t slice = 0; slice < copySize.depthOrArrayLayers; ++slice) { + for (uint32_t slice = 0; slice < copyLayer; ++slice) { // For each source texture array slice involved in the copy, emulate the T2T copy // on the CPU side by "copying" the copy data from the "source texture" // (srcTextureCopyData) to the "destination texture" (expectedDstDataPerSlice). @@ -419,10 +435,10 @@ class CopyTests_T2T : public CopyTests { dstSpec.copyOrigin.y * dstDataCopyLayout.mipSize.width) * bytesPerTexel; // Do the T2T "copy" on the CPU side to get the expected texel value at the - PackTextureData(bytesPerTexel, &srcTextureCopyData[srcTexelDataOffset], - copySize.width, copySize.height, 1, srcDataCopyLayout.bytesPerRow, - &expectedDstDataPerSlice[expectedDstDataOffset], - dstDataCopyLayout.bytesPerRow); + PackTextureData( + bytesPerTexel, &srcTextureCopyData[srcTexelDataOffset], copySize.width, + copySize.height, copyDepth, srcDataCopyLayout.bytesPerRow, + &expectedDstDataPerSlice[expectedDstDataOffset], dstDataCopyLayout.bytesPerRow); // Compare the content of the destination texture at the (dstSpec.copyOrigin.z + // slice)-th layer to its expected data after the copy (the outputBuffer contains @@ -820,7 +836,7 @@ TEST_P(CopyTests_T2B, StrideSpecialCases) { } // Test that copying whole texture 2D array layers in one texture-to-buffer-copy works. -TEST_P(CopyTests_T2B, Texture2DArrayRegion) { +TEST_P(CopyTests_T2B, Texture2DArrayFull) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; @@ -930,7 +946,24 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetEvenRowsPerImage) { DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); } -// TODO(yunchao.he@intel.com): add T2B tests for 3D textures, like entire texture copy, RowPitch, +// Test that copying whole 3D texture in one texture-to-buffer-copy works. +TEST_P(CopyTests_T2B, Texture3DFull) { + // TODO(yunchao.he@intel.com): implement 3D texture copy on Vulkan, Metal, OpenGL and OpenGLES + // backend. + DAWN_SKIP_TEST_IF(IsVulkan() || IsMetal() || IsOpenGL() || IsOpenGLES()); + + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kDepth = 6u; + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, kDepth}; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kDepth), {kWidth, kHeight, kDepth}, + wgpu::TextureDimension::e3D); +} + +// TODO(yunchao.he@intel.com): add T2B tests for 3D textures, like RowPitch, // RowsPerImage, buffer offset, partial depth range, non-zero level, etc. DAWN_INSTANTIATE_TEST(CopyTests_T2B, @@ -1279,7 +1312,7 @@ TEST_P(CopyTests_B2T, StrideSpecialCases) { } // Test that copying whole texture 2D array layers in one texture-to-buffer-copy works. -TEST_P(CopyTests_B2T, Texture2DArrayRegion) { +TEST_P(CopyTests_B2T, Texture2DArrayFull) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; @@ -1370,20 +1403,20 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetEvenRowsPerImage) { DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); } -// Test that copying whole texture 3D in one texture-to-buffer-copy works. -TEST_P(CopyTests_B2T, Texture3DRegion) { +// Test that copying whole texture 3D in one buffer-to-texture-copy works. +TEST_P(CopyTests_B2T, Texture3DFull) { // TODO(yunchao.he@intel.com): implement 3D texture copy on Vulkan, Metal, OpenGL and OpenGLES // backend. DAWN_SKIP_TEST_IF(IsVulkan() || IsMetal() || IsOpenGL() || IsOpenGLES()); constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; - constexpr uint32_t kLayers = 6u; + constexpr uint32_t kDepth = 6u; TextureSpec textureSpec; - textureSpec.textureSize = {kWidth, kHeight, kLayers}; + textureSpec.textureSize = {kWidth, kHeight, kDepth}; - DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kLayers), {kWidth, kHeight, kLayers}, + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kDepth), {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D); } @@ -1434,7 +1467,7 @@ TEST_P(CopyTests_T2T, TextureRegion) { } // Test copying the whole 2D array texture. -TEST_P(CopyTests_T2T, Texture2DArray) { +TEST_P(CopyTests_T2T, Texture2DArrayFull) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; @@ -1700,7 +1733,23 @@ TEST_P(CopyTests_T2T, CopyFromNonZeroMipLevelWithTexelBlockSizeLessThan4Bytes) { } } -// TODO(yunchao.he@intel.com): add T2T tests for 3D textures, like entire texture copy, RowPitch, +// Test that copying whole 3D texture in one texture-to-texture-copy works. +TEST_P(CopyTests_T2T, Texture3DFull) { + // TODO(yunchao.he@intel.com): implement 3D texture copy on Vulkan, Metal, OpenGL and OpenGLES + // backend. + DAWN_SKIP_TEST_IF(IsVulkan() || IsMetal() || IsOpenGL() || IsOpenGLES()); + + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kDepth = 6u; + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, kDepth}; + + DoTest(textureSpec, textureSpec, {kWidth, kHeight, kDepth}, false, wgpu::TextureDimension::e3D); +} + +// TODO(yunchao.he@intel.com): add T2T tests for 3D textures, like RowPitch, // RowsPerImage, buffer offset, partial depth range, non-zero level, etc. DAWN_INSTANTIATE_TEST(