Implement copying between a buffer and a texture 2D array on Vulkan (#257)

Implement copying between a buffer and a texture 2D array on Vulkan

This patch implements the creation of a 2D array texture and data
copying between a buffer and a layer of a 2D array texture on
Vulkan back-ends.

TEST=dawn_end2end_tests
This commit is contained in:
Jiawei Shao 2018-08-30 16:27:38 +08:00 committed by Corentin Wallez
parent ec72443bf1
commit 4b74dbef7b
12 changed files with 187 additions and 128 deletions

View File

@ -345,7 +345,8 @@
{"name": "width", "type": "uint32_t"}, {"name": "width", "type": "uint32_t"},
{"name": "height", "type": "uint32_t"}, {"name": "height", "type": "uint32_t"},
{"name": "depth", "type": "uint32_t"}, {"name": "depth", "type": "uint32_t"},
{"name": "level", "type": "uint32_t"} {"name": "level", "type": "uint32_t"},
{"name": "slice", "type": "uint32_t"}
], ],
"TODO": [ "TODO": [
"Make pretty with Offset and Extents structures", "Make pretty with Offset and Extents structures",
@ -365,6 +366,7 @@
{"name": "height", "type": "uint32_t"}, {"name": "height", "type": "uint32_t"},
{"name": "depth", "type": "uint32_t"}, {"name": "depth", "type": "uint32_t"},
{"name": "level", "type": "uint32_t"}, {"name": "level", "type": "uint32_t"},
{"name": "slice", "type": "uint32_t"},
{"name": "buffer", "type": "buffer"}, {"name": "buffer", "type": "buffer"},
{"name": "buffer offset", "type": "uint32_t"}, {"name": "buffer offset", "type": "uint32_t"},
{"name": "row pitch", "type": "uint32_t"} {"name": "row pitch", "type": "uint32_t"}

View File

@ -71,7 +71,7 @@ void initTextures() {
dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::TransferSrc); dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::TransferSrc);
dawn::CommandBuffer copy = device.CreateCommandBufferBuilder() dawn::CommandBuffer copy = device.CreateCommandBufferBuilder()
.CopyBufferToTexture(stagingBuffer, 0, 0, texture, 0, 0, 0, 1024, 1024, 1, 0) .CopyBufferToTexture(stagingBuffer, 0, 0, texture, 0, 0, 0, 1024, 1024, 1, 0, 0)
.GetResult(); .GetResult();
queue.Submit(1, &copy); queue.Submit(1, &copy);

View File

@ -434,7 +434,7 @@ namespace {
dawn::Buffer staging = utils::CreateBufferFromData(device, data, rowPitch * iImage.height, dawn::BufferUsageBit::TransferSrc); dawn::Buffer staging = utils::CreateBufferFromData(device, data, rowPitch * iImage.height, dawn::BufferUsageBit::TransferSrc);
auto cmdbuf = device.CreateCommandBufferBuilder() auto cmdbuf = device.CreateCommandBufferBuilder()
.CopyBufferToTexture(staging, 0, rowPitch, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0) .CopyBufferToTexture(staging, 0, rowPitch, oTexture, 0, 0, 0, iImage.width, iImage.height, 1, 0, 0)
.GetResult(); .GetResult();
queue.Submit(1, &cmdbuf); queue.Submit(1, &cmdbuf);

View File

@ -38,6 +38,10 @@ namespace dawn_native {
DAWN_RETURN_ERROR("Copy mip-level out of range"); DAWN_RETURN_ERROR("Copy mip-level out of range");
} }
if (location.slice >= texture->GetArrayLayers()) {
DAWN_RETURN_ERROR("Copy array-layer out of range");
}
// All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
// overflows. // overflows.
uint64_t level = location.level; uint64_t level = location.level;
@ -585,7 +589,8 @@ namespace dawn_native {
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
uint32_t level) { uint32_t level,
uint32_t slice) {
if (rowPitch == 0) { if (rowPitch == 0) {
rowPitch = ComputeDefaultRowPitch(texture, width); rowPitch = ComputeDefaultRowPitch(texture, width);
} }
@ -602,6 +607,7 @@ namespace dawn_native {
copy->destination.height = height; copy->destination.height = height;
copy->destination.depth = depth; copy->destination.depth = depth;
copy->destination.level = level; copy->destination.level = level;
copy->destination.slice = slice;
copy->rowPitch = rowPitch; copy->rowPitch = rowPitch;
} }
@ -613,6 +619,7 @@ namespace dawn_native {
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
uint32_t level, uint32_t level,
uint32_t slice,
BufferBase* buffer, BufferBase* buffer,
uint32_t bufferOffset, uint32_t bufferOffset,
uint32_t rowPitch) { uint32_t rowPitch) {
@ -630,6 +637,7 @@ namespace dawn_native {
copy->source.height = height; copy->source.height = height;
copy->source.depth = depth; copy->source.depth = depth;
copy->source.level = level; copy->source.level = level;
copy->source.slice = slice;
copy->destination.buffer = buffer; copy->destination.buffer = buffer;
copy->destination.offset = bufferOffset; copy->destination.offset = bufferOffset;
copy->rowPitch = rowPitch; copy->rowPitch = rowPitch;

View File

@ -77,7 +77,8 @@ namespace dawn_native {
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
uint32_t level); uint32_t level,
uint32_t slice);
void CopyTextureToBuffer(TextureBase* texture, void CopyTextureToBuffer(TextureBase* texture,
uint32_t x, uint32_t x,
uint32_t y, uint32_t y,
@ -86,6 +87,7 @@ namespace dawn_native {
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
uint32_t level, uint32_t level,
uint32_t slice,
BufferBase* buffer, BufferBase* buffer,
uint32_t bufferOffset, uint32_t bufferOffset,
uint32_t rowPitch); uint32_t rowPitch);

View File

@ -64,6 +64,7 @@ namespace dawn_native {
uint32_t x, y, z; uint32_t x, y, z;
uint32_t width, height, depth; uint32_t width, height, depth;
uint32_t level; uint32_t level;
uint32_t slice;
}; };
struct CopyBufferToBufferCmd { struct CopyBufferToBufferCmd {

View File

@ -53,7 +53,7 @@ namespace dawn_native { namespace vulkan {
region.imageSubresource.aspectMask = texture->GetVkAspectMask(); region.imageSubresource.aspectMask = texture->GetVkAspectMask();
region.imageSubresource.mipLevel = textureLocation.level; region.imageSubresource.mipLevel = textureLocation.level;
region.imageSubresource.baseArrayLayer = 0; region.imageSubresource.baseArrayLayer = textureLocation.slice;
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = 1;
region.imageOffset.x = textureLocation.x; region.imageOffset.x = textureLocation.x;

View File

@ -248,7 +248,7 @@ namespace dawn_native { namespace vulkan {
createInfo.format = VulkanImageFormat(GetFormat()); createInfo.format = VulkanImageFormat(GetFormat());
createInfo.extent = VkExtent3D{GetWidth(), GetHeight(), GetDepth()}; createInfo.extent = VkExtent3D{GetWidth(), GetHeight(), GetDepth()};
createInfo.mipLevels = GetNumMipLevels(); createInfo.mipLevels = GetNumMipLevels();
createInfo.arrayLayers = 1; createInfo.arrayLayers = GetArrayLayers();
createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat()); createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat());

View File

@ -259,7 +259,7 @@ std::ostringstream& DawnTest::AddTextureExpectation(const char* file,
// the texture might have been modified. // the texture might have been modified.
dawn::CommandBuffer commands = dawn::CommandBuffer commands =
device.CreateCommandBufferBuilder() device.CreateCommandBufferBuilder()
.CopyTextureToBuffer(source, x, y, 0, width, height, 1, level, readback.buffer, .CopyTextureToBuffer(source, x, y, 0, width, height, 1, level, 0, readback.buffer,
readback.offset, rowPitch) readback.offset, rowPitch)
.GetResult(); .GetResult();

View File

@ -31,6 +31,7 @@ class CopyTests : public DawnTest {
uint32_t copyWidth; uint32_t copyWidth;
uint32_t copyHeight; uint32_t copyHeight;
uint32_t level; uint32_t level;
uint32_t arrayLayer = 1u;
}; };
struct BufferSpec { struct BufferSpec {
@ -57,13 +58,13 @@ class CopyTests : public DawnTest {
class CopyTests_T2B : public CopyTests { class CopyTests_T2B : public CopyTests {
protected: protected:
static void FillTextureData(uint32_t width, uint32_t height, uint32_t texelsPerRow, RGBA8* data) { static void FillTextureData(uint32_t width, uint32_t height, uint32_t texelsPerRow, RGBA8* data, uint32_t layer) {
for (unsigned int y = 0; y < height; ++y) { for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) { for (unsigned int x = 0; x < width; ++x) {
unsigned int i = x + y * texelsPerRow; unsigned int i = x + y * texelsPerRow;
data[i] = RGBA8( data[i] = RGBA8(
static_cast<uint8_t>(x % 256), static_cast<uint8_t>((x + layer * x)% 256),
static_cast<uint8_t>(y % 256), static_cast<uint8_t>((y + layer * y)% 256),
static_cast<uint8_t>(x / 256), static_cast<uint8_t>(x / 256),
static_cast<uint8_t>(y / 256)); static_cast<uint8_t>(y / 256));
} }
@ -77,7 +78,7 @@ class CopyTests_T2B : public CopyTests {
descriptor.width = textureSpec.width; descriptor.width = textureSpec.width;
descriptor.height = textureSpec.height; descriptor.height = textureSpec.height;
descriptor.depth = 1; descriptor.depth = 1;
descriptor.arrayLayer = 1; descriptor.arrayLayer = textureSpec.arrayLayer;
descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm; descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;
descriptor.mipLevel = textureSpec.level + 1; descriptor.mipLevel = textureSpec.level + 1;
descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc; descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc;
@ -87,51 +88,62 @@ class CopyTests_T2B : public CopyTests {
uint32_t height = textureSpec.height >> textureSpec.level; uint32_t height = textureSpec.height >> textureSpec.level;
uint32_t rowPitch = Align(kBytesPerTexel * width, kTextureRowPitchAlignment); uint32_t rowPitch = Align(kBytesPerTexel * width, kTextureRowPitchAlignment);
uint32_t texelsPerRow = rowPitch / kBytesPerTexel; uint32_t texelsPerRow = rowPitch / kBytesPerTexel;
uint32_t texelCount = texelsPerRow * (height - 1) + width; uint32_t texelCountPerLayer = texelsPerRow * (height - 1) + width;
// Create an upload buffer and use it to populate the `level` mip of the texture dawn::CommandBufferBuilder cmdBuilder = device.CreateCommandBufferBuilder();
std::vector<RGBA8> textureData(texelCount);
FillTextureData(width, height, rowPitch / kBytesPerTexel, textureData.data());
dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, textureData.data(), static_cast<uint32_t>(sizeof(RGBA8) * textureData.size()), dawn::BufferUsageBit::TransferSrc);
dawn::CommandBuffer commands[2]; std::vector<std::vector<RGBA8>> textureArrayData(textureSpec.arrayLayer);
for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++slice) {
textureArrayData[slice].resize(texelCountPerLayer);
FillTextureData(width, height, rowPitch / kBytesPerTexel, textureArrayData[slice].data(), slice);
commands[0] = device.CreateCommandBufferBuilder() // Create an upload buffer and use it to populate the current slice of the texture in `level` mip level
.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level) dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, textureArrayData[slice].data(),
.GetResult(); static_cast<uint32_t>(sizeof(RGBA8) * textureArrayData[slice].size()), dawn::BufferUsageBit::TransferSrc);
// Create a buffer of size `size` and populate it with empty data (0,0,0,0) cmdBuilder.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level, slice);
}
// 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 // 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 row pitch is not modified by the copy // and helps ensure that the padding due to the row pitch is not modified by the copy
dawn::BufferDescriptor bufDescriptor; dawn::BufferDescriptor bufDescriptor;
bufDescriptor.size = bufferSpec.size; bufDescriptor.size = bufferSpec.size * textureSpec.arrayLayer;
bufDescriptor.usage = dawn::BufferUsageBit::TransferSrc | dawn::BufferUsageBit::TransferDst; bufDescriptor.usage = dawn::BufferUsageBit::TransferSrc | dawn::BufferUsageBit::TransferDst;
dawn::Buffer buffer = device.CreateBuffer(&bufDescriptor); dawn::Buffer buffer = device.CreateBuffer(&bufDescriptor);
std::vector<RGBA8> emptyData(bufferSpec.size / kBytesPerTexel * textureSpec.arrayLayer);
std::vector<RGBA8> emptyData(bufferSpec.size / kBytesPerTexel);
buffer.SetSubData(0, static_cast<uint32_t>(emptyData.size() * sizeof(RGBA8)), reinterpret_cast<const uint8_t*>(emptyData.data())); buffer.SetSubData(0, static_cast<uint32_t>(emptyData.size() * sizeof(RGBA8)), reinterpret_cast<const uint8_t*>(emptyData.data()));
// Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` mip into the buffer at the specified `offset` and `rowPitch` uint32_t bufferOffset = bufferSpec.offset;
commands[1] = device.CreateCommandBufferBuilder() for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++slice) {
.CopyTextureToBuffer(texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, buffer, bufferSpec.offset, bufferSpec.rowPitch) // Copy the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] from the `level` mip into the buffer at `offset + bufferSpec.size * slice` and `rowPitch`
.GetResult(); cmdBuilder.CopyTextureToBuffer(texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, slice, buffer, bufferOffset, bufferSpec.rowPitch);
bufferOffset += bufferSpec.size;
}
queue.Submit(2, commands); dawn::CommandBuffer commands = cmdBuilder.GetResult();
queue.Submit(1, &commands);
// Pack the data used to create the upload buffer in the specified copy region to have the same format as the expected buffer data. bufferOffset = bufferSpec.offset;
std::vector<RGBA8> expected(bufferSpec.rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth); std::vector<RGBA8> expected(bufferSpec.rowPitch / kBytesPerTexel * (textureSpec.copyHeight - 1) + textureSpec.copyWidth);
for (uint32_t slice = 0; slice < textureSpec.arrayLayer; ++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( PackTextureData(
&textureData[textureSpec.x + textureSpec.y * (rowPitch / kBytesPerTexel)], &textureArrayData[slice][textureSpec.x + textureSpec.y * (rowPitch / kBytesPerTexel)],
textureSpec.copyWidth, textureSpec.copyWidth,
textureSpec.copyHeight, textureSpec.copyHeight,
rowPitch / kBytesPerTexel, rowPitch / kBytesPerTexel,
expected.data(), expected.data(),
bufferSpec.rowPitch / kBytesPerTexel); bufferSpec.rowPitch / kBytesPerTexel);
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, bufferSpec.offset, static_cast<uint32_t>(expected.size())) << EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, bufferOffset, static_cast<uint32_t>(expected.size())) <<
"Texture to Buffer copy failed copying region [(" << textureSpec.x << ", " << textureSpec.y << "), (" << textureSpec.x + textureSpec.copyWidth << ", " << textureSpec.y + textureSpec.copyHeight << "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 << ")) from " << textureSpec.width << " x " << textureSpec.height << " texture at mip level " << textureSpec.level << " layer " << slice <<
" to " << bufferSpec.size << "-byte buffer with offset " << bufferSpec.offset << " and row pitch " << bufferSpec.rowPitch << std::endl; " to " << bufDescriptor.size << "-byte buffer with offset " << bufferOffset << " and row pitch " << bufferSpec.rowPitch << std::endl;
bufferOffset += bufferSpec.size;
}
} }
@ -172,7 +184,7 @@ protected:
descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc; descriptor.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::TransferSrc;
dawn::Texture texture = device.CreateTexture(&descriptor); dawn::Texture texture = device.CreateTexture(&descriptor);
dawn::CommandBuffer commands[2]; dawn::CommandBufferBuilder cmdBuilder = device.CreateCommandBufferBuilder();
// Create an upload buffer filled with empty data and use it to populate the `level` mip of the texture // 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 // Note: Prepopulating the texture with empty data ensures that there is not random data in the expectation
@ -187,17 +199,14 @@ protected:
std::vector<RGBA8> emptyData(texelCount); std::vector<RGBA8> emptyData(texelCount);
dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, emptyData.data(), static_cast<uint32_t>(sizeof(RGBA8) * emptyData.size()), dawn::BufferUsageBit::TransferSrc); dawn::Buffer uploadBuffer = utils::CreateBufferFromData(device, emptyData.data(), static_cast<uint32_t>(sizeof(RGBA8) * emptyData.size()), dawn::BufferUsageBit::TransferSrc);
commands[0] = device.CreateCommandBufferBuilder() cmdBuilder.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level, 0);
.CopyBufferToTexture(uploadBuffer, 0, rowPitch, texture, 0, 0, 0, width, height, 1, textureSpec.level)
.GetResult();
} }
// Copy to the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] at the `level` mip from the buffer at the specified `offset` and `rowPitch` // Copy to the region [(`x`, `y`), (`x + copyWidth, `y + copyWidth`)] at the `level` mip from the buffer at the specified `offset` and `rowPitch`
commands[1] = device.CreateCommandBufferBuilder() cmdBuilder.CopyBufferToTexture(buffer, bufferSpec.offset, bufferSpec.rowPitch, texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level, 0);
.CopyBufferToTexture(buffer, bufferSpec.offset, bufferSpec.rowPitch, texture, textureSpec.x, textureSpec.y, 0, textureSpec.copyWidth, textureSpec.copyHeight, 1, textureSpec.level)
.GetResult();
queue.Submit(2, commands); dawn::CommandBuffer commands = cmdBuilder.GetResult();
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. // 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 rowPitch = Align(kBytesPerTexel * textureSpec.copyWidth, kTextureRowPitchAlignment); uint32_t rowPitch = Align(kBytesPerTexel * textureSpec.copyWidth, kTextureRowPitchAlignment);
@ -355,6 +364,36 @@ TEST_P(CopyTests_T2B, RowPitchUnaligned) {
} }
} }
// Test that copying regions of each texture 2D array layer works
TEST_P(CopyTests_T2B, Texture2DArrayRegion)
{
// TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
if (IsOpenGL() || IsD3D12() || IsMetal()) {
std::cout << "Test skipped on OpenGL, D3D12 and Metal" << std::endl;
return;
}
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));
}
// Test that copying texture 2D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_T2B, Texture2DArrayMip) {
// TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
if (IsOpenGL() || IsD3D12() || IsMetal()) {
std::cout << "Test skipped on OpenGL, D3D12 and Metal" << std::endl;
return;
}
constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kLayers = 6u;
for (unsigned int i = 1; i < 4; ++i) {
DoTest({ kWidth, kHeight, 0, 0, kWidth >> i, kHeight >> i, i, kLayers }, MinimumBufferSpec(kWidth >> i, kHeight >> i));
}
}
DAWN_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend) DAWN_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
// Test that copying an entire texture with 256-byte aligned dimensions works // Test that copying an entire texture with 256-byte aligned dimensions works

