From 16036cf206f186a1db2659e717711c72e81c392e Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Fri, 6 Nov 2020 13:41:50 +0000 Subject: [PATCH] Add WGPU_STRIDE_UNDEFINED and update bytesPerRow/rowsPerImage validation This makes a nearly one-to-one mapping between the JS and C APIs, which benefits projects like Blink and Emscripten. - JavaScript's `undefined` is equivalent to C `WGPU_STRIDE_UNDEFINED`. - JavaScript's `0` is equivalent to C `0`. - To implement the API correctly, Blink must special-case an actual value coming in from JS that is equal to WGPU_STRIDE_UNDEFINED (0xFFFF'FFFF), and inject an error. Keeps but deprecates a reasonable approximation of the old behavior. Bug: dawn:520 Change-Id: Ie9c992ffab82830090d0dfc3120731e89cd9691c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31140 Commit-Queue: Corentin Wallez Reviewed-by: Corentin Wallez --- dawn.json | 4 +- examples/CppHelloTriangle.cpp | 3 +- generator/templates/webgpu.h | 1 + generator/templates/webgpu_cpp.h | 1 + src/dawn_native/CommandEncoder.cpp | 56 +-- src/dawn_native/CommandValidation.cpp | 127 ++++-- src/dawn_native/CommandValidation.h | 10 +- src/dawn_native/Format.cpp | 4 + src/dawn_native/Queue.cpp | 11 +- src/tests/DawnTest.cpp | 2 +- src/tests/end2end/BindGroupTests.cpp | 2 +- .../end2end/CompressedTextureFormatTests.cpp | 8 +- src/tests/end2end/CopyTests.cpp | 166 ++++++-- .../end2end/CopyTextureForBrowserTests.cpp | 4 +- .../end2end/NonzeroTextureCreationTests.cpp | 4 +- src/tests/end2end/QueueTests.cpp | 76 +++- src/tests/end2end/RenderPassLoadOpTests.cpp | 2 +- src/tests/end2end/SamplerTests.cpp | 2 +- src/tests/end2end/StorageTextureTests.cpp | 4 +- src/tests/end2end/TextureFormatTests.cpp | 5 +- src/tests/end2end/TextureViewTests.cpp | 2 +- src/tests/end2end/TextureZeroInitTests.cpp | 25 +- .../CopyCommandsValidationTests.cpp | 374 +++++++++++------- .../QueueWriteTextureValidationTests.cpp | 150 ++++--- .../VulkanImageWrappingTestsDmaBuf.cpp | 8 +- .../VulkanImageWrappingTestsOpaqueFD.cpp | 8 +- src/utils/TestUtils.cpp | 15 +- src/utils/TestUtils.h | 3 +- src/utils/WGPUHelpers.h | 4 +- 29 files changed, 712 insertions(+), 369 deletions(-) diff --git a/dawn.json b/dawn.json index 37e9862e9c..9170c20ff5 100644 --- a/dawn.json +++ b/dawn.json @@ -1622,8 +1622,8 @@ "extensible": true, "members": [ {"name": "offset", "type": "uint64_t", "default": 0}, - {"name": "bytes per row", "type": "uint32_t"}, - {"name": "rows per image", "type": "uint32_t", "default": 0} + {"name": "bytes per row", "type": "uint32_t", "default": "WGPU_STRIDE_UNDEFINED"}, + {"name": "rows per image", "type": "uint32_t", "default": "WGPU_STRIDE_UNDEFINED"} ] }, "texture descriptor": { diff --git a/examples/CppHelloTriangle.cpp b/examples/CppHelloTriangle.cpp index cef8d6e122..1a879e9f69 100644 --- a/examples/CppHelloTriangle.cpp +++ b/examples/CppHelloTriangle.cpp @@ -73,8 +73,7 @@ void initTextures() { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, 4 * 1024, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 4 * 1024); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {1024, 1024, 1}; diff --git a/generator/templates/webgpu.h b/generator/templates/webgpu.h index 8e52caca2b..42a4c9358f 100644 --- a/generator/templates/webgpu.h +++ b/generator/templates/webgpu.h @@ -74,6 +74,7 @@ #include #define WGPU_WHOLE_SIZE (0xffffffffffffffffULL) +#define WGPU_STRIDE_UNDEFINED (0xffffffffUL) typedef uint32_t WGPUFlags; diff --git a/generator/templates/webgpu_cpp.h b/generator/templates/webgpu_cpp.h index 275f6b4b31..4819724671 100644 --- a/generator/templates/webgpu_cpp.h +++ b/generator/templates/webgpu_cpp.h @@ -20,6 +20,7 @@ namespace wgpu { static constexpr uint64_t kWholeSize = WGPU_WHOLE_SIZE; + static constexpr uint32_t kStrideUndefined = WGPU_STRIDE_UNDEFINED; {% for type in by_category["enum"] %} enum class {{as_cppType(type.name)}} : uint32_t { diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp index 7d4cb18da7..e26f9e9c8b 100644 --- a/src/dawn_native/CommandEncoder.cpp +++ b/src/dawn_native/CommandEncoder.cpp @@ -580,28 +580,18 @@ namespace dawn_native { } const TexelBlockInfo& blockInfo = destination->texture->GetFormat().GetAspectInfo(destination->aspect).block; + TextureDataLayout srcLayout = FixUpDeprecatedTextureDataLayoutOptions( + GetDevice(), source->layout, blockInfo, *copySize); if (GetDevice()->IsValidationEnabled()) { - DAWN_TRY(ValidateLinearTextureCopyOffset(source->layout, blockInfo)); - DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(), - blockInfo, *copySize)); + DAWN_TRY(ValidateLinearTextureCopyOffset(srcLayout, blockInfo)); + DAWN_TRY(ValidateLinearTextureData(srcLayout, source->buffer->GetSize(), blockInfo, + *copySize)); mTopLevelBuffers.insert(source->buffer); mTopLevelTextures.insert(destination->texture); } - // Compute default value for rowsPerImage - uint32_t defaultedRowsPerImage = source->layout.rowsPerImage; - if (defaultedRowsPerImage == 0) { - ASSERT(copySize->height % blockInfo.height == 0); - defaultedRowsPerImage = copySize->height / blockInfo.height; - } - - // In the case of one row copy bytesPerRow might not contain enough bytes - uint32_t bytesPerRow = source->layout.bytesPerRow; - if (copySize->height <= 1 && copySize->depth <= 1) { - bytesPerRow = - Align(copySize->width * blockInfo.byteSize, kTextureBytesPerRowAlignment); - } + ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize); // Skip noop copies. if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) { @@ -609,9 +599,9 @@ namespace dawn_native { CopyBufferToTextureCmd* copy = allocator->Allocate(Command::CopyBufferToTexture); copy->source.buffer = source->buffer; - copy->source.offset = source->layout.offset; - copy->source.bytesPerRow = bytesPerRow; - copy->source.rowsPerImage = defaultedRowsPerImage; + copy->source.offset = srcLayout.offset; + copy->source.bytesPerRow = srcLayout.bytesPerRow; + copy->source.rowsPerImage = srcLayout.rowsPerImage; copy->destination.texture = destination->texture; copy->destination.origin = destination->origin; copy->destination.mipLevel = destination->mipLevel; @@ -645,28 +635,18 @@ namespace dawn_native { } const TexelBlockInfo& blockInfo = source->texture->GetFormat().GetAspectInfo(source->aspect).block; + TextureDataLayout dstLayout = FixUpDeprecatedTextureDataLayoutOptions( + GetDevice(), destination->layout, blockInfo, *copySize); if (GetDevice()->IsValidationEnabled()) { - DAWN_TRY(ValidateLinearTextureCopyOffset(destination->layout, blockInfo)); - DAWN_TRY(ValidateLinearTextureData( - destination->layout, destination->buffer->GetSize(), blockInfo, *copySize)); + DAWN_TRY(ValidateLinearTextureCopyOffset(dstLayout, blockInfo)); + DAWN_TRY(ValidateLinearTextureData(dstLayout, destination->buffer->GetSize(), + blockInfo, *copySize)); mTopLevelTextures.insert(source->texture); mTopLevelBuffers.insert(destination->buffer); } - // Compute default value for rowsPerImage - uint32_t defaultedRowsPerImage = destination->layout.rowsPerImage; - if (defaultedRowsPerImage == 0) { - ASSERT(copySize->height % blockInfo.height == 0); - defaultedRowsPerImage = copySize->height / blockInfo.height; - } - - // In the case of one row copy bytesPerRow might not contain enough bytes - uint32_t bytesPerRow = destination->layout.bytesPerRow; - if (copySize->height <= 1 && copySize->depth <= 1) { - bytesPerRow = - Align(copySize->width * blockInfo.byteSize, kTextureBytesPerRowAlignment); - } + ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize); // Skip noop copies. if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) { @@ -678,9 +658,9 @@ namespace dawn_native { copy->source.mipLevel = source->mipLevel; copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect); copy->destination.buffer = destination->buffer; - copy->destination.offset = destination->layout.offset; - copy->destination.bytesPerRow = bytesPerRow; - copy->destination.rowsPerImage = defaultedRowsPerImage; + copy->destination.offset = dstLayout.offset; + copy->destination.bytesPerRow = dstLayout.bytesPerRow; + copy->destination.rowsPerImage = dstLayout.rowsPerImage; copy->copySize = *copySize; } diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp index 8ca86f8da7..08ab6d747a 100644 --- a/src/dawn_native/CommandValidation.cpp +++ b/src/dawn_native/CommandValidation.cpp @@ -397,7 +397,6 @@ namespace dawn_native { uint32_t widthInBlocks = copySize.width / blockInfo.width; uint32_t heightInBlocks = copySize.height / blockInfo.height; uint64_t bytesInLastRow = Safe32x32(widthInBlocks, blockInfo.byteSize); - uint64_t bytesPerImage = Safe32x32(bytesPerRow, rowsPerImage); if (copySize.depth == 0) { return 0; @@ -406,7 +405,7 @@ namespace dawn_native { // Check for potential overflows for the rest of the computations. We have the following // inequalities: // - // lastRowBytes <= bytesPerRow + // bytesInLastRow <= bytesPerRow // heightInBlocks <= rowsPerImage // // So: @@ -418,12 +417,16 @@ namespace dawn_native { // // This means that if the computation of depth * bytesPerImage doesn't overflow, none of the // computations for requiredBytesInCopy will. (and it's not a very pessimizing check) + ASSERT(copySize.depth <= 1 || + (bytesPerRow != wgpu::kStrideUndefined && rowsPerImage != wgpu::kStrideUndefined)); + uint64_t bytesPerImage = Safe32x32(bytesPerRow, rowsPerImage); if (bytesPerImage > std::numeric_limits::max() / copySize.depth) { return DAWN_VALIDATION_ERROR("requiredBytesInCopy is too large."); } uint64_t requiredBytesInCopy = bytesPerImage * (copySize.depth - 1); if (heightInBlocks > 0) { + ASSERT(heightInBlocks <= 1 || bytesPerRow != wgpu::kStrideUndefined); uint64_t bytesInLastImage = Safe32x32(bytesPerRow, heightInBlocks - 1) + bytesInLastRow; requiredBytesInCopy += bytesInLastImage; } @@ -442,40 +445,98 @@ namespace dawn_native { return {}; } - MaybeError ValidateLinearTextureData(TextureDataLayout layout, - uint64_t byteSize, - const TexelBlockInfo& blockInfo, - const Extent3D& copyExtent) { - ASSERT(copyExtent.width % blockInfo.width == 0); - uint32_t widthInBlocks = copyExtent.width / blockInfo.width; - ASSERT(copyExtent.height % blockInfo.height == 0); - uint32_t heightInBlocks = copyExtent.height / blockInfo.height; + TextureDataLayout FixUpDeprecatedTextureDataLayoutOptions( + DeviceBase* device, + const TextureDataLayout& originalLayout, + const TexelBlockInfo& blockInfo, + const Extent3D& copyExtent) { + // TODO(crbug.com/dawn/520): Remove deprecated functionality. + TextureDataLayout layout = originalLayout; - // Default value for rowsPerImage - if (layout.rowsPerImage == 0) { - layout.rowsPerImage = heightInBlocks; - } - - // Validation for other members in layout: - ASSERT(Safe32x32(widthInBlocks, blockInfo.byteSize) <= - std::numeric_limits::max()); - uint32_t lastRowBytes = widthInBlocks * blockInfo.byteSize; - if (lastRowBytes > layout.bytesPerRow) { - if (copyExtent.height > 1 || copyExtent.depth > 1) { - return DAWN_VALIDATION_ERROR("The byte size of a row must be <= bytesPerRow."); - } else { - // bytesPerRow is unused. Populate it with a valid value for later validation. - layout.bytesPerRow = lastRowBytes; + if (copyExtent.height != 0 && layout.rowsPerImage == 0) { + if (copyExtent.depth > 1) { + device->EmitDeprecationWarning( + "rowsPerImage soon must be non-zero if copy depth > 1 (it will no longer " + "default to the copy height)."); + ASSERT(copyExtent.height % blockInfo.height == 0); + uint32_t heightInBlocks = copyExtent.height / blockInfo.height; + layout.rowsPerImage = heightInBlocks; + } else if (copyExtent.depth == 1) { + device->EmitDeprecationWarning( + "rowsPerImage soon must be non-zero or unspecified if copy depth == 1 (it will " + "no longer default to the copy height)."); + layout.rowsPerImage = wgpu::kStrideUndefined; } } - // TODO(tommek@google.com): to match the spec there should be another condition here - // on rowsPerImage >= copyExtent.height if copyExtent.depth > 1. + // Only bother to fix-up for height == 1 && depth == 1. + // The other cases that used to be allowed were zero-size copies. + ASSERT(copyExtent.width % blockInfo.width == 0); + uint32_t widthInBlocks = copyExtent.width / blockInfo.width; + uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize; + if (copyExtent.height == 1 && copyExtent.depth == 1 && + bytesInLastRow > layout.bytesPerRow) { + device->EmitDeprecationWarning( + "Soon, even if copy height == 1, bytesPerRow must be >= the byte size of each row " + "or left unspecified."); + layout.bytesPerRow = wgpu::kStrideUndefined; + } + return layout; + } - // Validation for the copy being in-bounds: - if (layout.rowsPerImage != 0 && layout.rowsPerImage < heightInBlocks) { + // Replace wgpu::kStrideUndefined with real values, so backends don't have to think about it. + void ApplyDefaultTextureDataLayoutOptions(TextureDataLayout* layout, + const TexelBlockInfo& blockInfo, + const Extent3D& copyExtent) { + ASSERT(layout != nullptr); + ASSERT(copyExtent.height % blockInfo.height == 0); + uint32_t heightInBlocks = copyExtent.height / blockInfo.height; + + if (layout->bytesPerRow == wgpu::kStrideUndefined) { + ASSERT(copyExtent.width % blockInfo.width == 0); + uint32_t widthInBlocks = copyExtent.width / blockInfo.width; + uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize; + + ASSERT(heightInBlocks <= 1 && copyExtent.depth <= 1); + layout->bytesPerRow = Align(bytesInLastRow, kTextureBytesPerRowAlignment); + } + if (layout->rowsPerImage == wgpu::kStrideUndefined) { + ASSERT(copyExtent.depth <= 1); + layout->rowsPerImage = heightInBlocks; + } + } + + MaybeError ValidateLinearTextureData(const TextureDataLayout& layout, + uint64_t byteSize, + const TexelBlockInfo& blockInfo, + const Extent3D& copyExtent) { + ASSERT(copyExtent.height % blockInfo.height == 0); + uint32_t heightInBlocks = copyExtent.height / blockInfo.height; + + if (copyExtent.depth > 1 && (layout.bytesPerRow == wgpu::kStrideUndefined || + layout.rowsPerImage == wgpu::kStrideUndefined)) { return DAWN_VALIDATION_ERROR( - "rowsPerImage must not be less than the copy height in blocks."); + "If copy depth > 1, bytesPerRow and rowsPerImage must be specified."); + } + if (heightInBlocks > 1 && layout.bytesPerRow == wgpu::kStrideUndefined) { + return DAWN_VALIDATION_ERROR("If heightInBlocks > 1, bytesPerRow must be specified."); + } + + // Validation for other members in layout: + ASSERT(copyExtent.width % blockInfo.width == 0); + uint32_t widthInBlocks = copyExtent.width / blockInfo.width; + ASSERT(Safe32x32(widthInBlocks, blockInfo.byteSize) <= + std::numeric_limits::max()); + uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize; + + // These != wgpu::kStrideUndefined checks are technically redundant with the > checks, but + // they should get optimized out. + if (layout.bytesPerRow != wgpu::kStrideUndefined && bytesInLastRow > layout.bytesPerRow) { + return DAWN_VALIDATION_ERROR("The byte size of each row must be <= bytesPerRow."); + } + if (layout.rowsPerImage != wgpu::kStrideUndefined && heightInBlocks > layout.rowsPerImage) { + return DAWN_VALIDATION_ERROR( + "The height of each image, in blocks, must be <= rowsPerImage."); } // We compute required bytes in copy after validating texel block alignments @@ -499,8 +560,10 @@ namespace dawn_native { MaybeError ValidateBufferCopyView(DeviceBase const* device, const BufferCopyView& bufferCopyView) { DAWN_TRY(device->ValidateObject(bufferCopyView.buffer)); - if (bufferCopyView.layout.bytesPerRow % kTextureBytesPerRowAlignment != 0) { - return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256"); + if (bufferCopyView.layout.bytesPerRow != wgpu::kStrideUndefined) { + if (bufferCopyView.layout.bytesPerRow % kTextureBytesPerRowAlignment != 0) { + return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256"); + } } return {}; diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h index 0eb04f50b7..3e46774c2f 100644 --- a/src/dawn_native/CommandValidation.h +++ b/src/dawn_native/CommandValidation.h @@ -51,7 +51,15 @@ namespace dawn_native { uint32_t bytesPerRow, uint32_t rowsPerImage); - MaybeError ValidateLinearTextureData(TextureDataLayout layout, + TextureDataLayout FixUpDeprecatedTextureDataLayoutOptions( + DeviceBase* device, + const TextureDataLayout& originalLayout, + const TexelBlockInfo& blockInfo, + const Extent3D& copyExtent); + void ApplyDefaultTextureDataLayoutOptions(TextureDataLayout* layout, + const TexelBlockInfo& blockInfo, + const Extent3D& copyExtent); + MaybeError ValidateLinearTextureData(const TextureDataLayout& layout, uint64_t byteSize, const TexelBlockInfo& blockInfo, const Extent3D& copyExtent); diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp index 74831b3231..f57b7b4178 100644 --- a/src/dawn_native/Format.cpp +++ b/src/dawn_native/Format.cpp @@ -127,6 +127,10 @@ namespace dawn_native { // formats are set exactly once. ASSERT(!formatsSet[index]); + // Vulkan describes bytesPerRow in units of texels. If there's any format for which this + // ASSERT isn't true, then additional validation on bytesPerRow must be added. + ASSERT((kTextureBytesPerRowAlignment % format.firstAspect.block.byteSize) == 0); + table[index] = format; formatsSet.set(index); }; diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp index 11b7f5eb21..8bf92e1fb2 100644 --- a/src/dawn_native/Queue.cpp +++ b/src/dawn_native/Queue.cpp @@ -441,10 +441,13 @@ namespace dawn_native { // copyExtent.height by blockHeight while the divisibility conditions are // checked in validating texture copy range. DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize)); - DAWN_TRY(ValidateLinearTextureData( - *dataLayout, dataSize, - destination->texture->GetFormat().GetAspectInfo(destination->aspect).block, - *writeSize)); + + const TexelBlockInfo& blockInfo = + destination->texture->GetFormat().GetAspectInfo(destination->aspect).block; + + TextureDataLayout layout = FixUpDeprecatedTextureDataLayoutOptions(GetDevice(), *dataLayout, + blockInfo, *writeSize); + DAWN_TRY(ValidateLinearTextureData(layout, dataSize, blockInfo, *writeSize)); DAWN_TRY(destination->texture->ValidateCanUseInSubmitNow()); diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index 3040fa7e8f..171f2f66c5 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -889,7 +889,7 @@ std::ostringstream& DawnTestBase::AddTextureExpectationImpl(const char* file, wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, level, {x, y, slice}, aspect); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(readback.buffer, readback.offset, bytesPerRow, 0); + utils::CreateBufferCopyView(readback.buffer, readback.offset, bytesPerRow, rowsPerImage); wgpu::Extent3D copySize = {width, height, 1}; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); diff --git a/src/tests/end2end/BindGroupTests.cpp b/src/tests/end2end/BindGroupTests.cpp index 4239e7dda9..abc85b2594 100644 --- a/src/tests/end2end/BindGroupTests.cpp +++ b/src/tests/end2end/BindGroupTests.cpp @@ -304,7 +304,7 @@ TEST_P(BindGroupTests, UBOSamplerAndTexture) { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, widthInBytes, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, widthInBytes); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {width, height, 1}; encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); diff --git a/src/tests/end2end/CompressedTextureFormatTests.cpp b/src/tests/end2end/CompressedTextureFormatTests.cpp index 43b8b8973b..5ad5a323d1 100644 --- a/src/tests/end2end/CompressedTextureFormatTests.cpp +++ b/src/tests/end2end/CompressedTextureFormatTests.cpp @@ -30,7 +30,7 @@ struct CopyConfig { uint32_t viewMipmapLevel = 0; uint32_t bufferOffset = 0; uint32_t bytesPerRowAlignment = kTextureBytesPerRowAlignment; - uint32_t rowsPerImage = 0; + uint32_t rowsPerImage = wgpu::kStrideUndefined; }; class CompressedTextureBCFormatTest : public DawnTest { @@ -60,7 +60,7 @@ class CompressedTextureBCFormatTest : public DawnTest { utils::GetTexelBlockSizeInBytes(copyConfig.textureDescriptor.format); } uint32_t copyRowsPerImage = copyConfig.rowsPerImage; - if (copyRowsPerImage == 0) { + if (copyRowsPerImage == wgpu::kStrideUndefined) { copyRowsPerImage = copyHeightInBlock; } uint32_t copyBytesPerImage = copyBytesPerRow * copyRowsPerImage; @@ -1028,6 +1028,7 @@ TEST_P(CompressedTextureBCFormatTest, CopyWhole2DArrayTexture) { CopyConfig config; config.textureDescriptor.usage = kDefaultBCFormatTextureUsage; config.textureDescriptor.size = {8, 8, kArrayLayerCount}; + config.rowsPerImage = 8; config.copyExtent3D = config.textureDescriptor.size; config.copyExtent3D.depth = kArrayLayerCount; @@ -1054,6 +1055,7 @@ TEST_P(CompressedTextureBCFormatTest, CopyMultiple2DArrayLayers) { CopyConfig config; config.textureDescriptor.usage = kDefaultBCFormatTextureUsage; config.textureDescriptor.size = {8, 8, kArrayLayerCount}; + config.rowsPerImage = 8; constexpr uint32_t kCopyBaseArrayLayer = 1; constexpr uint32_t kCopyLayerCount = 2; @@ -1087,7 +1089,7 @@ TEST_P(CompressedTextureBCFormatTest, UnalignedDynamicUploader) { wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, 256, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, 256); wgpu::Extent3D copyExtent = {4, 4, 1}; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp index d1c171ee4e..98a1f091f2 100644 --- a/src/tests/end2end/CopyTests.cpp +++ b/src/tests/end2end/CopyTests.cpp @@ -21,6 +21,9 @@ #include "utils/TextureFormatUtils.h" #include "utils/WGPUHelpers.h" +// For MinimumBufferSpec bytesPerRow and rowsPerImage, compute a default from the copy extent. +constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul; + class CopyTests : public DawnTest { protected: static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; @@ -56,18 +59,27 @@ class CopyTests : public DawnTest { return textureData; } - static BufferSpec MinimumBufferSpec(uint32_t width, - uint32_t height, - uint32_t arrayLayer = 1, - bool testZeroRowsPerImage = true) { - const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, width); - const uint32_t rowsPerImage = height; - const uint32_t totalBufferSize = utils::RequiredBytesInCopy( - bytesPerRow, rowsPerImage, {width, height, arrayLayer}, kTextureFormat); - uint32_t appliedRowsPerImage = testZeroRowsPerImage ? 0 : height; - return {totalBufferSize, 0, bytesPerRow, appliedRowsPerImage}; + static BufferSpec MinimumBufferSpec(uint32_t width, uint32_t height, uint32_t depth = 1) { + return MinimumBufferSpec({width, height, depth}, kStrideComputeDefault, + depth == 1 ? wgpu::kStrideUndefined : kStrideComputeDefault); } + static BufferSpec MinimumBufferSpec(wgpu::Extent3D copyExtent, + uint32_t overrideBytesPerRow = kStrideComputeDefault, + uint32_t overrideRowsPerImage = kStrideComputeDefault) { + uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, copyExtent.width); + if (overrideBytesPerRow != kStrideComputeDefault) { + bytesPerRow = overrideBytesPerRow; + } + uint32_t rowsPerImage = copyExtent.height; + if (overrideRowsPerImage != kStrideComputeDefault) { + rowsPerImage = overrideRowsPerImage; + } + + uint32_t totalDataSize = + utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, copyExtent, kTextureFormat); + return {totalDataSize, 0, bytesPerRow, rowsPerImage}; + } static void PackTextureData(const RGBA8* srcData, uint32_t width, uint32_t height, @@ -100,10 +112,11 @@ class CopyTests_T2B : public CopyTests { descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; wgpu::Texture texture = device.CreateTexture(&descriptor); + // Layout for initial data upload to texture. + // Some parts of this result are also reused later. const utils::TextureDataCopyLayout copyLayout = utils::GetTextureDataCopyLayoutForTexture2DAtLevel( - kTextureFormat, textureSpec.textureSize, textureSpec.level, - bufferSpec.rowsPerImage); + kTextureFormat, textureSpec.textureSize, textureSpec.level); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); @@ -113,7 +126,7 @@ class CopyTests_T2B : public CopyTests { wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( device, textureArrayData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( - uploadBuffer, 0, copyLayout.bytesPerRow, bufferSpec.rowsPerImage); + uploadBuffer, 0, copyLayout.bytesPerRow, copyLayout.rowsPerImage); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0}); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Layout.mipSize); @@ -156,22 +169,23 @@ class CopyTests_T2B : public CopyTests { texelIndexOffset + (textureSpec.copyOrigin.x + textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow); - PackTextureData(&textureArrayData[expectedTexelArrayDataStartIndex], copySize.width, - copySize.height, copyLayout.texelBlocksPerRow, expected.data(), - bufferSpec.bytesPerRow / bytesPerTexel); + PackTextureData(textureArrayData.data() + expectedTexelArrayDataStartIndex, + copySize.width, copySize.height, copyLayout.texelBlocksPerRow, + expected.data(), bufferSpec.bytesPerRow / bytesPerTexel); EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast(expected.data()), buffer, bufferOffset, static_cast(expected.size())) << "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x - << ", " << textureSpec.copyOrigin.y << "), (" + << ", " << textureSpec.copyOrigin.y << ", " << textureSpec.copyOrigin.z << "), (" << textureSpec.copyOrigin.x + copySize.width << ", " - << textureSpec.copyOrigin.y + copySize.height << ")) from " + << textureSpec.copyOrigin.y + copySize.height << ", " + << textureSpec.copyOrigin.z + copySize.depth << ")) from " << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height << " texture at mip level " << textureSpec.level << " layer " << slice << " to " << bufferSpec.size << "-byte buffer with offset " << bufferOffset << " and bytes per row " << bufferSpec.bytesPerRow << std::endl; - bufferOffset += copyLayout.bytesPerImage; + bufferOffset += bufferSpec.bytesPerRow * bufferSpec.rowsPerImage; } } }; @@ -232,7 +246,7 @@ class CopyTests_B2T : public CopyTests { // Pack the data used to create the buffer in the specified copy region to have the same // format as the expected texture data. std::vector expected(texelCountLastLayer); - PackTextureData(&bufferData[bufferOffset / bytesPerTexel], copySize.width, + PackTextureData(bufferData.data() + bufferOffset / bytesPerTexel, copySize.width, copySize.height, bufferSpec.bytesPerRow / bytesPerTexel, expected.data(), copySize.width); @@ -288,14 +302,14 @@ class CopyTests_T2T : public CopyTests { utils::GetTextureDataCopyLayoutForTexture2DAtLevel( kTextureFormat, {srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth}, - srcSpec.level, 0); + srcSpec.level); const std::vector textureArrayCopyData = GetExpectedTextureData(copyLayout); wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( device, textureArrayCopyData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, copyLayout.bytesPerRow, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( + uploadBuffer, 0, copyLayout.bytesPerRow, copyLayout.rowsPerImage); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z}); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Layout.mipSize); @@ -633,7 +647,7 @@ TEST_P(CopyTests_T2B, OffsetBufferUnaligned) { // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row // works -TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) { +TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallBytesPerRow) { constexpr uint32_t kWidth = 32; constexpr uint32_t kHeight = 128; @@ -652,7 +666,7 @@ TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) { } // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works -TEST_P(CopyTests_T2B, RowPitchAligned) { +TEST_P(CopyTests_T2B, BytesPerRowAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; @@ -671,7 +685,7 @@ TEST_P(CopyTests_T2B, RowPitchAligned) { // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte // aligned works -TEST_P(CopyTests_T2B, RowPitchUnaligned) { +TEST_P(CopyTests_T2B, BytesPerRowUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; @@ -699,18 +713,55 @@ TEST_P(CopyTests_T2B, BytesPerRowWithOneRowCopy) { textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.level = 0; - // bytesPerRow = 0 { BufferSpec bufferSpec = MinimumBufferSpec(5, 1); + + // bytesPerRow = 0 + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. bufferSpec.bytesPerRow = 0; + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {5, 1, 1})); + + // bytesPerRow undefined + bufferSpec.bytesPerRow = wgpu::kStrideUndefined; DoTest(textureSpec, bufferSpec, {5, 1, 1}); } // bytesPerRow < bytesInACompleteRow + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. { BufferSpec bufferSpec = MinimumBufferSpec(259, 1); bufferSpec.bytesPerRow = 256; - DoTest(textureSpec, bufferSpec, {259, 1, 1}); + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {259, 1, 1})); + } +} + +TEST_P(CopyTests_T2B, StrideSpecialCases) { + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {4, 4, 4}; + textureSpec.level = 0; + + // bytesPerRow 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent); + } + + // bytesPerRow undefined + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent); + } + + // rowsPerImage 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent); + } + + // rowsPerImage undefined + for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent); } } @@ -780,7 +831,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionNonzeroRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.rowsPerImage = kRowsPerImage; DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); } @@ -801,7 +852,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetOddRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.offset += 128u; bufferSpec.size += 128u; bufferSpec.rowsPerImage = kRowsPerImage; @@ -824,7 +875,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetEvenRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.offset += 128u; bufferSpec.size += 128u; bufferSpec.rowsPerImage = kRowsPerImage; @@ -1083,7 +1134,7 @@ TEST_P(CopyTests_B2T, OffsetBufferUnaligned) { // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row // works -TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) { +TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallBytesPerRow) { constexpr uint32_t kWidth = 32; constexpr uint32_t kHeight = 128; @@ -1102,7 +1153,7 @@ TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) { } // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works -TEST_P(CopyTests_B2T, RowPitchAligned) { +TEST_P(CopyTests_B2T, BytesPerRowAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; @@ -1121,7 +1172,7 @@ TEST_P(CopyTests_B2T, RowPitchAligned) { // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte // aligned works -TEST_P(CopyTests_B2T, RowPitchUnaligned) { +TEST_P(CopyTests_B2T, BytesPerRowUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; @@ -1149,18 +1200,55 @@ TEST_P(CopyTests_B2T, BytesPerRowWithOneRowCopy) { textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.level = 0; - // bytesPerRow = 0 { BufferSpec bufferSpec = MinimumBufferSpec(5, 1); + + // bytesPerRow = 0 + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. bufferSpec.bytesPerRow = 0; + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {5, 1, 1})); + + // bytesPerRow undefined + bufferSpec.bytesPerRow = wgpu::kStrideUndefined; DoTest(textureSpec, bufferSpec, {5, 1, 1}); } // bytesPerRow < bytesInACompleteRow + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. { BufferSpec bufferSpec = MinimumBufferSpec(259, 1); bufferSpec.bytesPerRow = 256; - DoTest(textureSpec, bufferSpec, {259, 1, 1}); + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {259, 1, 1})); + } +} + +TEST_P(CopyTests_B2T, StrideSpecialCases) { + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {4, 4, 4}; + textureSpec.level = 0; + + // bytesPerRow 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent); + } + + // bytesPerRow undefined + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent); + } + + // rowsPerImage 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent); + } + + // rowsPerImage undefined + for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) { + DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent); } } @@ -1211,7 +1299,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionNonzeroRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.rowsPerImage = kRowsPerImage; DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); } @@ -1232,7 +1320,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetOddRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.offset += 128u; bufferSpec.size += 128u; bufferSpec.rowsPerImage = kRowsPerImage; @@ -1255,7 +1343,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetEvenRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.level = 0; - BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers); bufferSpec.offset += 128u; bufferSpec.size += 128u; bufferSpec.rowsPerImage = kRowsPerImage; diff --git a/src/tests/end2end/CopyTextureForBrowserTests.cpp b/src/tests/end2end/CopyTextureForBrowserTests.cpp index 1ab8a44dff..c38cbeea8e 100644 --- a/src/tests/end2end/CopyTextureForBrowserTests.cpp +++ b/src/tests/end2end/CopyTextureForBrowserTests.cpp @@ -92,7 +92,7 @@ class CopyTextureForBrowserTests : public DawnTest { utils::GetTextureDataCopyLayoutForTexture2DAtLevel( kTextureFormat, {srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth}, - srcSpec.level, 0); + srcSpec.level); const std::vector textureArrayCopyData = GetExpectedTextureData(copyLayout); wgpu::TextureCopyView textureCopyView = @@ -101,7 +101,7 @@ class CopyTextureForBrowserTests : public DawnTest { wgpu::TextureDataLayout textureDataLayout; textureDataLayout.offset = 0; textureDataLayout.bytesPerRow = copyLayout.bytesPerRow; - textureDataLayout.rowsPerImage = copyLayout.bytesPerImage / copyLayout.bytesPerRow; + textureDataLayout.rowsPerImage = copyLayout.rowsPerImage; device.GetDefaultQueue().WriteTexture(&textureCopyView, textureArrayCopyData.data(), textureArrayCopyData.size() * sizeof(RGBA8), diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp index 2e574cc05c..efb301bd10 100644 --- a/src/tests/end2end/NonzeroTextureCreationTests.cpp +++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp @@ -134,7 +134,7 @@ TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) { wgpu::Buffer bufferDst = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -168,7 +168,7 @@ TEST_P(NonzeroTextureCreationTests, NonRenderableTextureClearWithMultiArrayLayer wgpu::Buffer bufferDst = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1}); wgpu::Extent3D copySize = {kSize, kSize, 1}; diff --git a/src/tests/end2end/QueueTests.cpp b/src/tests/end2end/QueueTests.cpp index bcda12f327..6502315ba0 100644 --- a/src/tests/end2end/QueueTests.cpp +++ b/src/tests/end2end/QueueTests.cpp @@ -199,6 +199,9 @@ DAWN_INSTANTIATE_TEST(QueueWriteBufferTests, OpenGLBackend(), VulkanBackend()); +// For MinimumDataSpec bytesPerRow and rowsPerImage, compute a default from the copy extent. +constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul; + class QueueWriteTextureTests : public DawnTest { protected: static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; @@ -217,14 +220,17 @@ class QueueWriteTextureTests : public DawnTest { }; static DataSpec MinimumDataSpec(wgpu::Extent3D writeSize, - uint32_t bytesPerRow = 0, - uint32_t rowsPerImage = 0) { - if (bytesPerRow == 0) { - bytesPerRow = writeSize.width * utils::GetTexelBlockSizeInBytes(kTextureFormat); + uint32_t overrideBytesPerRow = kStrideComputeDefault, + uint32_t overrideRowsPerImage = kStrideComputeDefault) { + uint32_t bytesPerRow = writeSize.width * utils::GetTexelBlockSizeInBytes(kTextureFormat); + if (overrideBytesPerRow != kStrideComputeDefault) { + bytesPerRow = overrideBytesPerRow; } - if (rowsPerImage == 0) { - rowsPerImage = writeSize.height; + uint32_t rowsPerImage = writeSize.height; + if (overrideRowsPerImage != kStrideComputeDefault) { + rowsPerImage = overrideRowsPerImage; } + uint32_t totalDataSize = utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, writeSize, kTextureFormat); return {totalDataSize, 0, bytesPerRow, rowsPerImage}; @@ -282,10 +288,14 @@ class QueueWriteTextureTests : public DawnTest { wgpu::Extent3D mipSize = {textureSpec.textureSize.width >> textureSpec.level, textureSpec.textureSize.height >> textureSpec.level, textureSpec.textureSize.depth}; - uint32_t alignedBytesPerRow = Align(dataSpec.bytesPerRow, bytesPerTexel); + uint32_t bytesPerRow = dataSpec.bytesPerRow; + if (bytesPerRow == wgpu::kStrideUndefined) { + bytesPerRow = mipSize.width * bytesPerTexel; + } + uint32_t alignedBytesPerRow = Align(bytesPerRow, bytesPerTexel); uint32_t appliedRowsPerImage = dataSpec.rowsPerImage > 0 ? dataSpec.rowsPerImage : mipSize.height; - uint32_t bytesPerImage = dataSpec.bytesPerRow * appliedRowsPerImage; + uint32_t bytesPerImage = bytesPerRow * appliedRowsPerImage; const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth; @@ -296,7 +306,7 @@ class QueueWriteTextureTests : public DawnTest { // Pack the data in the specified copy region to have the same // format as the expected texture data. std::vector expected(texelCountLastLayer); - PackTextureData(&data[dataOffset], copySize.width, copySize.height, + PackTextureData(data.data() + dataOffset, copySize.width, copySize.height, dataSpec.bytesPerRow, expected.data(), copySize.width, bytesPerTexel); EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.copyOrigin.x, @@ -468,7 +478,7 @@ TEST_P(QueueWriteTextureTests, VaryingRowsPerImage) { textureSpec.textureSize = {kWidth, kHeight, kDepth}; textureSpec.level = 0; - DataSpec dataSpec = MinimumDataSpec(copySize, 0, copySize.height + r); + DataSpec dataSpec = MinimumDataSpec(copySize, kStrideComputeDefault, copySize.height + r); DoTest(textureSpec, dataSpec, copySize); } } @@ -488,7 +498,7 @@ TEST_P(QueueWriteTextureTests, VaryingBytesPerRow) { for (unsigned int b : {1, 2, 3, 4}) { uint32_t bytesPerRow = copyExtent.width * utils::GetTexelBlockSizeInBytes(kTextureFormat) + b; - DoTest(textureSpec, MinimumDataSpec(copyExtent, bytesPerRow, 0), copyExtent); + DoTest(textureSpec, MinimumDataSpec(copyExtent, bytesPerRow), copyExtent); } } @@ -503,22 +513,27 @@ TEST_P(QueueWriteTextureTests, BytesPerRowWithOneRowCopy) { textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.level = 0; - // bytesPerRow = 0 { constexpr wgpu::Extent3D copyExtent = {5, 1, 1}; - DataSpec dataSpec = MinimumDataSpec(copyExtent); + + // bytesPerRow = 0 + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. dataSpec.bytesPerRow = 0; + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, dataSpec, copyExtent)); + + // bytesPerRow undefined + dataSpec.bytesPerRow = wgpu::kStrideUndefined; DoTest(textureSpec, dataSpec, copyExtent); } // bytesPerRow < bytesInACompleteRow + // TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case. { constexpr wgpu::Extent3D copyExtent = {259, 1, 1}; - DataSpec dataSpec = MinimumDataSpec(copyExtent); dataSpec.bytesPerRow = 256; - DoTest(textureSpec, dataSpec, copyExtent); + EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, dataSpec, copyExtent)); } } @@ -552,6 +567,37 @@ TEST_P(QueueWriteTextureTests, VaryingArrayBytesPerRow) { } } +// Test valid special cases of bytesPerRow and rowsPerImage (0 or undefined). +TEST_P(QueueWriteTextureTests, StrideSpecialCases) { + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {4, 4, 4}; + textureSpec.level = 0; + + // bytesPerRow 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumDataSpec(copyExtent, 0, 2), copyExtent); + } + + // bytesPerRow undefined + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) { + DoTest(textureSpec, MinimumDataSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent); + } + + // rowsPerImage 0 + for (const wgpu::Extent3D copyExtent : + {wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) { + DoTest(textureSpec, MinimumDataSpec(copyExtent, 256, 0), copyExtent); + } + + // rowsPerImage undefined + for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) { + DoTest(textureSpec, MinimumDataSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent); + } +} + // Testing a special code path: writing when dynamic uploader already contatins some unaligned // data, it might be necessary to use a ring buffer with properly aligned offset. TEST_P(QueueWriteTextureTests, UnalignedDynamicUploader) { diff --git a/src/tests/end2end/RenderPassLoadOpTests.cpp b/src/tests/end2end/RenderPassLoadOpTests.cpp index 645ccb5343..af351b134d 100644 --- a/src/tests/end2end/RenderPassLoadOpTests.cpp +++ b/src/tests/end2end/RenderPassLoadOpTests.cpp @@ -123,7 +123,7 @@ class RenderPassLoadOpTests : public DawnTest { wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(buffer, 0, kTextureBytesPerRowAlignment, 0); + utils::CreateBufferCopyView(buffer, 0, kTextureBytesPerRowAlignment); encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &kTextureSize); wgpu::CommandBuffer commandBuffer = encoder.Finish(); diff --git a/src/tests/end2end/SamplerTests.cpp b/src/tests/end2end/SamplerTests.cpp index ad5ed92142..b3483d6496 100644 --- a/src/tests/end2end/SamplerTests.cpp +++ b/src/tests/end2end/SamplerTests.cpp @@ -104,7 +104,7 @@ class SamplerTest : public DawnTest { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(device, data, sizeof(data), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 256, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 256); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {2, 2, 1}; diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp index 6e6a97fe5a..536766ac4e 100644 --- a/src/tests/end2end/StorageTextureTests.cpp +++ b/src/tests/end2end/StorageTextureTests.cpp @@ -464,7 +464,7 @@ class StorageTextureTests : public DawnTest { const wgpu::Extent3D copyExtent = {kWidth, kHeight, arrayLayerCount}; wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, kTextureBytesPerRowAlignment, 0); + utils::CreateBufferCopyView(uploadBuffer, 0, kTextureBytesPerRowAlignment, kHeight); wgpu::TextureCopyView textureCopyView; textureCopyView.texture = outputTexture; encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Extent); @@ -640,7 +640,7 @@ class StorageTextureTests : public DawnTest { wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(writeonlyStorageTexture, 0, {0, 0, 0}); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(resultBuffer, 0, kTextureBytesPerRowAlignment, 0); + utils::CreateBufferCopyView(resultBuffer, 0, kTextureBytesPerRowAlignment, kHeight); encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, ©Extent); wgpu::CommandBuffer commandBuffer = encoder.Finish(); queue.Submit(1, &commandBuffer); diff --git a/src/tests/end2end/TextureFormatTests.cpp b/src/tests/end2end/TextureFormatTests.cpp index 1055267958..f26153f2f9 100644 --- a/src/tests/end2end/TextureFormatTests.cpp +++ b/src/tests/end2end/TextureFormatTests.cpp @@ -240,7 +240,7 @@ class TextureFormatTest : public DawnTest { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); { - wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(uploadBuffer, 0, 256, 0); + wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(uploadBuffer, 0, 256); wgpu::TextureCopyView textureView = utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 0}); wgpu::Extent3D extent{width, 1, 1}; @@ -255,8 +255,7 @@ class TextureFormatTest : public DawnTest { renderPass.EndPass(); { - wgpu::BufferCopyView bufferView = - utils::CreateBufferCopyView(readbackBuffer, 0, 256, 0); + wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(readbackBuffer, 0, 256); wgpu::TextureCopyView textureView = utils::CreateTextureCopyView(renderTarget, 0, {0, 0, 0}); wgpu::Extent3D extent{width, 1, 1}; diff --git a/src/tests/end2end/TextureViewTests.cpp b/src/tests/end2end/TextureViewTests.cpp index 597ce3542f..139e5c66a4 100644 --- a/src/tests/end2end/TextureViewTests.cpp +++ b/src/tests/end2end/TextureViewTests.cpp @@ -134,7 +134,7 @@ class TextureViewSamplingTest : public DawnTest { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), data.size() * sizeof(RGBA8), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kTextureBytesPerRowAlignment, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kTextureBytesPerRowAlignment); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(mTexture, level, {0, 0, layer}); wgpu::Extent3D copySize = {texWidth, texHeight, 1}; diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp index bb9231b526..e8ec0cc02b 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp @@ -153,7 +153,7 @@ TEST_P(TextureZeroInitTest, CopyMultipleTextureArrayLayersToBufferSource) { wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); const wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(buffer, 0, bytesPerRow, 0); + utils::CreateBufferCopyView(buffer, 0, bytesPerRow, kSize); const wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); const wgpu::Extent3D copySize = {kSize, kSize, kArrayLayers}; @@ -275,7 +275,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTexture) { device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint32_t), 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint32_t)); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -306,7 +306,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) { device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint16_t), 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint16_t)); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize / 2, kSize, 1}; @@ -340,7 +340,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureMultipleArrayLayers) { device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); const wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, kSize); const wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, kBaseArrayLayer}); const wgpu::Extent3D copySize = {kSize, kSize, kCopyLayerCount}; @@ -414,7 +414,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(srcTexture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -965,7 +965,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClear) { wgpu::Buffer bufferDst = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -996,7 +996,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClearUnalignedSize) { std::vector data(bufferSize, 100); wgpu::Buffer bufferDst = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1}; @@ -1026,7 +1026,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) { device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(bufferDst, 0, kSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(bufferDst, 0, kSize * kFormatBlockByteSize); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -1064,7 +1064,7 @@ TEST_P(TextureZeroInitTest, RenderPassStoreOpClear) { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); @@ -1212,7 +1212,7 @@ TEST_P(TextureZeroInitTest, PreservesInitializedMip) { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, mipSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, mipSize * kFormatBlockByteSize); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(sampleTexture, 1, {0, 0, 0}); wgpu::Extent3D copySize = {mipSize, mipSize, 1}; @@ -1290,7 +1290,7 @@ TEST_P(TextureZeroInitTest, PreservesInitializedArrayLayer) { wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( device, data.data(), static_cast(data.size()), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); + utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 1}); wgpu::Extent3D copySize = {kSize, kSize, 1}; @@ -1374,8 +1374,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToBufferNonRenderableUnaligned) { bufferSize, wgpu::BufferUsage::CopyDst); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(buffer, 0, bytesPerRow, 0); + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, bytesPerRow); wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1}; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp index 55c5fbc27a..2804078c8a 100644 --- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp +++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp @@ -367,51 +367,75 @@ TEST_F(CopyCommandTest_B2T, Success) { // Different copies, including some that touch the OOB condition { // Copy 4x4 block in corner of first mip. - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); // Copy 4x4 block in opposite corner of first mip. - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {12, 12, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {12, 12, 0}, {4, 4, 1}); // Copy 4x4 block in the 4x4 mip. - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 2, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 2, {0, 0, 0}, {4, 4, 1}); // Copy with a buffer offset - TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, + TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); + TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, + wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, {1, 1, 1}); } // Copies with a 256-byte aligned bytes per row but unaligned texture region { // Unaligned region - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0}, {3, 4, 1}); // Unaligned region with texture offset - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {5, 7, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 3, destination, 0, {5, 7, 0}, {2, 3, 1}); // Unaligned region, with buffer offset - TestB2TCopy(utils::Expectation::Success, source, 31 * 4, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 31 * 4, 256, 3, destination, 0, {0, 0, 0}, {3, 3, 1}); } + // bytesPerRow is undefined + { + TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 2, destination, + 0, {0, 0, 0}, {1, 1, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 2, destination, + 0, {0, 0, 0}, {3, 1, 1}); + // Fail because height or depth is greater than 1: + TestB2TCopy(utils::Expectation::Failure, source, 0, wgpu::kStrideUndefined, 2, destination, + 0, {0, 0, 0}, {1, 2, 1}); + TestB2TCopy(utils::Expectation::Failure, source, 0, wgpu::kStrideUndefined, 2, destination, + 0, {0, 0, 0}, {1, 1, 2}); + } + // Empty copies are valid { // An empty copy TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination, + 0, {0, 0, 0}, {0, 0, 1}); // An empty copy with depth = 0 TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 0}); + TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination, + 0, {0, 0, 0}, {0, 0, 0}); // An empty copy touching the end of the buffer TestB2TCopy(utils::Expectation::Success, source, bufferSize, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); + TestB2TCopy(utils::Expectation::Success, source, bufferSize, wgpu::kStrideUndefined, 0, + destination, 0, {0, 0, 0}, {0, 0, 1}); // An empty copy touching the side of the texture TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {16, 16, 0}, {0, 0, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination, + 0, {16, 16, 0}, {0, 0, 1}); + // An empty copy with depth = 1 and bytesPerRow > 0 TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0 - TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 16, + TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 3, destination, 0, {0, 0, 0}, {0, 1, 0}); } } @@ -424,16 +448,16 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) { Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // OOB on the buffer because we copy too many pixels - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 5, 1}); // OOB on the buffer because of the offset - TestB2TCopy(utils::Expectation::Failure, source, 4, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 4, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); // OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth // overflows - TestB2TCopy(utils::Expectation::Failure, source, 0, 512, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 512, 3, destination, 0, {0, 0, 0}, {4, 3, 1}); // Not OOB on the buffer although bytes per row * height overflows @@ -443,7 +467,7 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) { ASSERT_TRUE(256 * 3 > sourceBufferSize) << "bytes per row * height should overflow buffer"; wgpu::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, wgpu::BufferUsage::CopySrc); - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 3, destination, 0, {0, 0, 0}, {7, 3, 1}); } } @@ -456,15 +480,15 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) { Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // OOB on the texture because x + width overflows - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {13, 12, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 0, {13, 12, 0}, {4, 4, 1}); // OOB on the texture because y + width overflows - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {12, 13, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 0, {12, 13, 0}, {4, 4, 1}); // OOB on the texture because we overflow a non-zero mip - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 2, {1, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 2, {1, 0, 0}, {4, 4, 1}); // OOB on the texture even on an empty copy when we copy to a non-existent mip. @@ -494,80 +518,106 @@ TEST_F(CopyCommandTest_B2T, IncorrectUsage) { Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::Sampled); // Incorrect source usage - TestB2TCopy(utils::Expectation::Failure, vertex, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, vertex, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); // Incorrect destination usage - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, sampled, 0, {0, 0, 0}, {4, 4, 1}); + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, sampled, 0, {0, 0, 0}, {4, 4, 1}); } -TEST_F(CopyCommandTest_B2T, IncorrectBytesPerRow) { +TEST_F(CopyCommandTest_B2T, BytesPerRowConstraints) { uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc); - wgpu::Texture destination = Create2DTexture(128, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, + wgpu::Texture destination = Create2DTexture(128, 16, 5, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // bytes per row is 0 { // copyHeight > 1 - TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 4, destination, 0, {0, 0, 0}, {64, 4, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, 0, 4, destination, 0, {0, 0, 0}, + {0, 4, 1}); // copyDepth > 1 TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 1, destination, 0, {0, 0, 0}, {64, 1, 4}); + TestB2TCopy(utils::Expectation::Success, source, 0, 0, 1, destination, 0, {0, 0, 0}, + {0, 1, 4}); // copyHeight = 1 and copyDepth = 1 - TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, - {64, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 0, 1, + destination, 0, {0, 0, 0}, {64, 1, 1})); } // bytes per row is not 256-byte aligned { // copyHeight > 1 - TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); // copyHeight = 1 and copyDepth = 1 - TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 1, destination, 0, {0, 0, 0}, {4, 1, 1}); } // bytes per row is less than width * bytesPerPixel { // copyHeight > 1 - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, 0, {0, 0, 0}, {65, 2, 1}); + // copyHeight == 0 + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + {65, 0, 1}); // copyDepth > 1 TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0}, {65, 1, 2}); + // copyDepth == 0 + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0}, + {65, 1, 0}); // copyHeight = 1 and copyDepth = 1 - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, - {65, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1, + destination, 0, {0, 0, 0}, {65, 1, 1})); } } -TEST_F(CopyCommandTest_B2T, ImageHeightConstraint) { - uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 1); +TEST_F(CopyCommandTest_B2T, RowsPerImageConstraints) { + uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 6); wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc); wgpu::Texture destination = - Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); + Create2DTexture(16, 16, 1, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); - // Image height is zero (Valid) - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, + // rowsPerImage is zero + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, + destination, 0, {0, 0, 0}, {1, 1, 1})); + EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, + destination, 0, {0, 0, 0}, {4, 4, 1})); + + // rowsPerImage is undefined + TestB2TCopy(utils::Expectation::Success, source, 0, 256, wgpu::kStrideUndefined, destination, 0, + {0, 0, 0}, {4, 4, 1}); + // Fail because depth > 1: + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, wgpu::kStrideUndefined, destination, 0, + {0, 0, 0}, {4, 4, 2}); + + // rowsPerImage is equal to copy height (Valid) + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0}, + {4, 4, 2}); - // Image height is equal to copy height (Valid) - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, - {4, 4, 1}); - - // Image height is larger than copy height (Valid) + // rowsPerImage is larger than copy height (Valid) TestB2TCopy(utils::Expectation::Success, source, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 5, destination, 0, {0, 0, 0}, + {4, 4, 2}); - // Image height is less than copy height (Invalid) + // rowsPerImage is less than copy height (Invalid) TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 3, destination, 0, {0, 0, 0}, {4, 4, 1}); } @@ -580,16 +630,16 @@ TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) { Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // Correct usage - TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, + TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); // Incorrect usages { - TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 5, 256, 0, destination, 0, + TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 5, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); - TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 6, 256, 0, destination, 0, + TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 6, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); - TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 7, 256, 0, destination, 0, + TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 7, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); } } @@ -601,7 +651,7 @@ TEST_F(CopyCommandTest_B2T, CopyToMultisampledTexture) { wgpu::Texture destination = Create2DTexture(2, 2, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst, 4); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, 0, {0, 0, 0}, {2, 2, 1}); } @@ -663,8 +713,8 @@ TEST_F(CopyCommandTest_B2T, TextureCopyBufferSizeLastRowComputation) { wgpu::Buffer source = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopySrc); wgpu::Texture destination = Create2DTexture(kWidth, kHeight, 1, 1, format, wgpu::TextureUsage::CopyDst); - TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, 0, destination, 0, - {0, 0, 0}, {kWidth, kHeight, 1}); + TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, kHeight, destination, + 0, {0, 0, 0}, {kWidth, kHeight, 1}); } } @@ -679,14 +729,14 @@ TEST_F(CopyCommandTest_B2T, TextureCopyBufferSizeLastRowComputation) { { uint32_t invalidBuffferSize = validBufferSize - 1; wgpu::Buffer source = CreateBuffer(invalidBuffferSize, wgpu::BufferUsage::CopySrc); - TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, 0, destination, 0, - {0, 0, 0}, {kWidth, kHeight, 1}); + TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, kHeight, + destination, 0, {0, 0, 0}, {kWidth, kHeight, 1}); } { wgpu::Buffer source = CreateBuffer(validBufferSize, wgpu::BufferUsage::CopySrc); - TestB2TCopy(utils::Expectation::Success, source, 0, kBytesPerRow, 0, destination, 0, - {0, 0, 0}, {kWidth, kHeight, 1}); + TestB2TCopy(utils::Expectation::Success, source, 0, kBytesPerRow, kHeight, + destination, 0, {0, 0, 0}, {kWidth, kHeight, 1}); } } } @@ -701,19 +751,19 @@ TEST_F(CopyCommandTest_B2T, CopyToMipmapOfNonSquareTexture) { 4, 2, maxMipmapLevel, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); // Copy to top level mip map - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, maxMipmapLevel - 1, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1, destination, maxMipmapLevel - 1, {0, 0, 0}, {1, 1, 1}); // Copy to high level mip map - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, maxMipmapLevel - 2, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1, destination, maxMipmapLevel - 2, {0, 0, 0}, {2, 1, 1}); // Mip level out of range - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, maxMipmapLevel, {0, 0, 0}, {1, 1, 1}); // Copy origin out of range - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel - 2, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, maxMipmapLevel - 2, {1, 0, 0}, {2, 1, 1}); // Copy size out of range - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel - 2, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, maxMipmapLevel - 2, {0, 0, 0}, {2, 2, 1}); } @@ -727,10 +777,10 @@ TEST_F(CopyCommandTest_B2T, CopyToDepthAspect) { wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth32Float, wgpu::TextureUsage::CopyDst); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::DepthOnly); } @@ -760,12 +810,12 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { wgpu::Texture destination = Create2DTexture( 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); // And that it fails if the buffer is one byte too small wgpu::Buffer sourceSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopySrc); - TestB2TCopy(utils::Expectation::Failure, sourceSmall, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, sourceSmall, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } @@ -777,7 +827,7 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } @@ -789,7 +839,7 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Uint, wgpu::TextureUsage::CopyDst); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } @@ -802,10 +852,10 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 15, destination, 0, {0, 0, 0}, {15, 15, 1}, wgpu::TextureAspect::StencilOnly); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } @@ -820,14 +870,14 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); // Whole mip is success - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 8, destination, 1, {0, 0, 0}, {8, 8, 1}, wgpu::TextureAspect::StencilOnly); // Partial mip fails - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 7, destination, 1, {0, 0, 0}, {7, 7, 1}, wgpu::TextureAspect::StencilOnly); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 1, {0, 0, 0}, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } @@ -842,14 +892,14 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) { wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); // Whole mip is success - TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Success, source, 0, 256, 8, destination, 1, {0, 0, 0}, {8, 8, 1}, wgpu::TextureAspect::StencilOnly); // Partial mip fails - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 7, destination, 1, {0, 0, 0}, {7, 7, 1}, wgpu::TextureAspect::StencilOnly); - TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, + TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 1, {0, 0, 0}, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } } @@ -880,46 +930,76 @@ TEST_F(CopyCommandTest_T2B, Success) { // Different copies, including some that touch the OOB condition { // Copy from 4x4 block in corner of first mip. - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4, {4, 4, 1}); // Copy from 4x4 block in opposite corner of first mip. - TestT2BCopy(utils::Expectation::Success, source, 0, {12, 12, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {12, 12, 0}, destination, 0, 256, 4, {4, 4, 1}); // Copy from 4x4 block in the 4x4 mip. - TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 0, 256, 4, {4, 4, 1}); // Copy with a buffer offset TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, - 256, 0, {1, 1, 1}); + 256, 1, {1, 1, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, + 256, wgpu::kStrideUndefined, {1, 1, 1}); } // Copies with a 256-byte aligned bytes per row but unaligned texture region { // Unaligned region - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4, {3, 4, 1}); // Unaligned region with texture offset - TestT2BCopy(utils::Expectation::Success, source, 0, {5, 7, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {5, 7, 0}, destination, 0, 256, 3, {2, 3, 1}); // Unaligned region, with buffer offset - TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 31 * 4, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 31 * 4, 256, 3, {3, 3, 1}); } + // bytesPerRow is undefined + { + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 2, {1, 1, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 2, {3, 1, 1}); + // Fail because height or depth is greater than 1: + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 2, {1, 2, 1}); + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 2, {1, 1, 2}); + } + // Empty copies are valid { // An empty copy TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, {0, 0, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 0, {0, 0, 1}); // An empty copy with depth = 0 TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, {0, 0, 0}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + wgpu::kStrideUndefined, 0, {0, 0, 0}); // An empty copy touching the end of the buffer TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize, 0, 0, {0, 0, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize, + wgpu::kStrideUndefined, 0, {0, 0, 1}); // An empty copy touching the side of the texture TestT2BCopy(utils::Expectation::Success, source, 0, {16, 16, 0}, destination, 0, 0, 0, {0, 0, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {16, 16, 0}, destination, 0, + wgpu::kStrideUndefined, 0, {0, 0, 1}); + + // An empty copy with depth = 1 and bytesPerRow > 0 + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + kTextureBytesPerRowAlignment, 0, {0, 0, 1}); + // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0 + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, + kTextureBytesPerRowAlignment, 3, {0, 1, 0}); } } @@ -959,19 +1039,19 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) { wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); // OOB on the texture because x + width overflows - TestT2BCopy(utils::Expectation::Failure, source, 0, {13, 12, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {13, 12, 0}, destination, 0, 256, 4, {4, 4, 1}); // OOB on the texture because y + width overflows - TestT2BCopy(utils::Expectation::Failure, source, 0, {12, 13, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {12, 13, 0}, destination, 0, 256, 4, {4, 4, 1}); // OOB on the texture because we overflow a non-zero mip - TestT2BCopy(utils::Expectation::Failure, source, 2, {1, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 2, {1, 0, 0}, destination, 0, 256, 4, {4, 4, 1}); // OOB on the texture even on an empty copy when we copy from a non-existent mip. - TestT2BCopy(utils::Expectation::Failure, source, 5, {0, 0, 0}, destination, 0, 0, 0, {0, 0, 1}); + TestT2BCopy(utils::Expectation::Failure, source, 5, {0, 0, 0}, destination, 0, 0, 4, {0, 0, 1}); } // Test OOB conditions on the buffer @@ -982,16 +1062,16 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) { wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); // OOB on the buffer because we copy too many pixels - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 5, {4, 5, 1}); // OOB on the buffer because of the offset - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 4, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 4, 256, 4, {4, 4, 1}); // OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth // overflows - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 512, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 512, 3, {4, 3, 1}); // Not OOB on the buffer although bytes per row * height overflows @@ -1002,7 +1082,7 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) { << "bytes per row * height should overflow buffer"; wgpu::Buffer destinationBuffer = CreateBuffer(destinationBufferSize, wgpu::BufferUsage::CopyDst); - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destinationBuffer, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destinationBuffer, 0, 256, 3, {7, 3, 1}); } } @@ -1029,80 +1109,106 @@ TEST_F(CopyCommandTest_T2B, IncorrectUsage) { wgpu::Buffer vertex = CreateBuffer(bufferSize, wgpu::BufferUsage::Vertex); // Incorrect source usage - TestT2BCopy(utils::Expectation::Failure, sampled, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, sampled, 0, {0, 0, 0}, destination, 0, 256, 4, {4, 4, 1}); // Incorrect destination usage - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, vertex, 0, 256, 0, {4, 4, 1}); + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, vertex, 0, 256, 4, {4, 4, 1}); } -TEST_F(CopyCommandTest_T2B, IncorrectBytesPerRow) { +TEST_F(CopyCommandTest_T2B, BytesPerRowConstraints) { uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); - wgpu::Texture source = Create2DTexture(128, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, + wgpu::Texture source = Create2DTexture(128, 16, 5, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); // bytes per row is 0 { // copyHeight > 1 - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 4, {64, 4, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 4, + {0, 4, 1}); // copyDepth > 1 TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 1, {64, 1, 4}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 1, + {0, 1, 4}); // copyHeight = 1 and copyDepth = 1 - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, - {64, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, + destination, 0, 0, 1, {64, 1, 1})); } // bytes per row is not 256-byte aligned { // copyHeight > 1 - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 4, {4, 4, 1}); // copyHeight = 1 and copyDepth = 1 - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 1, {4, 1, 1}); } // bytes per row is less than width * bytesPerPixel { // copyHeight > 1 - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 2, {65, 2, 1}); + // copyHeight == 0 + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + {65, 0, 1}); // copyDepth > 1 TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1, {65, 1, 2}); + // copyDepth == 0 + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1, + {65, 1, 0}); // copyHeight = 1 and copyDepth = 1 - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, - {65, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, + destination, 0, 256, 1, {65, 1, 1})); } } -TEST_F(CopyCommandTest_T2B, ImageHeightConstraint) { - uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 1); +TEST_F(CopyCommandTest_T2B, RowsPerImageConstraints) { + uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 6); wgpu::Texture source = - Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); + Create2DTexture(16, 16, 1, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); - // Image height is zero (Valid) - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, - {4, 4, 1}); + // rowsPerImage is zero (Valid) + // TODO(crbug.com/dawn/520): Change to ::Failure. + EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, + destination, 0, 256, 0, {1, 1, 1})); + EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, + destination, 0, 256, 0, {4, 4, 1})); - // Image height is equal to copy height (Valid) + // rowsPerImage is undefined + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, + wgpu::kStrideUndefined, {4, 4, 1}); + // Fail because depth > 1: + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, + wgpu::kStrideUndefined, {4, 4, 2}); + + // rowsPerImage is equal to copy height (Valid) TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4, {4, 4, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4, + {4, 4, 2}); - // Image height exceeds copy height (Valid) + // rowsPerImage exceeds copy height (Valid) TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 5, {4, 4, 1}); + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 5, + {4, 4, 2}); - // Image height is less than copy height (Invalid) + // rowsPerImage is less than copy height (Invalid) TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 3, {4, 4, 1}); } @@ -1116,15 +1222,15 @@ TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) { // Correct usage TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, 256, - 0, {1, 1, 1}); + 1, {1, 1, 1}); // Incorrect usages TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 5, 256, - 0, {1, 1, 1}); + 1, {1, 1, 1}); TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 6, 256, - 0, {1, 1, 1}); + 1, {1, 1, 1}); TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 7, 256, - 0, {1, 1, 1}); + 1, {1, 1, 1}); } // Test multisampled textures cannot be used in T2B copies. @@ -1134,7 +1240,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromMultisampledTexture) { uint64_t bufferSize = BufferSizeForTextureCopy(16, 16, 1); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 2, {2, 2, 1}); } @@ -1198,7 +1304,7 @@ TEST_F(CopyCommandTest_T2B, TextureCopyBufferSizeLastRowComputation) { wgpu::Buffer destination = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopyDst); TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, - kBytesPerRow, 0, {kWidth, kHeight, 1}); + kBytesPerRow, kHeight, {kWidth, kHeight, 1}); } } @@ -1215,14 +1321,14 @@ TEST_F(CopyCommandTest_T2B, TextureCopyBufferSizeLastRowComputation) { wgpu::Buffer destination = CreateBuffer(invalidBufferSize, wgpu::BufferUsage::CopyDst); TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, - kBytesPerRow, 0, {kWidth, kHeight, 1}); + kBytesPerRow, kHeight, {kWidth, kHeight, 1}); } { wgpu::Buffer destination = CreateBuffer(validBufferSize, wgpu::BufferUsage::CopyDst); TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, - kBytesPerRow, 0, {kWidth, kHeight, 1}); + kBytesPerRow, kHeight, {kWidth, kHeight, 1}); } } } @@ -1238,19 +1344,19 @@ TEST_F(CopyCommandTest_T2B, CopyFromMipmapOfNonSquareTexture) { // Copy from top level mip map TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 1, {0, 0, 0}, destination, 0, - 256, 0, {1, 1, 1}); + 256, 1, {1, 1, 1}); // Copy from high level mip map TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 2, {0, 0, 0}, destination, 0, - 256, 0, {2, 1, 1}); + 256, 1, {2, 1, 1}); // Mip level out of range TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel, {0, 0, 0}, destination, 0, 256, - 0, {2, 1, 1}); + 1, {2, 1, 1}); // Copy origin out of range TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {2, 0, 0}, destination, 0, - 256, 0, {2, 1, 1}); + 256, 1, {2, 1, 1}); // Copy size out of range TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {1, 0, 0}, destination, 0, - 256, 0, {2, 1, 1}); + 256, 1, {2, 1, 1}); } // Test copy from only the depth aspect of a texture @@ -1262,11 +1368,11 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) { wgpu::TextureUsage::CopySrc); // Test "all" of a depth texture which is only the depth aspect. - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::All); // Test it is valid to copy the depth aspect of a depth texture - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::DepthOnly); } { @@ -1274,7 +1380,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) { wgpu::TextureUsage::CopySrc); // Test it is invalid to copy from the depth aspect of depth24plus - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::DepthOnly); } { @@ -1282,7 +1388,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) { 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); // Test it is invalid to copy from the depth aspect of depth24plus-stencil8 - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::DepthOnly); } { @@ -1290,7 +1396,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) { wgpu::TextureUsage::CopySrc); // Test it is invalid to copy from the depth aspect of a color texture - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::DepthOnly); } } @@ -1304,12 +1410,12 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); // Test it is valid to copy from the stencil aspect of a depth24plus-stencil8 texture - TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); // Test it is invalid if the buffer is too small wgpu::Buffer destinationSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopyDst); - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destinationSmall, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destinationSmall, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } { @@ -1317,7 +1423,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::R8Uint, wgpu::TextureUsage::CopySrc); // Test it is invalid to copy from the stencil aspect of a color texture - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } { @@ -1325,7 +1431,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { wgpu::TextureUsage::CopySrc); // Test it is invalid to copy from the stencil aspect of a depth-only texture - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16, {16, 16, 1}, wgpu::TextureAspect::StencilOnly); } @@ -1335,10 +1441,10 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { wgpu::Texture source = Create2DTexture( 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 15, {15, 15, 1}, wgpu::TextureAspect::StencilOnly); - TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } @@ -1349,14 +1455,14 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { 16, 16, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); // Whole mip is success - TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 8, {8, 8, 1}, wgpu::TextureAspect::StencilOnly); // Partial mip fails - TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 7, {7, 7, 1}, wgpu::TextureAspect::StencilOnly); - TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 1, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } @@ -1367,14 +1473,14 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) { 17, 17, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); // Whole mip is success - TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 8, {8, 8, 1}, wgpu::TextureAspect::StencilOnly); // Partial mip fails - TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 7, {7, 7, 1}, wgpu::TextureAspect::StencilOnly); - TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, + TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 1, {1, 1, 1}, wgpu::TextureAspect::StencilOnly); } } diff --git a/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp b/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp index 8cb7bc536b..b3c339dedf 100644 --- a/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp +++ b/src/tests/unittests/validation/QueueWriteTextureValidationTests.cpp @@ -99,38 +99,53 @@ namespace { // Different copies, including some that touch the OOB condition { // Copy 4x4 block in corner of first mip. - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}); + TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); // Copy 4x4 block in opposite corner of first mip. - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {12, 12, 0}, {4, 4, 1}); + TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {12, 12, 0}, {4, 4, 1}); // Copy 4x4 block in the 4x4 mip. - TestWriteTexture(dataSize, 0, 256, 0, destination, 2, {0, 0, 0}, {4, 4, 1}); + TestWriteTexture(dataSize, 0, 256, 4, destination, 2, {0, 0, 0}, {4, 4, 1}); // Copy with a data offset - TestWriteTexture(dataSize, dataSize - 4, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); + TestWriteTexture(dataSize, dataSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); + TestWriteTexture(dataSize, dataSize - 4, 256, wgpu::kStrideUndefined, destination, 0, + {0, 0, 0}, {1, 1, 1}); } // Copies with a 256-byte aligned bytes per row but unaligned texture region { // Unaligned region - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {3, 4, 1}); + TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {3, 4, 1}); // Unaligned region with texture offset - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {5, 7, 0}, {2, 3, 1}); + TestWriteTexture(dataSize, 0, 256, 3, destination, 0, {5, 7, 0}, {2, 3, 1}); // Unaligned region, with data offset - TestWriteTexture(dataSize, 31 * 4, 256, 0, destination, 0, {0, 0, 0}, {3, 3, 1}); + TestWriteTexture(dataSize, 31 * 4, 256, 3, destination, 0, {0, 0, 0}, {3, 3, 1}); } // Empty copies are valid { // An empty copy TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); + TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, + {0, 0, 1}); // An empty copy with depth = 0 TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 0}); + TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, + {0, 0, 0}); // An empty copy touching the end of the data TestWriteTexture(dataSize, dataSize, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); + TestWriteTexture(dataSize, dataSize, 0, wgpu::kStrideUndefined, destination, 0, + {0, 0, 0}, {0, 0, 1}); // An empty copy touching the side of the texture TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {16, 16, 0}, {0, 0, 1}); + TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {16, 16, 0}, + {0, 0, 1}); // An empty copy with depth = 1 and bytesPerRow > 0 TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); + TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, + {0, 0, 1}); // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0 + TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, + {0, 1, 0}); + TestWriteTexture(dataSize, 0, 256, 1, destination, 0, {0, 0, 0}, {0, 1, 0}); TestWriteTexture(dataSize, 0, 256, 16, destination, 0, {0, 0, 0}, {0, 1, 0}); } } @@ -144,15 +159,15 @@ namespace { // OOB on the data because we copy too many pixels ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 5, 1})); + TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 5, 1})); // OOB on the data because of the offset ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 4, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1})); + TestWriteTexture(dataSize, 4, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1})); // OOB on the data because utils::RequiredBytesInCopy overflows ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 512, 0, destination, 0, {0, 0, 0}, {4, 3, 1})); + TestWriteTexture(dataSize, 0, 512, 3, destination, 0, {0, 0, 0}, {4, 3, 1})); // Not OOB on the data although bytes per row * height overflows // but utils::RequiredBytesInCopy * depth does not overflow @@ -161,7 +176,7 @@ namespace { utils::RequiredBytesInCopy(256, 0, {7, 3, 1}, wgpu::TextureFormat::RGBA8Unorm); ASSERT_TRUE(256 * 3 > sourceDataSize) << "bytes per row * height should overflow data"; - TestWriteTexture(sourceDataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {7, 3, 1}); + TestWriteTexture(sourceDataSize, 0, 256, 3, destination, 0, {0, 0, 0}, {7, 3, 1}); } } @@ -174,15 +189,15 @@ namespace { // OOB on the texture because x + width overflows ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {13, 12, 0}, {4, 4, 1})); + TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {13, 12, 0}, {4, 4, 1})); // OOB on the texture because y + width overflows ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {12, 13, 0}, {4, 4, 1})); + TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {12, 13, 0}, {4, 4, 1})); // OOB on the texture because we overflow a non-zero mip ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, destination, 2, {1, 0, 0}, {4, 4, 1})); + TestWriteTexture(dataSize, 0, 256, 4, destination, 2, {1, 0, 0}, {4, 4, 1})); // OOB on the texture even on an empty copy when we copy to a non-existent mip. ASSERT_DEVICE_ERROR( @@ -214,68 +229,91 @@ namespace { // Incorrect destination usage ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, sampled, 0, {0, 0, 0}, {4, 4, 1})); + TestWriteTexture(dataSize, 0, 256, 4, sampled, 0, {0, 0, 0}, {4, 4, 1})); } // Test incorrect values of bytesPerRow and that values not divisible by 256 are allowed. - TEST_F(QueueWriteTextureValidationTest, BytesPerRowLimitations) { - wgpu::Texture destination = Create2DTexture({3, 7, 1}, 1, wgpu::TextureFormat::RGBA8Unorm, + TEST_F(QueueWriteTextureValidationTest, BytesPerRowConstraints) { + wgpu::Texture destination = Create2DTexture({3, 7, 2}, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); - // bytesPerRow = 0 + // bytesPerRow = 0 or wgpu::kStrideUndefined { // copyHeight > 1 ASSERT_DEVICE_ERROR( - TestWriteTexture(128, 0, 0, 0, destination, 0, {0, 0, 0}, {3, 7, 1})); + TestWriteTexture(128, 0, 0, 7, destination, 0, {0, 0, 0}, {3, 7, 1})); + TestWriteTexture(128, 0, 0, 7, destination, 0, {0, 0, 0}, {0, 7, 1}); + ASSERT_DEVICE_ERROR(TestWriteTexture(128, 0, wgpu::kStrideUndefined, 7, destination, 0, + {0, 0, 0}, {0, 7, 1})); // copyDepth > 1 ASSERT_DEVICE_ERROR( TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {3, 1, 2})); + TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {0, 1, 2}); + ASSERT_DEVICE_ERROR(TestWriteTexture(128, 0, wgpu::kStrideUndefined, 1, destination, 0, + {0, 0, 0}, {0, 1, 2})); // copyHeight = 1 and copyDepth = 1 - TestWriteTexture(128, 0, 0, 0, destination, 0, {0, 0, 0}, {3, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ASSERT_DEVICE_ERROR. + EXPECT_DEPRECATION_WARNING( + TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {3, 1, 1})); + TestWriteTexture(128, 0, wgpu::kStrideUndefined, 1, destination, 0, {0, 0, 0}, + {3, 1, 1}); } // bytesPerRow = 11 is invalid since a row takes 12 bytes. { // copyHeight > 1 ASSERT_DEVICE_ERROR( - TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 7, 1})); + TestWriteTexture(128, 0, 11, 7, destination, 0, {0, 0, 0}, {3, 7, 1})); + // copyHeight == 0 + ASSERT_DEVICE_ERROR( + TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 0, 1})); // copyDepth > 1 ASSERT_DEVICE_ERROR( TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 2})); + // copyDepth == 0 + ASSERT_DEVICE_ERROR( + TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 0})); // copyHeight = 1 and copyDepth = 1 - TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 1, 1}); + // TODO(crbug.com/dawn/520): Change to ASSERT_DEVICE_ERROR. bytesPerRow used to be only + // validated if height > 1 || depth > 1. + EXPECT_DEPRECATION_WARNING( + TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 1})); } // bytesPerRow = 12 is valid since a row takes 12 bytes. - TestWriteTexture(128, 0, 12, 0, destination, 0, {0, 0, 0}, {3, 7, 1}); + TestWriteTexture(128, 0, 12, 7, destination, 0, {0, 0, 0}, {3, 7, 1}); // bytesPerRow = 13 is valid since a row takes 12 bytes. - TestWriteTexture(128, 0, 13, 0, destination, 0, {0, 0, 0}, {3, 7, 1}); + TestWriteTexture(128, 0, 13, 7, destination, 0, {0, 0, 0}, {3, 7, 1}); } // Test that if rowsPerImage is greater than 0, it must be at least copy height. - TEST_F(QueueWriteTextureValidationTest, ImageHeightConstraint) { + TEST_F(QueueWriteTextureValidationTest, RowsPerImageConstraints) { uint64_t dataSize = - utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm); - wgpu::Texture destination = Create2DTexture({16, 16, 1}, 1, wgpu::TextureFormat::RGBA8Unorm, + utils::RequiredBytesInCopy(256, 5, {4, 4, 2}, wgpu::TextureFormat::RGBA8Unorm); + wgpu::Texture destination = Create2DTexture({16, 16, 2}, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); - // Image height is zero (Valid) - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}); + // rowsPerImage is wgpu::kStrideUndefined + TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, + {4, 4, 1}); - // Image height is equal to copy height (Valid) + // rowsPerImage is equal to copy height (Valid) TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); - // Image height is larger than copy height (Valid) + // rowsPerImage is larger than copy height (Valid) TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 1}); + TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 2}); - // Image height is less than copy height (Invalid) + // rowsPerImage is less than copy height (Invalid) ASSERT_DEVICE_ERROR( TestWriteTexture(dataSize, 0, 256, 3, destination, 0, {0, 0, 0}, {4, 4, 1})); + EXPECT_DEPRECATION_WARNING( + TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1})); } // Test WriteTexture with data offset @@ -286,12 +324,12 @@ namespace { wgpu::TextureUsage::CopyDst); // Offset aligned - TestWriteTexture(dataSize, dataSize - 4, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); + TestWriteTexture(dataSize, dataSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); // Offset not aligned - TestWriteTexture(dataSize, dataSize - 5, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); + TestWriteTexture(dataSize, dataSize - 5, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}); // Offset+size too large ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, dataSize - 3, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1})); + TestWriteTexture(dataSize, dataSize - 3, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1})); } // Test multisampled textures can be used in WriteTexture. @@ -302,7 +340,7 @@ namespace { wgpu::TextureUsage::CopyDst, 4); ASSERT_DEVICE_ERROR( - TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {2, 2, 1})); + TestWriteTexture(dataSize, 0, 256, 2, destination, 0, {0, 0, 0}, {2, 2, 1})); } // Test that WriteTexture cannot be run with a destroyed texture. @@ -366,7 +404,7 @@ namespace { for (wgpu::TextureFormat format : kFormats) { wgpu::Texture destination = Create2DTexture({kWidth, kHeight, 1}, 1, format, wgpu::TextureUsage::CopyDst); - ASSERT_DEVICE_ERROR(TestWriteTexture(kInvalidDataSize, 0, kBytesPerRow, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(kInvalidDataSize, 0, kBytesPerRow, kHeight, destination, 0, {0, 0, 0}, {kWidth, kHeight, 1})); } @@ -383,14 +421,14 @@ namespace { // data size in this test. { uint32_t invalidDataSize = validDataSize - 1; - ASSERT_DEVICE_ERROR(TestWriteTexture(invalidDataSize, 0, kBytesPerRow, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(invalidDataSize, 0, kBytesPerRow, kHeight, destination, 0, {0, 0, 0}, {kWidth, kHeight, 1})); } { - TestWriteTexture(validDataSize, 0, kBytesPerRow, 0, destination, 0, {0, 0, 0}, - {kWidth, kHeight, 1}); + TestWriteTexture(validDataSize, 0, kBytesPerRow, kHeight, destination, 0, + {0, 0, 0}, {kWidth, kHeight, 1}); } } } @@ -406,19 +444,19 @@ namespace { wgpu::TextureUsage::CopyDst); // Copy to top level mip map - TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 1, {0, 0, 0}, + TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 1, {0, 0, 0}, {1, 1, 1}); // Copy to high level mip map - TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, {0, 0, 0}, + TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 2, {0, 0, 0}, {2, 1, 1}); // Mip level out of range - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel, {0, 0, 0}, {1, 1, 1})); // Copy origin out of range - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 2, {1, 0, 0}, {2, 1, 1})); // Copy size out of range - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 2, destination, maxMipmapLevel - 2, {0, 0, 0}, {2, 2, 1})); } @@ -460,10 +498,10 @@ namespace { wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( {4, 4, 1}, 1, wgpu::TextureFormat::Depth32Float, wgpu::TextureUsage::CopyDst); - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All)); - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::DepthOnly)); } @@ -473,10 +511,10 @@ namespace { wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( {4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst); - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All)); - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::DepthOnly)); } @@ -494,16 +532,16 @@ namespace { {4, 4, 1}, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); - TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, {0, 0, 0}, {4, 4, 1}, - wgpu::TextureAspect::StencilOnly); + TestWriteTexture(dataSize, 0, bytesPerRow, wgpu::kStrideUndefined, destination, 0, + {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::StencilOnly); // And that it fails if the buffer is one byte too small - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize - 1, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize - 1, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::StencilOnly)); // It is invalid to write just part of the subresource size - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 3, destination, 0, {0, 0, 0}, {3, 3, 1}, wgpu::TextureAspect::StencilOnly)); } @@ -513,7 +551,7 @@ namespace { wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( {4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst); - ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, + ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0, {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::StencilOnly)); } @@ -608,14 +646,14 @@ namespace { // Valid usage of bytesPerRow in WriteTexture with compressed texture formats. { constexpr uint32_t kValidBytesPerRow = 20; - TestWriteTexture(512, 0, kValidBytesPerRow, 0, texture, 0, {0, 0, 0}, {4, 4, 1}); + TestWriteTexture(512, 0, kValidBytesPerRow, 4, texture, 0, {0, 0, 0}, {4, 4, 1}); } // Valid bytesPerRow. // Note that image width is not a multiple of blockWidth. { constexpr uint32_t kValidBytesPerRow = 17; - TestWriteTexture(512, 0, kValidBytesPerRow, 0, texture, 0, {0, 0, 0}, {4, 4, 1}); + TestWriteTexture(512, 0, kValidBytesPerRow, 4, texture, 0, {0, 0, 0}, {4, 4, 1}); } } } diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp index 529c86e6a6..6f68696577 100644 --- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp +++ b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp @@ -533,7 +533,7 @@ namespace dawn_native { namespace vulkan { // Copy |deviceWrappedTexture| into |copyDstBuffer| wgpu::TextureCopyView copySrc = utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0}); - wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256, 0); + wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256); wgpu::Extent3D copySize = {1, 1, 1}; @@ -585,7 +585,7 @@ namespace dawn_native { namespace vulkan { utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); // Copy |copySrcBuffer| into |secondDeviceWrappedTexture| - wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256, 0); + wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256); wgpu::TextureCopyView copyDst = utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0}); @@ -817,7 +817,7 @@ namespace dawn_native { namespace vulkan { wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView copySrc = - utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow, 0); + utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow); wgpu::TextureCopyView copyDst = utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {width, height, 1}; @@ -846,7 +846,7 @@ namespace dawn_native { namespace vulkan { wgpu::TextureCopyView copySrc = utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0}); wgpu::BufferCopyView copyDst = - utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow, 0); + utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow); wgpu::Extent3D copySize = {width, height, 1}; diff --git a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp index a01a86369f..5eb1eb6da0 100644 --- a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp +++ b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp @@ -667,7 +667,7 @@ namespace dawn_native { namespace vulkan { // Copy |deviceWrappedTexture| into |copyDstBuffer| wgpu::TextureCopyView copySrc = utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0}); - wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256, 0); + wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256); wgpu::Extent3D copySize = {1, 1, 1}; @@ -721,7 +721,7 @@ namespace dawn_native { namespace vulkan { utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); // Copy |copySrcBuffer| into |secondDeviceWrappedTexture| - wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256, 0); + wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256); wgpu::TextureCopyView copyDst = utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0}); @@ -980,7 +980,7 @@ namespace dawn_native { namespace vulkan { wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView copySrc = - utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow, 0); + utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow); wgpu::TextureCopyView copyDst = utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0}); wgpu::Extent3D copySize = {width, height, 1}; @@ -1012,7 +1012,7 @@ namespace dawn_native { namespace vulkan { wgpu::TextureCopyView copySrc = utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0}); wgpu::BufferCopyView copyDst = - utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow, 0); + utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow); wgpu::Extent3D copySize = {width, height, 1}; diff --git a/src/utils/TestUtils.cpp b/src/utils/TestUtils.cpp index ae36ecc388..e5487d3667 100644 --- a/src/utils/TestUtils.cpp +++ b/src/utils/TestUtils.cpp @@ -44,8 +44,12 @@ namespace utils { layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width); - uint32_t appliedRowsPerImage = rowsPerImage > 0 ? rowsPerImage : layout.mipSize.height; - layout.bytesPerImage = layout.bytesPerRow * appliedRowsPerImage; + if (rowsPerImage == wgpu::kStrideUndefined) { + rowsPerImage = layout.mipSize.height; + } + layout.rowsPerImage = rowsPerImage; + + layout.bytesPerImage = layout.bytesPerRow * rowsPerImage; // TODO(kainino@chromium.org): Remove this intermediate variable. // It is currently needed because of an issue in the D3D12 copy splitter @@ -54,9 +58,9 @@ namespace utils { // the actual height. wgpu::Extent3D mipSizeWithHeightWorkaround = layout.mipSize; mipSizeWithHeightWorkaround.height = - appliedRowsPerImage * utils::GetTextureFormatBlockHeight(format); + rowsPerImage * utils::GetTextureFormatBlockHeight(format); - layout.byteLength = RequiredBytesInCopy(layout.bytesPerRow, appliedRowsPerImage, + layout.byteLength = RequiredBytesInCopy(layout.bytesPerRow, rowsPerImage, mipSizeWithHeightWorkaround, format); const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); @@ -120,7 +124,8 @@ namespace utils { wgpu::Texture texture = device.CreateTexture(&descriptor); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); - wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(0, 0, 0); + wgpu::TextureDataLayout textureDataLayout = + utils::CreateTextureDataLayout(0, wgpu::kStrideUndefined); wgpu::Extent3D copyExtent = {1, 1, 1}; // WriteTexture with exactly 1 byte of data. diff --git a/src/utils/TestUtils.h b/src/utils/TestUtils.h index 1b2e0e016f..d4ecb57114 100644 --- a/src/utils/TestUtils.h +++ b/src/utils/TestUtils.h @@ -23,6 +23,7 @@ namespace utils { uint64_t byteLength; uint64_t texelBlockCount; uint32_t bytesPerRow; + uint32_t rowsPerImage; uint32_t texelBlocksPerRow; uint32_t bytesPerImage; uint32_t texelBlocksPerImage; @@ -34,7 +35,7 @@ namespace utils { wgpu::TextureFormat format, wgpu::Extent3D textureSizeAtLevel0, uint32_t mipmapLevel, - uint32_t rowsPerImage); + uint32_t rowsPerImage = wgpu::kStrideUndefined); uint64_t RequiredBytesInCopy(uint64_t bytesPerRow, uint64_t rowsPerImage, diff --git a/src/utils/WGPUHelpers.h b/src/utils/WGPUHelpers.h index b77b6a438b..16d2be4f49 100644 --- a/src/utils/WGPUHelpers.h +++ b/src/utils/WGPUHelpers.h @@ -53,7 +53,7 @@ namespace utils { wgpu::BufferCopyView CreateBufferCopyView(wgpu::Buffer buffer, uint64_t offset, uint32_t bytesPerRow, - uint32_t rowsPerImage); + uint32_t rowsPerImage = wgpu::kStrideUndefined); wgpu::TextureCopyView CreateTextureCopyView( wgpu::Texture texture, uint32_t level, @@ -61,7 +61,7 @@ namespace utils { wgpu::TextureAspect aspect = wgpu::TextureAspect::All); wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset, uint32_t bytesPerRow, - uint32_t rowsPerImage); + uint32_t rowsPerImage = wgpu::kStrideUndefined); struct ComboRenderPassDescriptor : public wgpu::RenderPassDescriptor { public: