From a3636ed8883d3b3e953d2099236497bb8d5f8a9e Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Thu, 28 May 2020 01:01:32 +0000 Subject: [PATCH] Support multiple array layers in one texture-to-texture copy command This patch adds the supports of copying multiple array layers of a 2D array texture in one texture-to-texture call. Note that in D3D12 and Metal it is implemented by copying each array layer in a for-loop. Note that we need extra validations when the source and destination texture are the same one in a texture-to-texture copy. This CL does not include these validations and we will add them in another one. BUG=dawn:18 TEST=dawn_unittests, dawn_end2end_tests Change-Id: I1239543e5692e140474b3c1de0b3579be449e283 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22140 Commit-Queue: Jiawei Shao Reviewed-by: Austin Eng --- src/dawn_native/CommandEncoder.cpp | 19 +-- src/dawn_native/d3d12/CommandBufferD3D12.cpp | 40 +++--- src/dawn_native/metal/CommandBufferMTL.mm | 42 ++++--- src/dawn_native/opengl/CommandBufferGL.cpp | 10 +- src/dawn_native/vulkan/CommandBufferVk.cpp | 20 +-- src/tests/end2end/CopyTests.cpp | 116 ++++++++++-------- .../CopyCommandsValidationTests.cpp | 34 +++-- 7 files changed, 167 insertions(+), 114 deletions(-) diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp index d2d43024b4..79db419408 100644 --- a/src/dawn_native/CommandEncoder.cpp +++ b/src/dawn_native/CommandEncoder.cpp @@ -37,6 +37,8 @@ namespace dawn_native { namespace { + // TODO(jiawei.shao@intel.com): add validations on the texture-to-texture copies within the + // same texture. MaybeError ValidateCopySizeFitsInTexture(const TextureCopyView& textureCopy, const Extent3D& copySize) { const TextureBase* texture = textureCopy.texture; @@ -44,7 +46,9 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("Copy mipLevel out of range"); } - if (textureCopy.arrayLayer >= texture->GetArrayLayers()) { + if (static_cast(textureCopy.arrayLayer) + + static_cast(copySize.depth) > + static_cast(texture->GetArrayLayers())) { return DAWN_VALIDATION_ERROR("Copy arrayLayer out of range"); } @@ -52,17 +56,18 @@ namespace dawn_native { // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid // overflows. - if (uint64_t(textureCopy.origin.x) + uint64_t(copySize.width) > + if (static_cast(textureCopy.origin.x) + + static_cast(copySize.width) > static_cast(extent.width) || - uint64_t(textureCopy.origin.y) + uint64_t(copySize.height) > + static_cast(textureCopy.origin.y) + + static_cast(copySize.height) > static_cast(extent.height)) { return DAWN_VALIDATION_ERROR("Copy would touch outside of the texture"); } - // TODO(cwallez@chromium.org): Check the depth bound differently for 2D arrays and 3D - // textures - if (textureCopy.origin.z != 0 || copySize.depth > 1) { - return DAWN_VALIDATION_ERROR("No support for z != 0 and depth > 1 for now"); + // TODO(cwallez@chromium.org): Check the depth bound differently for 3D textures. + if (textureCopy.origin.z != 0) { + return DAWN_VALIDATION_ERROR("No support for z != 0 for now"); } return {}; diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index ebbef1cc7b..ae85ef4486 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -660,15 +660,17 @@ namespace dawn_native { namespace d3d12 { Texture* destination = ToBackend(copy->destination.texture.Get()); source->EnsureSubresourceContentInitialized( - commandContext, copy->source.mipLevel, 1, copy->source.arrayLayer, 1); + commandContext, copy->source.mipLevel, 1, copy->source.arrayLayer, + copy->copySize.depth); if (IsCompleteSubresourceCopiedTo(destination, copy->copySize, copy->destination.mipLevel)) { destination->SetIsSubresourceContentInitialized( - true, copy->destination.mipLevel, 1, copy->destination.arrayLayer, 1); + true, copy->destination.mipLevel, 1, copy->destination.arrayLayer, + copy->copySize.depth); } else { destination->EnsureSubresourceContentInitialized( commandContext, copy->destination.mipLevel, 1, - copy->destination.arrayLayer, 1); + copy->destination.arrayLayer, copy->copySize.depth); } source->TrackUsageAndTransitionNow(commandContext, wgpu::TextureUsage::CopySrc); destination->TrackUsageAndTransitionNow(commandContext, @@ -678,21 +680,29 @@ namespace dawn_native { namespace d3d12 { commandList->CopyResource(destination->GetD3D12Resource(), source->GetD3D12Resource()); } else { - D3D12_TEXTURE_COPY_LOCATION srcLocation = - ComputeTextureCopyLocationForTexture(source, copy->source.mipLevel, - copy->source.arrayLayer); + // TODO(jiawei.shao@intel.com): support copying with 1D and 3D textures. + ASSERT(source->GetDimension() == wgpu::TextureDimension::e2D && + destination->GetDimension() == wgpu::TextureDimension::e2D); + const dawn_native::Extent3D copyExtentOneSlice = { + copy->copySize.width, copy->copySize.height, 1u}; + for (uint32_t slice = 0; slice < copy->copySize.depth; ++slice) { + D3D12_TEXTURE_COPY_LOCATION srcLocation = + ComputeTextureCopyLocationForTexture( + source, copy->source.mipLevel, copy->source.arrayLayer + slice); - D3D12_TEXTURE_COPY_LOCATION dstLocation = - ComputeTextureCopyLocationForTexture(destination, - copy->destination.mipLevel, - copy->destination.arrayLayer); + D3D12_TEXTURE_COPY_LOCATION dstLocation = + ComputeTextureCopyLocationForTexture( + destination, copy->destination.mipLevel, + copy->destination.arrayLayer + slice); - D3D12_BOX sourceRegion = - ComputeD3D12BoxFromOffsetAndSize(copy->source.origin, copy->copySize); + D3D12_BOX sourceRegion = ComputeD3D12BoxFromOffsetAndSize( + copy->source.origin, copyExtentOneSlice); - commandList->CopyTextureRegion( - &dstLocation, copy->destination.origin.x, copy->destination.origin.y, - copy->destination.origin.z, &srcLocation, &sourceRegion); + commandList->CopyTextureRegion(&dstLocation, copy->destination.origin.x, + copy->destination.origin.y, + copy->destination.origin.z, &srcLocation, + &sourceRegion); + } } break; } diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm index f27e7d4b0f..2ed61e3e90 100644 --- a/src/dawn_native/metal/CommandBufferMTL.mm +++ b/src/dawn_native/metal/CommandBufferMTL.mm @@ -325,10 +325,6 @@ namespace dawn_native { namespace metal { return MTLOriginMake(origin.x, origin.y, origin.z); } - MTLSize MakeMTLSize(Extent3D extent) { - return MTLSizeMake(extent.width, extent.height, extent.depth); - } - TextureBufferCopySplit ComputeTextureBufferCopySplit(Origin3D origin, Extent3D copyExtent, Format textureFormat, @@ -445,19 +441,19 @@ namespace dawn_native { namespace metal { void EnsureSourceTextureInitialized(Texture* texture, const Extent3D& size, const TextureCopy& src) { - // TODO(crbug.com/dawn/145): Specify multiple layers based on |size| - texture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer, 1); + texture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer, + size.depth); } void EnsureDestinationTextureInitialized(Texture* texture, const Extent3D& size, const TextureCopy& dst) { - // TODO(crbug.com/dawn/145): Specify multiple layers based on |size| if (IsCompleteSubresourceCopiedTo(texture, size, dst.mipLevel)) { texture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1, dst.arrayLayer, - 1); + size.depth); } else { - texture->EnsureSubresourceContentInitialized(dst.mipLevel, 1, dst.arrayLayer, 1); + texture->EnsureSubresourceContentInitialized(dst.mipLevel, 1, dst.arrayLayer, + size.depth); } } @@ -809,16 +805,24 @@ namespace dawn_native { namespace metal { EnsureDestinationTextureInitialized(dstTexture, copy->copySize, copy->destination); - [commandContext->EnsureBlit() - copyFromTexture:srcTexture->GetMTLTexture() - sourceSlice:copy->source.arrayLayer - sourceLevel:copy->source.mipLevel - sourceOrigin:MakeMTLOrigin(copy->source.origin) - sourceSize:MakeMTLSize(copy->copySize) - toTexture:dstTexture->GetMTLTexture() - destinationSlice:copy->destination.arrayLayer - destinationLevel:copy->destination.mipLevel - destinationOrigin:MakeMTLOrigin(copy->destination.origin)]; + // TODO(jiawei.shao@intel.com): support copies with 1D and 3D textures. + ASSERT(srcTexture->GetDimension() == wgpu::TextureDimension::e2D && + dstTexture->GetDimension() == wgpu::TextureDimension::e2D); + const MTLSize mtlSizeOneLayer = + MTLSizeMake(copy->copySize.width, copy->copySize.height, 1); + for (uint32_t slice = 0; slice < copy->copySize.depth; ++slice) { + [commandContext->EnsureBlit() + copyFromTexture:srcTexture->GetMTLTexture() + sourceSlice:copy->source.arrayLayer + slice + sourceLevel:copy->source.mipLevel + sourceOrigin:MakeMTLOrigin(copy->source.origin) + sourceSize:mtlSizeOneLayer + toTexture:dstTexture->GetMTLTexture() + destinationSlice:copy->destination.arrayLayer + slice + destinationLevel:copy->destination.mipLevel + destinationOrigin:MakeMTLOrigin(copy->destination.origin)]; + } + break; } diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp index 9ee4e08b2e..b8d6d2612d 100644 --- a/src/dawn_native/opengl/CommandBufferGL.cpp +++ b/src/dawn_native/opengl/CommandBufferGL.cpp @@ -623,17 +623,17 @@ namespace dawn_native { namespace opengl { srcTexture->EnsureSubresourceContentInitialized(src.mipLevel, 1, src.arrayLayer, 1); if (IsCompleteSubresourceCopiedTo(dstTexture, copySize, dst.mipLevel)) { - dstTexture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1, - dst.arrayLayer, 1); + dstTexture->SetIsSubresourceContentInitialized( + true, dst.mipLevel, 1, dst.arrayLayer, copy->copySize.depth); } else { - dstTexture->EnsureSubresourceContentInitialized(dst.mipLevel, 1, - dst.arrayLayer, 1); + dstTexture->EnsureSubresourceContentInitialized( + dst.mipLevel, 1, dst.arrayLayer, copy->copySize.depth); } gl.CopyImageSubData(srcTexture->GetHandle(), srcTexture->GetGLTarget(), src.mipLevel, src.origin.x, src.origin.y, src.arrayLayer, dstTexture->GetHandle(), dstTexture->GetGLTarget(), dst.mipLevel, dst.origin.x, dst.origin.y, dst.arrayLayer, - copySize.width, copySize.height, 1); + copySize.width, copySize.height, copy->copySize.depth); break; } diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp index e5c2106db8..6fad7c6953 100644 --- a/src/dawn_native/vulkan/CommandBufferVk.cpp +++ b/src/dawn_native/vulkan/CommandBufferVk.cpp @@ -64,10 +64,13 @@ namespace dawn_native { namespace vulkan { VkImageCopy region; + // TODO(jiawei.shao@intel.com): support 1D and 3D textures + ASSERT(srcTexture->GetDimension() == wgpu::TextureDimension::e2D && + dstTexture->GetDimension() == wgpu::TextureDimension::e2D); region.srcSubresource.aspectMask = srcTexture->GetVkAspectMask(); region.srcSubresource.mipLevel = srcCopy.mipLevel; region.srcSubresource.baseArrayLayer = srcCopy.arrayLayer; - region.srcSubresource.layerCount = 1; + region.srcSubresource.layerCount = copySize.depth; region.srcOffset.x = srcCopy.origin.x; region.srcOffset.y = srcCopy.origin.y; @@ -76,7 +79,7 @@ namespace dawn_native { namespace vulkan { region.dstSubresource.aspectMask = dstTexture->GetVkAspectMask(); region.dstSubresource.mipLevel = dstCopy.mipLevel; region.dstSubresource.baseArrayLayer = dstCopy.arrayLayer; - region.dstSubresource.layerCount = 1; + region.dstSubresource.layerCount = copySize.depth; region.dstOffset.x = dstCopy.origin.x; region.dstOffset.y = dstCopy.origin.y; @@ -86,7 +89,7 @@ namespace dawn_native { namespace vulkan { Extent3D imageExtent = ComputeTextureCopyExtent(dstCopy, copySize); region.extent.width = imageExtent.width; region.extent.height = imageExtent.height; - region.extent.depth = imageExtent.depth; + region.extent.depth = 1; return region; } @@ -495,20 +498,21 @@ namespace dawn_native { namespace vulkan { if (IsCompleteSubresourceCopiedTo(dst.texture.Get(), copy->copySize, dst.mipLevel)) { // Since destination texture has been overwritten, it has been "initialized" - dst.texture->SetIsSubresourceContentInitialized(true, dst.mipLevel, 1, - dst.arrayLayer, 1); + dst.texture->SetIsSubresourceContentInitialized( + true, dst.mipLevel, 1, dst.arrayLayer, copy->copySize.depth); } else { ToBackend(dst.texture) ->EnsureSubresourceContentInitialized(recordingContext, dst.mipLevel, 1, - dst.arrayLayer, 1); + dst.arrayLayer, + copy->copySize.depth); } ToBackend(src.texture) ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopySrc, - src.mipLevel, 1, src.arrayLayer, 1); + src.mipLevel, 1, src.arrayLayer, copy->copySize.depth); ToBackend(dst.texture) ->TransitionUsageNow(recordingContext, wgpu::TextureUsage::CopyDst, - dst.mipLevel, 1, dst.arrayLayer, 1); + dst.mipLevel, 1, dst.arrayLayer, copy->copySize.depth); // In some situations we cannot do texture-to-texture copies with vkCmdCopyImage // because as Vulkan SPEC always validates image copies with the virtual size of diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp index f00df82ddf..f9d768d4e3 100644 --- a/src/tests/end2end/CopyTests.cpp +++ b/src/tests/end2end/CopyTests.cpp @@ -281,11 +281,13 @@ class CopyTests_T2T : public CopyTests { uint32_t y; uint32_t level; uint32_t arraySize = 1u; + uint32_t baseArrayLayer = 0u; }; struct CopySize { uint32_t width; uint32_t height; + uint32_t arrayLayerCount = 1u; }; protected: @@ -324,77 +326,56 @@ class CopyTests_T2T : public CopyTests { uint32_t texelsPerRow = bytesPerRow / kBytesPerTexel; uint32_t texelCountPerLayer = texelsPerRow * (height - 1) + width; - std::vector> textureArrayData(srcSpec.arraySize); - for (uint32_t slice = 0; slice < srcSpec.arraySize; ++slice) { - textureArrayData[slice].resize(texelCountPerLayer); + // TODO(jiawei.shao@intel.com): support copying into multiple contiguous array layers in one + // copyBufferToTexture() call. + std::vector> textureArrayCopyData(copy.arrayLayerCount); + for (uint32_t slice = 0; slice < copy.arrayLayerCount; ++slice) { + textureArrayCopyData[slice].resize(texelCountPerLayer); FillTextureData(width, height, bytesPerRow / kBytesPerTexel, slice, - textureArrayData[slice].data()); + textureArrayCopyData[slice].data()); wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( - device, textureArrayData[slice].data(), - static_cast(sizeof(RGBA8) * textureArrayData[slice].size()), + device, textureArrayCopyData[slice].data(), + static_cast(sizeof(RGBA8) * textureArrayCopyData[slice].size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(uploadBuffer, 0, bytesPerRow, 0); - wgpu::TextureCopyView textureCopyView = - utils::CreateTextureCopyView(srcTexture, srcSpec.level, slice, {0, 0, 0}); + wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView( + srcTexture, srcSpec.level, srcSpec.baseArrayLayer + slice, {0, 0, 0}); wgpu::Extent3D bufferCopySize = {width, height, 1}; encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &bufferCopySize); } - // Create an upload buffer filled with empty data and use it to populate the `level` mip of - // the texture. Note: Prepopulating the texture 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 - { - uint32_t dstWidth = dstSpec.width >> dstSpec.level; - uint32_t dstHeight = dstSpec.height >> dstSpec.level; - uint32_t dstRowPitch = Align(kBytesPerTexel * dstWidth, kTextureBytesPerRowAlignment); - uint32_t dstTexelsPerRow = dstRowPitch / kBytesPerTexel; - uint32_t dstTexelCount = dstTexelsPerRow * (dstHeight - 1) + dstWidth; - - std::vector emptyData(dstTexelCount); - wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( - device, emptyData.data(), static_cast(sizeof(RGBA8) * emptyData.size()), - wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, dstRowPitch, 0); - wgpu::TextureCopyView textureCopyView = - utils::CreateTextureCopyView(dstTexture, dstSpec.level, 0, {0, 0, 0}); - wgpu::Extent3D dstCopySize = {dstWidth, dstHeight, 1}; - encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &dstCopySize); - } - // Perform the texture to texture copy - for (uint32_t slice = 0; slice < srcSpec.arraySize; ++slice) { - wgpu::TextureCopyView srcTextureCopyView = utils::CreateTextureCopyView( - srcTexture, srcSpec.level, slice, {srcSpec.x, srcSpec.y, 0}); - wgpu::TextureCopyView dstTextureCopyView = utils::CreateTextureCopyView( - dstTexture, dstSpec.level, slice, {dstSpec.x, dstSpec.y, 0}); - wgpu::Extent3D copySize = {copy.width, copy.height, 1}; - encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, ©Size); - } + wgpu::TextureCopyView srcTextureCopyView = utils::CreateTextureCopyView( + srcTexture, srcSpec.level, srcSpec.baseArrayLayer, {srcSpec.x, srcSpec.y, 0}); + wgpu::TextureCopyView dstTextureCopyView = utils::CreateTextureCopyView( + dstTexture, dstSpec.level, dstSpec.baseArrayLayer, {dstSpec.x, dstSpec.y, 0}); + wgpu::Extent3D copySize = {copy.width, copy.height, copy.arrayLayerCount}; + encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, ©Size); wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); std::vector expected(bytesPerRow / kBytesPerTexel * (copy.height - 1) + copy.width); - for (uint32_t slice = 0; slice < srcSpec.arraySize; ++slice) { + for (uint32_t slice = 0; slice < copy.arrayLayerCount; ++slice) { std::fill(expected.begin(), expected.end(), RGBA8()); - PackTextureData( - &textureArrayData[slice][srcSpec.x + srcSpec.y * (bytesPerRow / kBytesPerTexel)], - copy.width, copy.height, texelsPerRow, expected.data(), copy.width); + PackTextureData(&textureArrayCopyData[slice][srcSpec.x + srcSpec.y * (bytesPerRow / + kBytesPerTexel)], + copy.width, copy.height, texelsPerRow, expected.data(), copy.width); EXPECT_TEXTURE_RGBA8_EQ(expected.data(), dstTexture, dstSpec.x, dstSpec.y, copy.width, - copy.height, dstSpec.level, slice) + copy.height, dstSpec.level, dstSpec.baseArrayLayer + slice) << "Texture to Texture copy failed copying region [(" << srcSpec.x << ", " << srcSpec.y << "), (" << srcSpec.x + copy.width << ", " << srcSpec.y + copy.height << ")) from " << srcSpec.width << " x " << srcSpec.height - << " texture at mip level " << srcSpec.level << " layer " << slice << " to [(" - << dstSpec.x << ", " << dstSpec.y << "), (" << dstSpec.x + copy.width << ", " - << dstSpec.y + copy.height << ")) region of " << dstSpec.width << " x " - << dstSpec.height << " texture at mip level " << dstSpec.level << std::endl; + << " texture at mip level " << srcSpec.level << " layer " + << srcSpec.baseArrayLayer + slice << " to [(" << dstSpec.x << ", " << dstSpec.y + << "), (" << dstSpec.x + copy.width << ", " << dstSpec.y + copy.height + << ")) region of " << dstSpec.width << " x " << dstSpec.height + << " texture at mip level " << dstSpec.level << " layer " + << dstSpec.baseArrayLayer + slice << std::endl; } } }; @@ -723,26 +704,61 @@ TEST_P(CopyTests_T2T, TextureRegion) { } } +// Test copying the whole 2D array texture. TEST_P(CopyTests_T2T, Texture2DArray) { + // TODO(jiawei.shao@intel.com): investigate why this test fails with swiftshader. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; DoTest({kWidth, kHeight, 0, 0, 0, kLayers}, {kWidth, kHeight, 0, 0, 0, kLayers}, - {kWidth, kHeight}); + {kWidth, kHeight, kLayers}); } +// Test copying a subresource region of the 2D array texture. TEST_P(CopyTests_T2T, Texture2DArrayRegion) { + // TODO(jiawei.shao@intel.com): investigate why this test fails with swiftshader. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; for (unsigned int w : {64, 128, 256}) { for (unsigned int h : {16, 32, 48}) { DoTest({kWidth, kHeight, 0, 0, 0, kLayers}, {kWidth, kHeight, 0, 0, 0, kLayers}, - {w, h}); + {w, h, kLayers}); } } } +// Test copying one slice of a 2D array texture. +TEST_P(CopyTests_T2T, Texture2DArrayCopyOneSlice) { + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kLayers = 6u; + constexpr uint32_t kSrcBaseLayer = 1u; + constexpr uint32_t kDstBaseLayer = 3u; + DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, + {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, {kWidth, kHeight, 1u}); +} + +// Test copying multiple contiguous slices of a 2D array texture. +TEST_P(CopyTests_T2T, Texture2DArrayCopyMultipleSlices) { + // TODO(jiawei.shao@intel.com): investigate why this test fails with swiftshader. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kLayers = 6u; + constexpr uint32_t kSrcBaseLayer = 0u; + constexpr uint32_t kDstBaseLayer = 3u; + constexpr uint32_t kCopyArrayLayerCount = 3u; + DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, + {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, + {kWidth, kHeight, kCopyArrayLayerCount}); +} + TEST_P(CopyTests_T2T, TextureMip) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp index 4523aee2c5..de1da260a3 100644 --- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp +++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp @@ -990,9 +990,9 @@ class CopyCommandTest_T2T : public CopyCommandTest {}; TEST_F(CopyCommandTest_T2T, Success) { wgpu::Texture source = - Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); + Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); wgpu::Texture destination = - Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); + Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // Different copies, including some that touch the OOB condition { @@ -1019,6 +1019,16 @@ TEST_F(CopyCommandTest_T2T, Success) { // Copy between slices TestT2TCopy(utils::Expectation::Success, source, 0, 1, {0, 0, 0}, destination, 0, 1, {0, 0, 0}, {16, 16, 1}); + + // Copy multiple slices (srcTextureCopyView.arrayLayer + copySize.depth == + // srcTextureCopyView.texture.arrayLayerCount) + TestT2TCopy(utils::Expectation::Success, source, 0, 2, {0, 0, 0}, destination, 0, 0, + {0, 0, 0}, {16, 16, 2}); + + // Copy multiple slices (dstTextureCopyView.arrayLayer + copySize.depth == + // dstTextureCopyView.texture.arrayLayerCount) + TestT2TCopy(utils::Expectation::Success, source, 0, 0, {0, 0, 0}, destination, 0, 2, + {0, 0, 0}, {16, 16, 2}); } // Empty copies are valid @@ -1058,9 +1068,9 @@ TEST_F(CopyCommandTest_T2T, IncorrectUsage) { TEST_F(CopyCommandTest_T2T, OutOfBounds) { wgpu::Texture source = - Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); + Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); wgpu::Texture destination = - Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); + Create2DTexture(16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // OOB on source { @@ -1076,12 +1086,16 @@ TEST_F(CopyCommandTest_T2T, OutOfBounds) { TestT2TCopy(utils::Expectation::Failure, source, 1, 0, {0, 0, 0}, destination, 0, 0, {0, 0, 0}, {9, 9, 1}); + // arrayLayer + depth OOB + TestT2TCopy(utils::Expectation::Failure, source, 0, 3, {0, 0, 0}, destination, 0, 0, + {0, 0, 0}, {16, 16, 2}); + // empty copy on non-existent mip fails TestT2TCopy(utils::Expectation::Failure, source, 6, 0, {0, 0, 0}, destination, 0, 0, {0, 0, 0}, {0, 0, 1}); // empty copy from non-existent slice fails - TestT2TCopy(utils::Expectation::Failure, source, 0, 2, {0, 0, 0}, destination, 0, 0, + TestT2TCopy(utils::Expectation::Failure, source, 0, 4, {0, 0, 0}, destination, 0, 0, {0, 0, 0}, {0, 0, 1}); } @@ -1099,12 +1113,16 @@ TEST_F(CopyCommandTest_T2T, OutOfBounds) { TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 1, 0, {0, 0, 0}, {9, 9, 1}); + // arrayLayer + depth OOB + TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 3, + {0, 0, 0}, {16, 16, 2}); + // empty copy on non-existent mip fails TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 6, 0, {0, 0, 0}, {0, 0, 1}); // empty copy on non-existent slice fails - TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 2, + TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 4, {0, 0, 0}, {0, 0, 1}); } } @@ -1122,10 +1140,6 @@ TEST_F(CopyCommandTest_T2T, 2DTextureDepthConstraints) { // Empty copy on destination with z > 0 fails TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 0, {0, 0, 1}, {0, 0, 1}); - - // Empty copy with depth > 1 fails - TestT2TCopy(utils::Expectation::Failure, source, 0, 0, {0, 0, 0}, destination, 0, 0, {0, 0, 0}, - {0, 0, 2}); } TEST_F(CopyCommandTest_T2T, 2DTextureDepthStencil) {