View File

@ -101,7 +101,7 @@ protected:
dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data, sizeof(data), dawn::BufferUsageBit::TransferSrc); dawn::Buffer stagingBuffer = utils::CreateBufferFromData(device, data, sizeof(data), dawn::BufferUsageBit::TransferSrc);
dawn::CommandBuffer copy = device.CreateCommandBufferBuilder() dawn::CommandBuffer copy = device.CreateCommandBufferBuilder()
.CopyBufferToTexture(stagingBuffer, 0, 256, texture, 0, 0, 0, 2, 2, 1, 0) .CopyBufferToTexture(stagingBuffer, 0, 256, texture, 0, 0, 0, 2, 2, 1, 0, 0)
.GetResult(); .GetResult();
queue.Submit(1, &copy); queue.Submit(1, &copy);

View File

@ -26,14 +26,14 @@ class CopyCommandTest : public ValidationTest {
return device.CreateBuffer(&descriptor); return device.CreateBuffer(&descriptor);
} }
dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t levels, dawn::Texture Create2DTexture(uint32_t width, uint32_t height, uint32_t levels, uint32_t arrayLayer,
dawn::TextureFormat format, dawn::TextureUsageBit usage) { dawn::TextureFormat format, dawn::TextureUsageBit usage) {
dawn::TextureDescriptor descriptor; dawn::TextureDescriptor descriptor;
descriptor.dimension = dawn::TextureDimension::e2D; descriptor.dimension = dawn::TextureDimension::e2D;
descriptor.width = width; descriptor.width = width;
descriptor.height = height; descriptor.height = height;
descriptor.depth = 1; descriptor.depth = 1;
descriptor.arrayLayer = 1; descriptor.arrayLayer = arrayLayer;
descriptor.format = format; descriptor.format = format;
descriptor.mipLevel = levels; descriptor.mipLevel = levels;
descriptor.usage = usage; descriptor.usage = usage;
@ -124,20 +124,20 @@ class CopyCommandTest_B2T : public CopyCommandTest {
TEST_F(CopyCommandTest_B2T, Success) { TEST_F(CopyCommandTest_B2T, Success) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// Different copies, including some that touch the OOB condition // Different copies, including some that touch the OOB condition
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// Copy 4x4 block in corner of first mip. // Copy 4x4 block in corner of first mip.
.CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
// Copy 4x4 block in opposite corner of first mip. // Copy 4x4 block in opposite corner of first mip.
.CopyBufferToTexture(source, 0, 256, destination, 12, 12, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 12, 12, 0, 4, 4, 1, 0, 0)
// Copy 4x4 block in the 4x4 mip. // Copy 4x4 block in the 4x4 mip.
.CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 2) .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 4, 1, 2, 0)
// Copy with a buffer offset // Copy with a buffer offset
.CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
@ -145,11 +145,11 @@ TEST_F(CopyCommandTest_B2T, Success) {
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// Unaligned region // Unaligned region
.CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 3, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 3, 4, 1, 0, 0)
// Unaligned region with texture offset // Unaligned region with texture offset
.CopyBufferToTexture(source, 0, 256, destination, 5, 7, 0, 2, 3, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 5, 7, 0, 2, 3, 1, 0, 0)
// Unaligned region, with buffer offset // Unaligned region, with buffer offset
.CopyBufferToTexture(source, 31 * 4, 256, destination, 0, 0, 0, 3, 3, 1, 0) .CopyBufferToTexture(source, 31 * 4, 256, destination, 0, 0, 0, 3, 3, 1, 0, 0)
.GetResult(); .GetResult();
} }
@ -157,11 +157,11 @@ TEST_F(CopyCommandTest_B2T, Success) {
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// An empty copy // An empty copy
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0, 0)
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
.CopyBufferToTexture(source, bufferSize, 0, destination, 0, 0, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, bufferSize, 0, destination, 0, 0, 0, 0, 0, 1, 0, 0)
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
.CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 16, 16, 0, 0, 0, 1, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -170,27 +170,27 @@ TEST_F(CopyCommandTest_B2T, Success) {
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) { TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// OOB on the buffer because we copy too many pixels // OOB on the buffer because we copy too many pixels
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 5, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 4, 5, 1, 0, 0)
.GetResult(); .GetResult();
} }
// OOB on the buffer because of the offset // OOB on the buffer because of the offset
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 4, 256, destination, 0, 0, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 4, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows // OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 512, destination, 0, 0, 0, 4, 3, 1, 0) .CopyBufferToTexture(source, 0, 512, destination, 0, 0, 0, 4, 3, 1, 0, 0)
.GetResult(); .GetResult();
} }
@ -201,7 +201,7 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
ASSERT_TRUE(256 * 3 > sourceBufferSize) << "row pitch * height should overflow buffer"; ASSERT_TRUE(256 * 3 > sourceBufferSize) << "row pitch * height should overflow buffer";
dawn::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(sourceBuffer, 0, 256, destination, 0, 0, 0, 7, 3, 1, 0) .CopyBufferToTexture(sourceBuffer, 0, 256, destination, 0, 0, 0, 7, 3, 1, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -210,34 +210,41 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) { TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 2, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, destination, 13, 12, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 13, 12, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// OOB on the texture because y + width overflows // OOB on the texture because y + width overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, destination, 12, 13, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 12, 13, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// OOB on the texture because we overflow a non-zero mip // OOB on the texture because we overflow a non-zero mip
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, destination, 1, 0, 0, 4, 4, 1, 2) .CopyBufferToTexture(source, 0, 256, destination, 1, 0, 0, 4, 4, 1, 2, 0)
.GetResult(); .GetResult();
} }
// OOB on the texture even on an empty copy when we copy to a non-existent mip. // OOB on the texture even on an empty copy when we copy to a non-existent mip.
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 5) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 5, 0)
.GetResult();
}
// OOB on the texture because slice overflows
{
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 1, 0, 2)
.GetResult(); .GetResult();
} }
} }
@ -245,20 +252,20 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
// Test that we force Z=0 and Depth=1 on copies to 2D textures // Test that we force Z=0 and Depth=1 on copies to 2D textures
TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) { TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) {
dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// Z=1 on an empty copy still errors // Z=1 on an empty copy still errors
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 1, 0, 0, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 1, 0, 0, 1, 0, 0)
.GetResult(); .GetResult();
} }
// Depth=0 on an empty copy still errors // Depth=0 on an empty copy still errors
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 0, 0) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 0, 0, 0, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -267,22 +274,22 @@ TEST_F(CopyCommandTest_B2T, ZDepthConstraintFor2DTextures) {
TEST_F(CopyCommandTest_B2T, IncorrectUsage) { TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(16 * 4, dawn::BufferUsageBit::TransferSrc);
dawn::Buffer vertex = CreateBuffer(16 * 4, dawn::BufferUsageBit::Vertex); dawn::Buffer vertex = CreateBuffer(16 * 4, dawn::BufferUsageBit::Vertex);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
dawn::Texture sampled = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::Sampled); dawn::TextureUsageBit::Sampled);
// Incorrect source usage // Incorrect source usage
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(vertex, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0) .CopyBufferToTexture(vertex, 0, 256, destination, 0, 0, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// Incorrect destination usage // Incorrect destination usage
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, sampled, 0, 0, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 256, sampled, 0, 0, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -290,27 +297,27 @@ TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
TEST_F(CopyCommandTest_B2T, IncorrectRowPitch) { TEST_F(CopyCommandTest_B2T, IncorrectRowPitch) {
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// Default row pitch is not 256-byte aligned // Default row pitch is not 256-byte aligned
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 3, 4, 1, 0) .CopyBufferToTexture(source, 0, 0, destination, 0, 0, 0, 3, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// Row pitch is not 256-byte aligned // Row pitch is not 256-byte aligned
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 128, destination, 0, 0, 0, 4, 4, 1, 0) .CopyBufferToTexture(source, 0, 128, destination, 0, 0, 0, 4, 4, 1, 0, 0)
.GetResult(); .GetResult();
} }
// Row pitch is less than width * bytesPerPixel // Row pitch is less than width * bytesPerPixel
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 65, 1, 1, 0) .CopyBufferToTexture(source, 0, 256, destination, 0, 0, 0, 65, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -319,29 +326,29 @@ TEST_F(CopyCommandTest_B2T, IncorrectRowPitch) {
TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) { TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer source = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
dawn::Texture destination = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture destination = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
// Correct usage // Correct usage
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(source, bufferSize - 4, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
// Incorrect usages // Incorrect usages
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, bufferSize - 5, 256, destination, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(source, bufferSize - 5, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, bufferSize - 6, 256, destination, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(source, bufferSize - 6, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyBufferToTexture(source, bufferSize - 7, 256, destination, 0, 0, 0, 1, 1, 1, 0) .CopyBufferToTexture(source, bufferSize - 7, 256, destination, 0, 0, 0, 1, 1, 1, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -352,7 +359,7 @@ class CopyCommandTest_T2B : public CopyCommandTest {
// Test a successfull T2B copy // Test a successfull T2B copy
TEST_F(CopyCommandTest_T2B, Success) { TEST_F(CopyCommandTest_T2B, Success) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
@ -360,13 +367,13 @@ TEST_F(CopyCommandTest_T2B, Success) {
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// Copy from 4x4 block in corner of first mip. // Copy from 4x4 block in corner of first mip.
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 256)
// Copy from 4x4 block in opposite corner of first mip. // Copy from 4x4 block in opposite corner of first mip.
.CopyTextureToBuffer(source, 12, 12, 0, 4, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 12, 12, 0, 4, 4, 1, 0, 0, destination, 0, 256)
// Copy from 4x4 block in the 4x4 mip. // Copy from 4x4 block in the 4x4 mip.
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 2, 0, destination, 0, 256)
// Copy with a buffer offset // Copy with a buffer offset
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 4, 256) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 4, 256)
.GetResult(); .GetResult();
} }
@ -374,11 +381,11 @@ TEST_F(CopyCommandTest_T2B, Success) {
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// Unaligned region // Unaligned region
.CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, 0, destination, 0, 256)
// Unaligned region with texture offset // Unaligned region with texture offset
.CopyTextureToBuffer(source, 5, 7, 0, 2, 3, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 5, 7, 0, 2, 3, 1, 0, 0, destination, 0, 256)
// Unaligned region, with buffer offset // Unaligned region, with buffer offset
.CopyTextureToBuffer(source, 0, 0, 0, 3, 3, 1, 2, destination, 31 * 4, 256) .CopyTextureToBuffer(source, 0, 0, 0, 3, 3, 1, 2, 0, destination, 31 * 4, 256)
.GetResult(); .GetResult();
} }
@ -386,11 +393,11 @@ TEST_F(CopyCommandTest_T2B, Success) {
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
// An empty copy // An empty copy
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, 0, destination, 0, 0)
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, destination, bufferSize, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 0, 0, destination, bufferSize, 0)
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
.CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, destination, 0, 0) .CopyTextureToBuffer(source, 16, 16, 0, 0, 0, 1, 0, 0, destination, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -398,35 +405,35 @@ TEST_F(CopyCommandTest_T2B, Success) {
// Test OOB conditions on the texture // Test OOB conditions on the texture
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) { TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 13, 12, 0, 4, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 13, 12, 0, 4, 4, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// OOB on the texture because y + width overflows // OOB on the texture because y + width overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 12, 13, 0, 4, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 12, 13, 0, 4, 4, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// OOB on the texture because we overflow a non-zero mip // OOB on the texture because we overflow a non-zero mip
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 1, 0, 0, 4, 4, 1, 2, destination, 0, 256) .CopyTextureToBuffer(source, 1, 0, 0, 4, 4, 1, 2, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// OOB on the texture even on an empty copy when we copy from a non-existent mip. // OOB on the texture even on an empty copy when we copy from a non-existent mip.
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 5, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 1, 5, 0, destination, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -434,28 +441,28 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
// Test OOB conditions on the buffer // Test OOB conditions on the buffer
TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) { TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
// OOB on the buffer because we copy too many pixels // OOB on the buffer because we copy too many pixels
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 4, 5, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 4, 5, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// OOB on the buffer because of the offset // OOB on the buffer because of the offset
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 4, 256) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 4, 256)
.GetResult(); .GetResult();
} }
// OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows // OOB on the buffer because (row pitch * (height - 1) + width) * depth overflows
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 4, 3, 1, 0, destination, 0, 512) .CopyTextureToBuffer(source, 0, 0, 0, 4, 3, 1, 0, 0, destination, 0, 512)
.GetResult(); .GetResult();
} }
@ -466,7 +473,7 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
ASSERT_TRUE(256 * 3 > destinationBufferSize) << "row pitch * height should overflow buffer"; ASSERT_TRUE(256 * 3 > destinationBufferSize) << "row pitch * height should overflow buffer";
dawn::Buffer destinationBuffer = CreateBuffer(destinationBufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destinationBuffer = CreateBuffer(destinationBufferSize, dawn::BufferUsageBit::TransferDst);
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 7, 3, 1, 0, destinationBuffer, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 7, 3, 1, 0, 0, destinationBuffer, 0, 256)
.GetResult(); .GetResult();
} }
} }
@ -474,21 +481,21 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
// Test that we force Z=0 and Depth=1 on copies from to 2D textures // Test that we force Z=0 and Depth=1 on copies from to 2D textures
TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) { TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
// Z=1 on an empty copy still errors // Z=1 on an empty copy still errors
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 1, 0, 0, 1, 0, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 1, 0, 0, 1, 0, 0, destination, 0, 0)
.GetResult(); .GetResult();
} }
// Depth=0 on an empty copy still errors // Depth=0 on an empty copy still errors
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 0, 0, destination, 0, 0) .CopyTextureToBuffer(source, 0, 0, 0, 0, 0, 0, 0, 0, destination, 0, 0)
.GetResult(); .GetResult();
} }
} }
@ -496,9 +503,9 @@ TEST_F(CopyCommandTest_T2B, ZDepthConstraintFor2DTextures) {
// Test T2B copies with incorrect buffer usage // Test T2B copies with incorrect buffer usage
TEST_F(CopyCommandTest_T2B, IncorrectUsage) { TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1); uint32_t bufferSize = BufferSizeForTextureCopy(4, 4, 1);
dawn::Texture source = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Texture sampled = Create2DTexture(16, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture sampled = Create2DTexture(16, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::Sampled); dawn::TextureUsageBit::Sampled);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
dawn::Buffer vertex = CreateBuffer(bufferSize, dawn::BufferUsageBit::Vertex); dawn::Buffer vertex = CreateBuffer(bufferSize, dawn::BufferUsageBit::Vertex);
@ -506,42 +513,42 @@ TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
// Incorrect source usage // Incorrect source usage
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(sampled, 0, 0, 0, 4, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(sampled, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// Incorrect destination usage // Incorrect destination usage
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, vertex, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, vertex, 0, 256)
.GetResult(); .GetResult();
} }
} }
TEST_F(CopyCommandTest_T2B, IncorrectRowPitch) { TEST_F(CopyCommandTest_T2B, IncorrectRowPitch) {
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
dawn::Texture source = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferDst); dawn::TextureUsageBit::TransferDst);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferSrc);
// Default row pitch is not 256-byte aligned // Default row pitch is not 256-byte aligned
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 3, 4, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
// Row pitch is not 256-byte aligned // Row pitch is not 256-byte aligned
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, destination, 0, 257) .CopyTextureToBuffer(source, 0, 0, 0, 4, 4, 1, 0, 0, destination, 0, 257)
.GetResult(); .GetResult();
} }
// Row pitch is less than width * bytesPerPixel // Row pitch is less than width * bytesPerPixel
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 65, 1, 1, 0, destination, 0, 256) .CopyTextureToBuffer(source, 0, 0, 0, 65, 1, 1, 0, 0, destination, 0, 256)
.GetResult(); .GetResult();
} }
} }
@ -549,30 +556,30 @@ TEST_F(CopyCommandTest_T2B, IncorrectRowPitch) {
// Test T2B copies with incorrect buffer offset usage // Test T2B copies with incorrect buffer offset usage
TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) { TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) {
uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); uint32_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
dawn::Texture source = Create2DTexture(128, 16, 5, dawn::TextureFormat::R8G8B8A8Unorm, dawn::Texture source = Create2DTexture(128, 16, 5, 1, dawn::TextureFormat::R8G8B8A8Unorm,
dawn::TextureUsageBit::TransferSrc); dawn::TextureUsageBit::TransferSrc);
dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst); dawn::Buffer destination = CreateBuffer(bufferSize, dawn::BufferUsageBit::TransferDst);
// Correct usage // Correct usage
{ {
dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 4, 256) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 4, 256)
.GetResult(); .GetResult();
} }
// Incorrect usages // Incorrect usages
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 5, 256) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 5, 256)
.GetResult(); .GetResult();
} }
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 6, 256) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 6, 256)
.GetResult(); .GetResult();
} }
{ {
dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder()) dawn::CommandBuffer commands = AssertWillBeError(device.CreateCommandBufferBuilder())
.CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, destination, bufferSize - 7, 256) .CopyTextureToBuffer(source, 0, 0, 0, 1, 1, 1, 0, 0, destination, bufferSize - 7, 256)
.GetResult(); .GetResult();
} }
} }