From 59cfe3ea033ac67d67b6175140ac9a29cb75160e Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Tue, 16 Jun 2020 12:26:38 +0000 Subject: [PATCH] Clean up CopyTests This patch does several clean-ups in CopyTests as a preparation of supporting buffer-to-texture and texture-to-buffer copies with multiple texture array layers. 1. Remove the zero-initialization of textures in CopyTests_B2T 2. Use a big buffer that contains the pixel data in all the texture array layers instead of several small ones that only contains one texture array layer. 3. Make CopyTests_T2T::DoTest() also use CopyTests::TextureSpec as its input parameter. 4. Add tests for the copies with multiple texture array layers. In this patch we just copy the data once per texture array layer, while in the next patch we will be able to copy the data for all the related texture array layers in one copy command. 5. Move some helper functions for copy tests to WGPUHelpers.cpp BUG=dawn:453 TEST=dawn_end2end_tests Change-Id: Ia0150a6c55fffce3e24dda2cd45fd920b0873dc9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23120 Commit-Queue: Corentin Wallez Reviewed-by: Austin Eng --- src/tests/end2end/CopyTests.cpp | 1049 ++++++++++++++++++++++--------- src/utils/WGPUHelpers.cpp | 42 ++ src/utils/WGPUHelpers.h | 22 + 3 files changed, 802 insertions(+), 311 deletions(-) diff --git a/src/tests/end2end/CopyTests.cpp b/src/tests/end2end/CopyTests.cpp index 857faa0a68..4b98414c7f 100644 --- a/src/tests/end2end/CopyTests.cpp +++ b/src/tests/end2end/CopyTests.cpp @@ -17,22 +17,18 @@ #include #include "common/Constants.h" #include "common/Math.h" +#include "utils/TextureFormatUtils.h" #include "utils/WGPUHelpers.h" class CopyTests : public DawnTest { protected: - static constexpr unsigned int kBytesPerTexel = 4; + static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; - struct TextureSpec { - uint32_t width; - uint32_t height; - uint32_t x; - uint32_t y; - uint32_t copyWidth; - uint32_t copyHeight; - uint32_t level; - uint32_t arraySize = 1u; - }; + struct TextureSpec { + wgpu::Origin3D copyOrigin; + wgpu::Extent3D textureSize; + uint32_t level; + }; struct BufferSpec { uint64_t size; @@ -40,24 +36,32 @@ class CopyTests : public DawnTest { uint32_t bytesPerRow; }; - static void FillTextureData(uint32_t width, - uint32_t height, - uint32_t texelsPerRow, - uint32_t layer, - RGBA8* data) { - for (uint32_t y = 0; y < height; ++y) { - for (uint32_t x = 0; x < width; ++x) { - uint32_t i = x + y * texelsPerRow; - data[i] = RGBA8(static_cast((x + layer * x) % 256), - static_cast((y + layer * y) % 256), - static_cast(x / 256), static_cast(y / 256)); + static std::vector GetExpectedTextureData( + const utils::BufferTextureCopyLayout& layout) { + std::vector textureData(layout.texelBlockCount); + for (uint32_t layer = 0; layer < layout.mipSize.depth; ++layer) { + const uint32_t texelIndexOffsetPerSlice = layout.texelBlocksPerImage * layer; + for (uint32_t y = 0; y < layout.mipSize.height; ++y) { + for (uint32_t x = 0; x < layout.mipSize.width; ++x) { + uint32_t i = x + y * layout.texelBlocksPerRow; + textureData[texelIndexOffsetPerSlice + i] = + RGBA8(static_cast((x + layer * x) % 256), + static_cast((y + layer * y) % 256), + static_cast(x / 256), static_cast(y / 256)); + } } } + + return textureData; } - BufferSpec MinimumBufferSpec(uint32_t width, uint32_t height) { - uint32_t bytesPerRow = Align(width * kBytesPerTexel, kTextureBytesPerRowAlignment); - return {bytesPerRow * (height - 1) + width * kBytesPerTexel, 0, bytesPerRow}; + static BufferSpec MinimumBufferSpec(uint32_t width, + uint32_t height, + uint32_t arrayLayer = 1) { + const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, width); + const uint32_t totalBufferSize = utils::GetBytesInBufferTextureCopy( + kTextureFormat, width, bytesPerRow, height, arrayLayer); + return {totalBufferSize, 0, bytesPerRow}; } static void PackTextureData(const RGBA8* srcData, uint32_t width, uint32_t height, uint32_t srcTexelsPerRow, RGBA8* dstData, uint32_t dstTexelsPerRow) { @@ -73,104 +77,110 @@ class CopyTests : public DawnTest { class CopyTests_T2B : public CopyTests { protected: + void DoTest(const TextureSpec& textureSpec, + const BufferSpec& bufferSpec, + const wgpu::Extent3D& copySize) { + // Create a texture that is `width` x `height` with (`level` + 1) mip levels. + wgpu::TextureDescriptor descriptor; + descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.size = textureSpec.textureSize; + descriptor.sampleCount = 1; + descriptor.format = kTextureFormat; + descriptor.mipLevelCount = textureSpec.level + 1; + descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; + wgpu::Texture texture = device.CreateTexture(&descriptor); - void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) { - // Create a texture that is `width` x `height` with (`level` + 1) mip levels. - wgpu::TextureDescriptor descriptor; - descriptor.dimension = wgpu::TextureDimension::e2D; - descriptor.size.width = textureSpec.width; - descriptor.size.height = textureSpec.height; - descriptor.size.depth = textureSpec.arraySize; - descriptor.sampleCount = 1; - descriptor.format = wgpu::TextureFormat::RGBA8Unorm; - descriptor.mipLevelCount = textureSpec.level + 1; - descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; - wgpu::Texture texture = device.CreateTexture(&descriptor); + const uint32_t rowsPerImage = textureSpec.textureSize.height >> textureSpec.level; + const utils::BufferTextureCopyLayout copyLayout = + utils::GetBufferTextureCopyLayoutForTexture2DAtLevel( + kTextureFormat, textureSpec.textureSize, textureSpec.level, rowsPerImage); - uint32_t width = textureSpec.width >> textureSpec.level; - uint32_t height = textureSpec.height >> textureSpec.level; - uint32_t bytesPerRow = Align(kBytesPerTexel * width, kTextureBytesPerRowAlignment); - uint32_t texelsPerRow = bytesPerRow / kBytesPerTexel; - uint32_t texelCountPerLayer = texelsPerRow * (height - 1) + width; + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + // Initialize the source texture + std::vector textureArrayData = GetExpectedTextureData(copyLayout); - std::vector> textureArrayData(textureSpec.arraySize); - for (uint32_t slice = 0; slice < textureSpec.arraySize; ++slice) { - textureArrayData[slice].resize(texelCountPerLayer); - FillTextureData(width, height, bytesPerRow / kBytesPerTexel, slice, - textureArrayData[slice].data()); + // TODO(jiawei.shao@intel.com): copy into multiple texture array layers in one + // buffer-to-texture copy command. + wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( + device, textureArrayData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); + uint64_t uploadBufferOffset = 0; + for (uint32_t slice = 0; slice < textureSpec.textureSize.depth; ++slice) { + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( + uploadBuffer, uploadBufferOffset, copyLayout.bytesPerRow, 0); + wgpu::TextureCopyView textureCopyView = + utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, slice}); + wgpu::Extent3D copyOneLayerSize = {copyLayout.mipSize.width, + copyLayout.mipSize.height, 1}; + encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©OneLayerSize); + uploadBufferOffset += copyLayout.bytesPerImage; + } - // Create an upload buffer and use it to populate the current slice of the texture in `level` mip level - wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( - device, textureArrayData[slice].data(), - static_cast(sizeof(RGBA8) * textureArrayData[slice].size()), - wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, bytesPerRow, 0); - wgpu::TextureCopyView textureCopyView = - utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, slice}); - wgpu::Extent3D copySize = {width, height, 1}; - encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); - } + // Create a buffer of `size` and populate it with empty data (0,0,0,0) Note: + // Prepopulating the buffer with empty data ensures that there is not random data in the + // expectation and helps ensure that the padding due to the bytes per row is not modified + // by the copy. + // TODO(jiawei.shao@intel.com): remove the initialization of the buffer after we support + // buffer lazy-initialization. + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + const std::vector emptyData(bufferSpec.size / bytesPerTexel, RGBA8()); + wgpu::Buffer buffer = + utils::CreateBufferFromData(device, emptyData.data(), bufferSpec.size, + wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst); - // Create a buffer of size `size * textureSpec.arrayLayer` and populate it with empty - // data (0,0,0,0) Note: Prepopulating the buffer with empty data ensures that there is - // not random data in the expectation and helps ensure that the padding due to the bytes - // per row is not modified by the copy - wgpu::BufferDescriptor bufDescriptor; - bufDescriptor.size = bufferSpec.size * textureSpec.arraySize; - bufDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; - wgpu::Buffer buffer = device.CreateBuffer(&bufDescriptor); - std::vector emptyData(bufferSpec.size / kBytesPerTexel * textureSpec.arraySize); - queue.WriteBuffer(buffer, 0, emptyData.data(), - static_cast(emptyData.size() * sizeof(RGBA8))); + const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth; - uint64_t bufferOffset = bufferSpec.offset; - for (uint32_t slice = 0; slice < textureSpec.arraySize; ++slice) { - // Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` - // mip into the buffer at `offset + bufferSpec.size * slice` and `bytesPerRow` - wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView( - texture, textureSpec.level, {textureSpec.x, textureSpec.y, slice}); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(buffer, bufferOffset, bufferSpec.bytesPerRow, 0); - wgpu::Extent3D copySize = {textureSpec.copyWidth, textureSpec.copyHeight, 1}; - encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, ©Size); - bufferOffset += bufferSpec.size; - } + // TODO(jiawei.shao@intel.com): copy from multiple texture array layers in one + // texture-to-buffer copy command. + uint64_t bufferOffset = bufferSpec.offset; + for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { + // Copy the region [(`x`, `y`, slice), (`x + testCopySize.width, `y + + // testCopySize.height`, 1)] from the `level` mip into the buffer at `offset + + // bufferSpec.size * slice` and `bytesPerRow` + wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView( + texture, textureSpec.level, + {textureSpec.copyOrigin.x, textureSpec.copyOrigin.y, slice}); + wgpu::BufferCopyView bufferCopyView = + utils::CreateBufferCopyView(buffer, bufferOffset, bufferSpec.bytesPerRow, 0); + wgpu::Extent3D copyOneLayerSize = {copySize.width, copySize.height, 1}; + encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, ©OneLayerSize); + bufferOffset += copyLayout.bytesPerImage; + } - wgpu::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + wgpu::CommandBuffer commands = encoder.Finish(); + queue.Submit(1, &commands); - bufferOffset = bufferSpec.offset; - std::vector expected(bufferSpec.bytesPerRow / kBytesPerTexel * - (textureSpec.copyHeight - 1) + - textureSpec.copyWidth); - for (uint32_t slice = 0; slice < textureSpec.arraySize; ++slice) { - // Pack the data used to create the upload buffer in the specified copy region to have the same format as the expected buffer data. - std::fill(expected.begin(), expected.end(), RGBA8()); - PackTextureData( - &textureArrayData[slice][textureSpec.x + - textureSpec.y * (bytesPerRow / kBytesPerTexel)], - textureSpec.copyWidth, textureSpec.copyHeight, bytesPerRow / kBytesPerTexel, - expected.data(), bufferSpec.bytesPerRow / kBytesPerTexel); + bufferOffset = bufferSpec.offset; + const uint32_t texelCountInCopyRegion = + bufferSpec.bytesPerRow / bytesPerTexel * (copySize.height - 1) + copySize.width; + std::vector expected(texelCountInCopyRegion); + for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { + // Pack the data used to create the upload buffer in the specified copy region to have + // the same format as the expected buffer data. + std::fill(expected.begin(), expected.end(), RGBA8()); + const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * slice; + const uint32_t expectedTexelArrayDataStartIndex = + texelIndexOffset + (textureSpec.copyOrigin.x + + textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow); - EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast(expected.data()), - buffer, bufferOffset, - static_cast(expected.size())) - << "Texture to Buffer copy failed copying region [(" << textureSpec.x << ", " - << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " - << textureSpec.y + textureSpec.copyHeight << ")) from " << textureSpec.width - << " x " << textureSpec.height << " texture at mip level " << textureSpec.level - << " layer " << slice << " to " << bufDescriptor.size - << "-byte buffer with offset " << bufferOffset << " and bytes per row " - << bufferSpec.bytesPerRow << std::endl; - - bufferOffset += bufferSpec.size; - } - } + PackTextureData(&textureArrayData[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.x + copySize.width << ", " + << textureSpec.copyOrigin.y + copySize.height << ")) 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; + } + } }; class CopyTests_B2T : public CopyTests { @@ -185,121 +195,94 @@ protected: } } - void DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) { + void DoTest(const TextureSpec& textureSpec, + const BufferSpec& bufferSpec, + const wgpu::Extent3D& copySize) { // Create a buffer of size `size` and populate it with data - wgpu::BufferDescriptor bufDescriptor; - bufDescriptor.size = bufferSpec.size; - bufDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; - wgpu::Buffer buffer = device.CreateBuffer(&bufDescriptor); - - std::vector bufferData(bufferSpec.size / kBytesPerTexel); + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + std::vector bufferData(bufferSpec.size / bytesPerTexel); FillBufferData(bufferData.data(), bufferData.size()); - queue.WriteBuffer(buffer, 0, bufferData.data(), - static_cast(bufferData.size() * sizeof(RGBA8))); + wgpu::Buffer buffer = + utils::CreateBufferFromData(device, bufferData.data(), bufferSpec.size, + wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst); // Create a texture that is `width` x `height` with (`level` + 1) mip levels. wgpu::TextureDescriptor descriptor; descriptor.dimension = wgpu::TextureDimension::e2D; - descriptor.size.width = textureSpec.width; - descriptor.size.height = textureSpec.height; - descriptor.size.depth = 1; + descriptor.size = textureSpec.textureSize; descriptor.sampleCount = 1; - descriptor.format = wgpu::TextureFormat::RGBA8Unorm; + descriptor.format = kTextureFormat; descriptor.mipLevelCount = textureSpec.level + 1; descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; wgpu::Texture texture = device.CreateTexture(&descriptor); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - // Create an upload buffer filled with empty data and use it to populate the `level` mip of - // the texture Note: Prepopulating the texture with empty data ensures that there is not - // random data in the expectation and helps ensure that the padding due to the bytes per row - // is not modified by the copy - { - uint32_t width = textureSpec.width >> textureSpec.level; - uint32_t height = textureSpec.height >> textureSpec.level; - uint32_t bytesPerRow = Align(kBytesPerTexel * width, kTextureBytesPerRowAlignment); - uint32_t texelsPerRow = bytesPerRow / kBytesPerTexel; - uint32_t texelCount = texelsPerRow * (height - 1) + width; + const uint32_t rowsPerImage = textureSpec.textureSize.height >> textureSpec.level; + const utils::BufferTextureCopyLayout copyLayout = + utils::GetBufferTextureCopyLayoutForTexture2DAtLevel( + kTextureFormat, textureSpec.textureSize, textureSpec.level, rowsPerImage); - std::vector emptyData(texelCount); - wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( - device, emptyData.data(), static_cast(sizeof(RGBA8) * emptyData.size()), - wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, bytesPerRow, 0); - wgpu::TextureCopyView textureCopyView = - utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0}); - wgpu::Extent3D copySize = {width, height, 1}; - encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); - } + const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth; - // Copy to the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] at the `level` mip - // from the buffer at the specified `offset` and `bytesPerRow` - { + // TODO(jiawei.shao@intel.com): support copying into multiple texture array layers in one + // copy command. + uint64_t bufferOffset = bufferSpec.offset; + for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { + // Copy to the region [(`x`, `y`, `slice`), (`x + testCopySize.width, `y + + // testCopySize.height`, 1] at the `level` mip + // from the buffer at the specified `offset` and `bytesPerRow` wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(buffer, bufferSpec.offset, bufferSpec.bytesPerRow, 0); + utils::CreateBufferCopyView(buffer, bufferOffset, bufferSpec.bytesPerRow, 0); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView( - texture, textureSpec.level, {textureSpec.x, textureSpec.y, 0}); - wgpu::Extent3D copySize = {textureSpec.copyWidth, textureSpec.copyHeight, 1}; - encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); + texture, textureSpec.level, + {textureSpec.copyOrigin.x, textureSpec.copyOrigin.y, slice}); + wgpu::Extent3D copyOneLayerSize = {copySize.width, copySize.height, 1}; + encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©OneLayerSize); + bufferOffset += copyLayout.bytesPerImage; } wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); - // Pack the data used to create the buffer in the specified copy region to have the same format as the expected texture data. - uint32_t bytesPerRow = - Align(kBytesPerTexel * textureSpec.copyWidth, kTextureBytesPerRowAlignment); - std::vector expected(bytesPerRow / kBytesPerTexel * (textureSpec.copyHeight - 1) + - textureSpec.copyWidth); - PackTextureData(&bufferData[bufferSpec.offset / kBytesPerTexel], textureSpec.copyWidth, - textureSpec.copyHeight, bufferSpec.bytesPerRow / kBytesPerTexel, - expected.data(), textureSpec.copyWidth); + bufferOffset = bufferSpec.offset; + const uint32_t texelCountLastLayer = + copyLayout.texelBlocksPerRow * (copyLayout.mipSize.height - 1) + + copyLayout.mipSize.width; + for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { + // 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, + copySize.height, bufferSpec.bytesPerRow / bytesPerTexel, + expected.data(), copySize.width); - EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.x, textureSpec.y, - textureSpec.copyWidth, textureSpec.copyHeight, textureSpec.level, 0) - << "Buffer to Texture copy failed copying " << bufferSpec.size - << "-byte buffer with offset " << bufferSpec.offset << " and bytes per row " - << bufferSpec.bytesPerRow << " to [(" << textureSpec.x << ", " << textureSpec.y - << "), (" << textureSpec.x + textureSpec.copyWidth << ", " - << textureSpec.y + textureSpec.copyHeight << ")) region of " << textureSpec.width - << " x " << textureSpec.height << " texture at mip level " << textureSpec.level - << std::endl; + EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.copyOrigin.x, + textureSpec.copyOrigin.y, copySize.width, copySize.height, + textureSpec.level, slice) + << "Buffer to Texture copy failed copying " << bufferSpec.size + << "-byte buffer with offset " << bufferSpec.offset << " and bytes per row " + << bufferSpec.bytesPerRow << " to [(" << textureSpec.copyOrigin.x << ", " + << textureSpec.copyOrigin.y << "), (" << textureSpec.copyOrigin.x + copySize.width + << ", " << textureSpec.copyOrigin.y + copySize.height << ")) region of " + << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height + << " texture at mip level " << textureSpec.level << " layer " << slice << std::endl; + bufferOffset += copyLayout.bytesPerImage; + } } - - }; class CopyTests_T2T : public CopyTests { - struct TextureSpec { - uint32_t width; - uint32_t height; - uint32_t x; - uint32_t y; - uint32_t level; - uint32_t arraySize = 1u; - uint32_t baseArrayLayer = 0u; - }; - - struct CopySize { - uint32_t width; - uint32_t height; - uint32_t arrayLayerCount = 1u; - }; - protected: void DoTest(const TextureSpec& srcSpec, const TextureSpec& dstSpec, - const CopySize& copy, + const wgpu::Extent3D& copySize, bool copyWithinSameTexture = false) { wgpu::TextureDescriptor srcDescriptor; srcDescriptor.dimension = wgpu::TextureDimension::e2D; - srcDescriptor.size.width = srcSpec.width; - srcDescriptor.size.height = srcSpec.height; - srcDescriptor.size.depth = srcSpec.arraySize; + srcDescriptor.size = srcSpec.textureSize; srcDescriptor.sampleCount = 1; - srcDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; + srcDescriptor.format = kTextureFormat; srcDescriptor.mipLevelCount = srcSpec.level + 1; srcDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor); @@ -310,11 +293,9 @@ class CopyTests_T2T : public CopyTests { } else { wgpu::TextureDescriptor dstDescriptor; dstDescriptor.dimension = wgpu::TextureDimension::e2D; - dstDescriptor.size.width = dstSpec.width; - dstDescriptor.size.height = dstSpec.height; - dstDescriptor.size.depth = dstSpec.arraySize; + dstDescriptor.size = dstSpec.textureSize; dstDescriptor.sampleCount = 1; - dstDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; + dstDescriptor.format = kTextureFormat; dstDescriptor.mipLevelCount = dstSpec.level + 1; dstDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; dstTexture = device.CreateTexture(&dstDescriptor); @@ -324,62 +305,68 @@ class CopyTests_T2T : public CopyTests { // Create an upload buffer and use it to populate the current slice of the texture in // `level` mip level - uint32_t width = srcSpec.width >> srcSpec.level; - uint32_t height = srcSpec.height >> srcSpec.level; - uint32_t bytesPerRow = Align(kBytesPerTexel * width, kTextureBytesPerRowAlignment); - uint32_t texelsPerRow = bytesPerRow / kBytesPerTexel; - uint32_t texelCountPerLayer = texelsPerRow * (height - 1) + width; + const uint32_t rowsPerImage = srcSpec.textureSize.height >> srcSpec.level; + const utils::BufferTextureCopyLayout copyLayout = + utils::GetBufferTextureCopyLayoutForTexture2DAtLevel( + kTextureFormat, + {srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth}, + srcSpec.level, rowsPerImage); + + const std::vector textureArrayCopyData = GetExpectedTextureData(copyLayout); // TODO(jiawei.shao@intel.com): support copying into multiple contiguous array layers in one // copyBufferToTexture() call. - std::vector> textureArrayCopyData(copy.arrayLayerCount); - for (uint32_t slice = 0; slice < copy.arrayLayerCount; ++slice) { - textureArrayCopyData[slice].resize(texelCountPerLayer); - FillTextureData(width, height, bytesPerRow / kBytesPerTexel, slice, - textureArrayCopyData[slice].data()); - - wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( - device, textureArrayCopyData[slice].data(), - static_cast(sizeof(RGBA8) * textureArrayCopyData[slice].size()), - wgpu::BufferUsage::CopySrc); - wgpu::BufferCopyView bufferCopyView = - utils::CreateBufferCopyView(uploadBuffer, 0, bytesPerRow, 0); + wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( + device, textureArrayCopyData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); + uint64_t uploadBufferOffset = 0; + for (uint32_t slice = 0; slice < copySize.depth; ++slice) { + wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( + uploadBuffer, uploadBufferOffset, copyLayout.bytesPerRow, 0); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView( - srcTexture, srcSpec.level, {0, 0, srcSpec.baseArrayLayer + slice}); - wgpu::Extent3D bufferCopySize = {width, height, 1}; - - encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &bufferCopySize); + srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z + slice}); + wgpu::Extent3D copyOneLayerSize = {copyLayout.mipSize.width, copyLayout.mipSize.height, + 1}; + encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©OneLayerSize); + uploadBufferOffset += copyLayout.bytesPerImage; } // Perform the texture to texture copy - wgpu::TextureCopyView srcTextureCopyView = utils::CreateTextureCopyView( - srcTexture, srcSpec.level, {srcSpec.x, srcSpec.y, srcSpec.baseArrayLayer}); - wgpu::TextureCopyView dstTextureCopyView = utils::CreateTextureCopyView( - dstTexture, dstSpec.level, {dstSpec.x, dstSpec.y, dstSpec.baseArrayLayer}); - wgpu::Extent3D copySize = {copy.width, copy.height, copy.arrayLayerCount}; + wgpu::TextureCopyView srcTextureCopyView = + utils::CreateTextureCopyView(srcTexture, srcSpec.level, srcSpec.copyOrigin); + wgpu::TextureCopyView dstTextureCopyView = + utils::CreateTextureCopyView(dstTexture, dstSpec.level, dstSpec.copyOrigin); encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, ©Size); wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); - std::vector expected(bytesPerRow / kBytesPerTexel * (copy.height - 1) + copy.width); - for (uint32_t slice = 0; slice < copy.arrayLayerCount; ++slice) { + const uint32_t texelCountInCopyRegion = + copyLayout.texelBlocksPerRow * (copySize.height - 1) + copySize.width; + std::vector expected(texelCountInCopyRegion); + for (uint32_t slice = 0; slice < copySize.depth; ++slice) { std::fill(expected.begin(), expected.end(), RGBA8()); - PackTextureData(&textureArrayCopyData[slice][srcSpec.x + srcSpec.y * (bytesPerRow / - kBytesPerTexel)], - copy.width, copy.height, texelsPerRow, expected.data(), copy.width); + const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * slice; + const uint32_t expectedTexelArrayDataStartIndex = + texelIndexOffset + + (srcSpec.copyOrigin.x + srcSpec.copyOrigin.y * copyLayout.texelBlocksPerRow); + PackTextureData(&textureArrayCopyData[expectedTexelArrayDataStartIndex], copySize.width, + copySize.height, copyLayout.texelBlocksPerRow, expected.data(), + copySize.width); - EXPECT_TEXTURE_RGBA8_EQ(expected.data(), dstTexture, dstSpec.x, dstSpec.y, copy.width, - copy.height, dstSpec.level, dstSpec.baseArrayLayer + slice) - << "Texture to Texture copy failed copying region [(" << srcSpec.x << ", " - << srcSpec.y << "), (" << srcSpec.x + copy.width << ", " << srcSpec.y + copy.height - << ")) from " << srcSpec.width << " x " << srcSpec.height + EXPECT_TEXTURE_RGBA8_EQ(expected.data(), dstTexture, dstSpec.copyOrigin.x, + dstSpec.copyOrigin.y, copySize.width, copySize.height, + dstSpec.level, dstSpec.copyOrigin.z + slice) + << "Texture to Texture copy failed copying region [(" << srcSpec.copyOrigin.x + << ", " << srcSpec.copyOrigin.y << "), (" << srcSpec.copyOrigin.x + copySize.width + << ", " << srcSpec.copyOrigin.y + copySize.height << ")) from " + << srcSpec.textureSize.width << " x " << srcSpec.textureSize.height << " texture at mip level " << srcSpec.level << " layer " - << srcSpec.baseArrayLayer + slice << " to [(" << dstSpec.x << ", " << dstSpec.y - << "), (" << dstSpec.x + copy.width << ", " << dstSpec.y + copy.height - << ")) region of " << dstSpec.width << " x " << dstSpec.height + << srcSpec.copyOrigin.z + slice << " to [(" << dstSpec.copyOrigin.x << ", " + << dstSpec.copyOrigin.y << "), (" << dstSpec.copyOrigin.x + copySize.width << ", " + << dstSpec.copyOrigin.y + copySize.height << ")) region of " + << dstSpec.textureSize.width << " x " << dstSpec.textureSize.height << " texture at mip level " << dstSpec.level << " layer " - << dstSpec.baseArrayLayer + slice << std::endl; + << dstSpec.copyOrigin.z + slice << std::endl; } } }; @@ -431,14 +418,26 @@ class CopyTests_B2B : public DawnTest { TEST_P(CopyTests_T2B, FullTextureAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight)); + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1}); } // Test that copying an entire texture without 256-byte aligned dimensions works TEST_P(CopyTests_T2B, FullTextureUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight)); + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1}); } // Test that reading pixels from a 256-byte aligned texture works @@ -446,12 +445,48 @@ TEST_P(CopyTests_T2B, PixelReadAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; BufferSpec pixelBuffer = MinimumBufferSpec(1, 1); - DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer); + + constexpr wgpu::Extent3D kCopySize = {1, 1, 1}; + constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1}; + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = kTextureSize; + defaultTextureSpec.level = 0; + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } } // Test that copying pixels from a texture that is not 256-byte aligned works @@ -459,12 +494,48 @@ TEST_P(CopyTests_T2B, PixelReadUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; BufferSpec pixelBuffer = MinimumBufferSpec(1, 1); - DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer); + + constexpr wgpu::Extent3D kCopySize = {1, 1, 1}; + constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1}; + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = kTextureSize; + defaultTextureSpec.level = 0; + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } } // Test that copying regions with 256-byte aligned sizes works @@ -473,7 +544,11 @@ TEST_P(CopyTests_T2B, TextureRegionAligned) { constexpr uint32_t kHeight = 128; for (unsigned int w : {64, 128, 256}) { for (unsigned int h : { 16, 32, 48 }) { - DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h)); + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1}); } } } @@ -482,9 +557,16 @@ TEST_P(CopyTests_T2B, TextureRegionAligned) { TEST_P(CopyTests_T2B, TextureRegionUnaligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.level = 0; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int w : {13, 63, 65}) { for (unsigned int h : { 17, 19, 63 }) { - DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h)); + TextureSpec textureSpec = defaultTextureSpec; + DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1}); } } } @@ -493,8 +575,16 @@ TEST_P(CopyTests_T2B, TextureRegionUnaligned) { TEST_P(CopyTests_T2B, TextureMipAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i)); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i), + {kWidth >> i, kHeight >> i, 1}); } } @@ -502,8 +592,16 @@ TEST_P(CopyTests_T2B, TextureMipAligned) { TEST_P(CopyTests_T2B, TextureMipUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i)); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i), + {kWidth >> i, kHeight >> i, 1}); } } @@ -511,12 +609,18 @@ TEST_P(CopyTests_T2B, TextureMipUnaligned) { TEST_P(CopyTests_T2B, OffsetBufferAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + for (unsigned int i = 0; i < 3; ++i) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); uint64_t offset = 512 * i; bufferSpec.size += offset; bufferSpec.offset += offset; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -524,11 +628,18 @@ TEST_P(CopyTests_T2B, OffsetBufferAligned) { TEST_P(CopyTests_T2B, OffsetBufferUnaligned) { constexpr uint32_t kWidth = 128; constexpr uint32_t kHeight = 128; - for (uint32_t i = kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) { + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + for (uint32_t i = bytesPerTexel; i < 512; i += bytesPerTexel * 9) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); bufferSpec.size += i; bufferSpec.offset += i; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -537,11 +648,18 @@ TEST_P(CopyTests_T2B, OffsetBufferUnaligned) { TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) { constexpr uint32_t kWidth = 32; constexpr uint32_t kHeight = 128; - for (uint32_t i = 256 + kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) { + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + for (uint32_t i = 256 + bytesPerTexel; i < 512; i += bytesPerTexel * 9) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); bufferSpec.size += i; bufferSpec.offset += i; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -549,11 +667,17 @@ TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) { TEST_P(CopyTests_T2B, RowPitchAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); for (unsigned int i = 1; i < 4; ++i) { bufferSpec.bytesPerRow += 256; bufferSpec.size += 256 * kHeight; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -562,11 +686,17 @@ TEST_P(CopyTests_T2B, RowPitchAligned) { TEST_P(CopyTests_T2B, RowPitchUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); for (unsigned int i = 1; i < 4; ++i) { bufferSpec.bytesPerRow += 256; bufferSpec.size += 256 * kHeight; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -575,7 +705,30 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegion) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0, kLayers }, MinimumBufferSpec(kWidth, kHeight)); + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, kLayers}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kLayers), {kWidth, kHeight, kLayers}); +} + +// Test that copying a sub-region of each texture 2D array layer works +TEST_P(CopyTests_T2B, Texture2DArraySubRegion) { + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kLayers = 6u; + constexpr uint32_t kBaseLayer = 2u; + constexpr uint32_t kCopyLayers = 3u; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, kBaseLayer}; + textureSpec.textureSize = {kWidth, kHeight, kLayers}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyLayers), + {kWidth, kHeight, kCopyLayers}); } // Test that copying texture 2D array mips with 256-byte aligned sizes works @@ -583,8 +736,17 @@ TEST_P(CopyTests_T2B, Texture2DArrayMip) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i, kLayers }, MinimumBufferSpec(kWidth >> i, kHeight >> i)); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + + DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kLayers), + {kWidth >> i, kHeight >> i, kLayers}); } } @@ -594,14 +756,26 @@ DAWN_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend(), MetalBackend(), OpenGLBacke TEST_P(CopyTests_B2T, FullTextureAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight)); + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1}); } // Test that copying an entire texture without 256-byte aligned dimensions works TEST_P(CopyTests_B2T, FullTextureUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, MinimumBufferSpec(kWidth, kHeight)); + + TextureSpec textureSpec; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight), {kWidth, kHeight, 1}); } // Test that reading pixels from a 256-byte aligned texture works @@ -609,12 +783,48 @@ TEST_P(CopyTests_B2T, PixelReadAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; BufferSpec pixelBuffer = MinimumBufferSpec(1, 1); - DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer); + + constexpr wgpu::Extent3D kCopySize = {1, 1, 1}; + constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1}; + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = kTextureSize; + defaultTextureSpec.level = 0; + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } } // Test that copying pixels from a texture that is not 256-byte aligned works @@ -622,12 +832,48 @@ TEST_P(CopyTests_B2T, PixelReadUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; BufferSpec pixelBuffer = MinimumBufferSpec(1, 1); - DoTest({ kWidth, kHeight, 0, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, 0, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, 0, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth - 1, kHeight - 1, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 3, kHeight / 7, 1, 1, 0 }, pixelBuffer); - DoTest({ kWidth, kHeight, kWidth / 7, kHeight / 3, 1, 1, 0 }, pixelBuffer); + + constexpr wgpu::Extent3D kCopySize = {1, 1, 1}; + constexpr wgpu::Extent3D kTextureSize = {kWidth, kHeight, 1}; + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = kTextureSize; + defaultTextureSpec.level = 0; + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, 0, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {0, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth - 1, kHeight - 1, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 3, kHeight / 7, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } + + { + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.copyOrigin = {kWidth / 7, kHeight / 3, 0}; + DoTest(textureSpec, pixelBuffer, kCopySize); + } } // Test that copying regions with 256-byte aligned sizes works @@ -636,7 +882,11 @@ TEST_P(CopyTests_B2T, TextureRegionAligned) { constexpr uint32_t kHeight = 128; for (unsigned int w : {64, 128, 256}) { for (unsigned int h : { 16, 32, 48 }) { - DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h)); + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1}); } } } @@ -645,9 +895,16 @@ TEST_P(CopyTests_B2T, TextureRegionAligned) { TEST_P(CopyTests_B2T, TextureRegionUnaligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.level = 0; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int w : {13, 63, 65}) { - for (unsigned int h : { 17, 19, 63 }) { - DoTest({ kWidth, kHeight, 0, 0, w, h, 0 }, MinimumBufferSpec(w, h)); + for (unsigned int h : {17, 19, 63}) { + TextureSpec textureSpec = defaultTextureSpec; + DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1}); } } } @@ -656,8 +913,16 @@ TEST_P(CopyTests_B2T, TextureRegionUnaligned) { TEST_P(CopyTests_B2T, TextureMipAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i)); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i), + {kWidth >> i, kHeight >> i, 1}); } } @@ -665,8 +930,16 @@ TEST_P(CopyTests_B2T, TextureMipAligned) { TEST_P(CopyTests_B2T, TextureMipUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i }, MinimumBufferSpec(kWidth >> i, kHeight >> i)); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i), + {kWidth >> i, kHeight >> i, 1}); } } @@ -674,12 +947,18 @@ TEST_P(CopyTests_B2T, TextureMipUnaligned) { TEST_P(CopyTests_B2T, OffsetBufferAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + for (unsigned int i = 0; i < 3; ++i) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); uint64_t offset = 512 * i; bufferSpec.size += offset; bufferSpec.offset += offset; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -687,11 +966,18 @@ TEST_P(CopyTests_B2T, OffsetBufferAligned) { TEST_P(CopyTests_B2T, OffsetBufferUnaligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; - for (uint32_t i = kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) { + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + for (uint32_t i = bytesPerTexel; i < 512; i += bytesPerTexel * 9) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); bufferSpec.size += i; bufferSpec.offset += i; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -700,11 +986,18 @@ TEST_P(CopyTests_B2T, OffsetBufferUnaligned) { TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) { constexpr uint32_t kWidth = 32; constexpr uint32_t kHeight = 128; - for (uint32_t i = 256 + kBytesPerTexel; i < 512; i += kBytesPerTexel * 9) { + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); + for (uint32_t i = 256 + bytesPerTexel; i < 512; i += bytesPerTexel * 9) { BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); bufferSpec.size += i; bufferSpec.offset += i; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -712,11 +1005,17 @@ TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) { TEST_P(CopyTests_B2T, RowPitchAligned) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); for (unsigned int i = 1; i < 4; ++i) { bufferSpec.bytesPerRow += 256; bufferSpec.size += 256 * kHeight; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } @@ -725,28 +1024,77 @@ TEST_P(CopyTests_B2T, RowPitchAligned) { TEST_P(CopyTests_B2T, RowPitchUnaligned) { constexpr uint32_t kWidth = 259; constexpr uint32_t kHeight = 127; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, 1}; + textureSpec.level = 0; + BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kHeight); for (unsigned int i = 1; i < 4; ++i) { bufferSpec.bytesPerRow += 256; bufferSpec.size += 256 * kHeight; - DoTest({ kWidth, kHeight, 0, 0, kWidth, kHeight, 0 }, bufferSpec); + DoTest(textureSpec, bufferSpec, {kWidth, kHeight, 1}); } } +// Test that copying into regions of each texture 2D array layer works +TEST_P(CopyTests_B2T, Texture2DArrayRegion) { + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kLayers = 6u; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.textureSize = {kWidth, kHeight, kLayers}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kLayers), {kWidth, kHeight, kLayers}); +} + +// Test that copying into a sub-region of each texture 2D array layer works +TEST_P(CopyTests_B2T, Texture2DArraySubRegion) { + constexpr uint32_t kWidth = 256; + constexpr uint32_t kHeight = 128; + constexpr uint32_t kLayers = 6u; + constexpr uint32_t kBaseLayer = 2u; + constexpr uint32_t kCopyLayers = 3u; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, kBaseLayer}; + textureSpec.textureSize = {kWidth, kHeight, kLayers}; + textureSpec.level = 0; + + DoTest(textureSpec, MinimumBufferSpec(kWidth, kHeight, kCopyLayers), + {kWidth, kHeight, kCopyLayers}); +} + DAWN_INSTANTIATE_TEST(CopyTests_B2T, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); TEST_P(CopyTests_T2T, Texture) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; - DoTest({kWidth, kHeight, 0, 0, 0}, {kWidth, kHeight, 0, 0, 0}, {kWidth, kHeight}); + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1}); } TEST_P(CopyTests_T2T, TextureRegion) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.level = 0; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int w : {64, 128, 256}) { for (unsigned int h : {16, 32, 48}) { - DoTest({kWidth, kHeight, 0, 0, 0, 1}, {kWidth, kHeight, 0, 0, 0, 1}, {w, h}); + TextureSpec textureSpec = defaultTextureSpec; + DoTest(textureSpec, textureSpec, {w, h, 1}); } } } @@ -759,8 +1107,13 @@ TEST_P(CopyTests_T2T, Texture2DArray) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; - DoTest({kWidth, kHeight, 0, 0, 0, kLayers}, {kWidth, kHeight, 0, 0, 0, kLayers}, - {kWidth, kHeight, kLayers}); + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, kLayers}; + + DoTest(textureSpec, textureSpec, {kWidth, kHeight, kLayers}); } // Test copying a subresource region of the 2D array texture. @@ -771,10 +1124,16 @@ TEST_P(CopyTests_T2T, Texture2DArrayRegion) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; constexpr uint32_t kLayers = 6u; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.level = 0; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + for (unsigned int w : {64, 128, 256}) { for (unsigned int h : {16, 32, 48}) { - DoTest({kWidth, kHeight, 0, 0, 0, kLayers}, {kWidth, kHeight, 0, 0, 0, kLayers}, - {w, h, kLayers}); + TextureSpec textureSpec = defaultTextureSpec; + DoTest(textureSpec, textureSpec, {w, h, kLayers}); } } } @@ -786,8 +1145,19 @@ TEST_P(CopyTests_T2T, Texture2DArrayCopyOneSlice) { constexpr uint32_t kLayers = 6u; constexpr uint32_t kSrcBaseLayer = 1u; constexpr uint32_t kDstBaseLayer = 3u; - DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, - {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, {kWidth, kHeight, 1u}); + constexpr uint32_t kCopyArrayLayerCount = 1u; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + defaultTextureSpec.level = 0; + + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer}; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer}; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}); } // Test copying multiple contiguous slices of a 2D array texture. @@ -801,9 +1171,18 @@ TEST_P(CopyTests_T2T, Texture2DArrayCopyMultipleSlices) { constexpr uint32_t kSrcBaseLayer = 0u; constexpr uint32_t kDstBaseLayer = 3u; constexpr uint32_t kCopyArrayLayerCount = 3u; - DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, - {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, - {kWidth, kHeight, kCopyArrayLayerCount}); + + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + defaultTextureSpec.level = 0; + + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer}; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer}; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}); } // Test copying one texture slice within the same texture. @@ -814,9 +1193,18 @@ TEST_P(CopyTests_T2T, CopyWithinSameTextureOneSlice) { constexpr uint32_t kSrcBaseLayer = 0u; constexpr uint32_t kDstBaseLayer = 3u; constexpr uint32_t kCopyArrayLayerCount = 1u; - DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, - {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, - {kWidth, kHeight, kCopyArrayLayerCount}, true); + + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + defaultTextureSpec.level = 0; + + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer}; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer}; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}, true); } // Test copying multiple contiguous texture slices within the same texture with non-overlapped @@ -831,34 +1219,73 @@ TEST_P(CopyTests_T2T, CopyWithinSameTextureNonOverlappedSlices) { constexpr uint32_t kSrcBaseLayer = 0u; constexpr uint32_t kDstBaseLayer = 3u; constexpr uint32_t kCopyArrayLayerCount = 3u; - DoTest({kWidth, kHeight, 0, 0, 0, kLayers, kSrcBaseLayer}, - {kWidth, kHeight, 0, 0, 0, kLayers, kDstBaseLayer}, - {kWidth, kHeight, kCopyArrayLayerCount}, true); + + TextureSpec defaultTextureSpec; + defaultTextureSpec.textureSize = {kWidth, kHeight, kLayers}; + defaultTextureSpec.level = 0; + + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.copyOrigin = {0, 0, kSrcBaseLayer}; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.copyOrigin = {0, 0, kDstBaseLayer}; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth, kHeight, kCopyArrayLayerCount}, true); } TEST_P(CopyTests_T2T, TextureMip) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({kWidth, kHeight, 0, 0, i}, {kWidth, kHeight, 0, 0, i}, {kWidth >> i, kHeight >> i}); + TextureSpec textureSpec = defaultTextureSpec; + textureSpec.level = i; + + DoTest(textureSpec, textureSpec, {kWidth >> i, kHeight >> i, 1}); } } TEST_P(CopyTests_T2T, SingleMipSrcMultipleMipDst) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({kWidth >> i, kHeight >> i, 0, 0, 0}, {kWidth, kHeight, 0, 0, i}, - {kWidth >> i, kHeight >> i}); + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.textureSize = {kWidth >> i, kHeight >> i, 1}; + srcTextureSpec.level = 0; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.textureSize = {kWidth, kHeight, 1}; + dstTextureSpec.level = i; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth >> i, kHeight >> i, 1}); } } TEST_P(CopyTests_T2T, MultipleMipSrcSingleMipDst) { constexpr uint32_t kWidth = 256; constexpr uint32_t kHeight = 128; + + TextureSpec defaultTextureSpec; + defaultTextureSpec.copyOrigin = {0, 0, 0}; + for (unsigned int i = 1; i < 4; ++i) { - DoTest({kWidth, kHeight, 0, 0, i}, {kWidth >> i, kHeight >> i, 0, 0, 0}, - {kWidth >> i, kHeight >> i}); + TextureSpec srcTextureSpec = defaultTextureSpec; + srcTextureSpec.textureSize = {kWidth, kHeight, 1}; + srcTextureSpec.level = i; + + TextureSpec dstTextureSpec = defaultTextureSpec; + dstTextureSpec.textureSize = {kWidth >> i, kHeight >> i, 1}; + dstTextureSpec.level = 0; + + DoTest(srcTextureSpec, dstTextureSpec, {kWidth >> i, kHeight >> i, 1}); } } diff --git a/src/utils/WGPUHelpers.cpp b/src/utils/WGPUHelpers.cpp index d3ee2c0a6b..b44b866669 100644 --- a/src/utils/WGPUHelpers.cpp +++ b/src/utils/WGPUHelpers.cpp @@ -17,6 +17,8 @@ #include "common/Assert.h" #include "common/Constants.h" #include "common/Log.h" +#include "common/Math.h" +#include "utils/TextureFormatUtils.h" #include @@ -372,4 +374,44 @@ namespace utils { return device.CreateBindGroup(&descriptor); } + uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width) { + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); + return Align(bytesPerTexel * width, kTextureBytesPerRowAlignment); + } + + uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format, + uint32_t width, + uint32_t bytesPerRow, + uint32_t rowsPerImage, + uint32_t copyArrayLayerCount) { + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); + const uint32_t bytesAtLastImage = bytesPerRow * (rowsPerImage - 1) + bytesPerTexel * width; + return bytesPerRow * rowsPerImage * (copyArrayLayerCount - 1) + bytesAtLastImage; + } + + // TODO(jiawei.shao@intel.com): support compressed texture formats + BufferTextureCopyLayout GetBufferTextureCopyLayoutForTexture2DAtLevel( + wgpu::TextureFormat format, + wgpu::Extent3D textureSizeAtLevel0, + uint32_t mipmapLevel, + uint32_t rowsPerImage) { + BufferTextureCopyLayout layout; + + layout.mipSize = {textureSizeAtLevel0.width >> mipmapLevel, + textureSizeAtLevel0.height >> mipmapLevel, textureSizeAtLevel0.depth}; + + layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width); + layout.bytesPerImage = layout.bytesPerRow * rowsPerImage; + + layout.byteLength = + GetBytesInBufferTextureCopy(format, layout.mipSize.width, layout.bytesPerRow, + layout.mipSize.height, textureSizeAtLevel0.depth); + + const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); + layout.texelBlocksPerRow = layout.bytesPerRow / bytesPerTexel; + layout.texelBlocksPerImage = layout.bytesPerImage / bytesPerTexel; + layout.texelBlockCount = layout.byteLength / bytesPerTexel; + + return layout; + } } // namespace utils diff --git a/src/utils/WGPUHelpers.h b/src/utils/WGPUHelpers.h index 8c756bcd82..fdbd8648f7 100644 --- a/src/utils/WGPUHelpers.h +++ b/src/utils/WGPUHelpers.h @@ -129,6 +129,28 @@ namespace utils { const wgpu::BindGroupLayout& layout, std::initializer_list entriesInitializer); + struct BufferTextureCopyLayout { + uint64_t byteLength; + uint64_t texelBlockCount; + uint32_t bytesPerRow; + uint32_t texelBlocksPerRow; + uint32_t bytesPerImage; + uint32_t texelBlocksPerImage; + wgpu::Extent3D mipSize; + }; + + uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width); + uint32_t GetBytesInBufferTextureCopy(wgpu::TextureFormat format, + uint32_t width, + uint32_t bytesPerRow, + uint32_t rowsPerImage, + uint32_t copyArrayLayerCount); + BufferTextureCopyLayout GetBufferTextureCopyLayoutForTexture2DAtLevel( + wgpu::TextureFormat format, + wgpu::Extent3D textureSizeAtLevel0, + uint32_t mipmapLevel, + uint32_t rowsPerImage); + } // namespace utils #endif // UTILS_DAWNHELPERS_H_