Add WGPU_STRIDE_UNDEFINED and update bytesPerRow/rowsPerImage validation

This makes a nearly one-to-one mapping between the JS and C APIs, which
benefits projects like Blink and Emscripten.

- JavaScript's `undefined` is equivalent to C `WGPU_STRIDE_UNDEFINED`.
- JavaScript's `0` is equivalent to C `0`.
- To implement the API correctly, Blink must special-case an actual
  value coming in from JS that is equal to WGPU_STRIDE_UNDEFINED
  (0xFFFF'FFFF), and inject an error.

Keeps but deprecates a reasonable approximation of the old behavior.

Bug: dawn:520
Change-Id: Ie9c992ffab82830090d0dfc3120731e89cd9691c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31140
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Kai Ninomiya 2020-11-06 13:41:50 +00:00 committed by Commit Bot service account
parent 973d145df8
commit 16036cf206
29 changed files with 712 additions and 369 deletions

View File

@ -1622,8 +1622,8 @@
"extensible": true, "extensible": true,
"members": [ "members": [
{"name": "offset", "type": "uint64_t", "default": 0}, {"name": "offset", "type": "uint64_t", "default": 0},
{"name": "bytes per row", "type": "uint32_t"}, {"name": "bytes per row", "type": "uint32_t", "default": "WGPU_STRIDE_UNDEFINED"},
{"name": "rows per image", "type": "uint32_t", "default": 0} {"name": "rows per image", "type": "uint32_t", "default": "WGPU_STRIDE_UNDEFINED"}
] ]
}, },
"texture descriptor": { "texture descriptor": {

View File

@ -73,8 +73,7 @@ void initTextures() {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 4 * 1024);
utils::CreateBufferCopyView(stagingBuffer, 0, 4 * 1024, 0);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {1024, 1024, 1}; wgpu::Extent3D copySize = {1024, 1024, 1};

View File

@ -74,6 +74,7 @@
#include <stdbool.h> #include <stdbool.h>
#define WGPU_WHOLE_SIZE (0xffffffffffffffffULL) #define WGPU_WHOLE_SIZE (0xffffffffffffffffULL)
#define WGPU_STRIDE_UNDEFINED (0xffffffffUL)
typedef uint32_t WGPUFlags; typedef uint32_t WGPUFlags;

View File

@ -20,6 +20,7 @@
namespace wgpu { namespace wgpu {
static constexpr uint64_t kWholeSize = WGPU_WHOLE_SIZE; static constexpr uint64_t kWholeSize = WGPU_WHOLE_SIZE;
static constexpr uint32_t kStrideUndefined = WGPU_STRIDE_UNDEFINED;
{% for type in by_category["enum"] %} {% for type in by_category["enum"] %}
enum class {{as_cppType(type.name)}} : uint32_t { enum class {{as_cppType(type.name)}} : uint32_t {

View File

@ -580,28 +580,18 @@ namespace dawn_native {
} }
const TexelBlockInfo& blockInfo = const TexelBlockInfo& blockInfo =
destination->texture->GetFormat().GetAspectInfo(destination->aspect).block; destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
TextureDataLayout srcLayout = FixUpDeprecatedTextureDataLayoutOptions(
GetDevice(), source->layout, blockInfo, *copySize);
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(ValidateLinearTextureCopyOffset(source->layout, blockInfo)); DAWN_TRY(ValidateLinearTextureCopyOffset(srcLayout, blockInfo));
DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(), DAWN_TRY(ValidateLinearTextureData(srcLayout, source->buffer->GetSize(), blockInfo,
blockInfo, *copySize)); *copySize));
mTopLevelBuffers.insert(source->buffer); mTopLevelBuffers.insert(source->buffer);
mTopLevelTextures.insert(destination->texture); mTopLevelTextures.insert(destination->texture);
} }
// Compute default value for rowsPerImage ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
uint32_t defaultedRowsPerImage = source->layout.rowsPerImage;
if (defaultedRowsPerImage == 0) {
ASSERT(copySize->height % blockInfo.height == 0);
defaultedRowsPerImage = copySize->height / blockInfo.height;
}
// In the case of one row copy bytesPerRow might not contain enough bytes
uint32_t bytesPerRow = source->layout.bytesPerRow;
if (copySize->height <= 1 && copySize->depth <= 1) {
bytesPerRow =
Align(copySize->width * blockInfo.byteSize, kTextureBytesPerRowAlignment);
}
// Skip noop copies. // Skip noop copies.
if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) { if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
@ -609,9 +599,9 @@ namespace dawn_native {
CopyBufferToTextureCmd* copy = CopyBufferToTextureCmd* copy =
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture); allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
copy->source.buffer = source->buffer; copy->source.buffer = source->buffer;
copy->source.offset = source->layout.offset; copy->source.offset = srcLayout.offset;
copy->source.bytesPerRow = bytesPerRow; copy->source.bytesPerRow = srcLayout.bytesPerRow;
copy->source.rowsPerImage = defaultedRowsPerImage; copy->source.rowsPerImage = srcLayout.rowsPerImage;
copy->destination.texture = destination->texture; copy->destination.texture = destination->texture;
copy->destination.origin = destination->origin; copy->destination.origin = destination->origin;
copy->destination.mipLevel = destination->mipLevel; copy->destination.mipLevel = destination->mipLevel;
@ -645,28 +635,18 @@ namespace dawn_native {
} }
const TexelBlockInfo& blockInfo = const TexelBlockInfo& blockInfo =
source->texture->GetFormat().GetAspectInfo(source->aspect).block; source->texture->GetFormat().GetAspectInfo(source->aspect).block;
TextureDataLayout dstLayout = FixUpDeprecatedTextureDataLayoutOptions(
GetDevice(), destination->layout, blockInfo, *copySize);
if (GetDevice()->IsValidationEnabled()) { if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(ValidateLinearTextureCopyOffset(destination->layout, blockInfo)); DAWN_TRY(ValidateLinearTextureCopyOffset(dstLayout, blockInfo));
DAWN_TRY(ValidateLinearTextureData( DAWN_TRY(ValidateLinearTextureData(dstLayout, destination->buffer->GetSize(),
destination->layout, destination->buffer->GetSize(), blockInfo, *copySize)); blockInfo, *copySize));
mTopLevelTextures.insert(source->texture); mTopLevelTextures.insert(source->texture);
mTopLevelBuffers.insert(destination->buffer); mTopLevelBuffers.insert(destination->buffer);
} }
// Compute default value for rowsPerImage ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
uint32_t defaultedRowsPerImage = destination->layout.rowsPerImage;
if (defaultedRowsPerImage == 0) {
ASSERT(copySize->height % blockInfo.height == 0);
defaultedRowsPerImage = copySize->height / blockInfo.height;
}
// In the case of one row copy bytesPerRow might not contain enough bytes
uint32_t bytesPerRow = destination->layout.bytesPerRow;
if (copySize->height <= 1 && copySize->depth <= 1) {
bytesPerRow =
Align(copySize->width * blockInfo.byteSize, kTextureBytesPerRowAlignment);
}
// Skip noop copies. // Skip noop copies.
if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) { if (copySize->width != 0 && copySize->height != 0 && copySize->depth != 0) {
@ -678,9 +658,9 @@ namespace dawn_native {
copy->source.mipLevel = source->mipLevel; copy->source.mipLevel = source->mipLevel;
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect); copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
copy->destination.buffer = destination->buffer; copy->destination.buffer = destination->buffer;
copy->destination.offset = destination->layout.offset; copy->destination.offset = dstLayout.offset;
copy->destination.bytesPerRow = bytesPerRow; copy->destination.bytesPerRow = dstLayout.bytesPerRow;
copy->destination.rowsPerImage = defaultedRowsPerImage; copy->destination.rowsPerImage = dstLayout.rowsPerImage;
copy->copySize = *copySize; copy->copySize = *copySize;
} }

View File

@ -397,7 +397,6 @@ namespace dawn_native {
uint32_t widthInBlocks = copySize.width / blockInfo.width; uint32_t widthInBlocks = copySize.width / blockInfo.width;
uint32_t heightInBlocks = copySize.height / blockInfo.height; uint32_t heightInBlocks = copySize.height / blockInfo.height;
uint64_t bytesInLastRow = Safe32x32(widthInBlocks, blockInfo.byteSize); uint64_t bytesInLastRow = Safe32x32(widthInBlocks, blockInfo.byteSize);
uint64_t bytesPerImage = Safe32x32(bytesPerRow, rowsPerImage);
if (copySize.depth == 0) { if (copySize.depth == 0) {
return 0; return 0;
@ -406,7 +405,7 @@ namespace dawn_native {
// Check for potential overflows for the rest of the computations. We have the following // Check for potential overflows for the rest of the computations. We have the following
// inequalities: // inequalities:
// //
// lastRowBytes <= bytesPerRow // bytesInLastRow <= bytesPerRow
// heightInBlocks <= rowsPerImage // heightInBlocks <= rowsPerImage
// //
// So: // So:
@ -418,12 +417,16 @@ namespace dawn_native {
// //
// This means that if the computation of depth * bytesPerImage doesn't overflow, none of the // This means that if the computation of depth * bytesPerImage doesn't overflow, none of the
// computations for requiredBytesInCopy will. (and it's not a very pessimizing check) // computations for requiredBytesInCopy will. (and it's not a very pessimizing check)
ASSERT(copySize.depth <= 1 ||
(bytesPerRow != wgpu::kStrideUndefined && rowsPerImage != wgpu::kStrideUndefined));
uint64_t bytesPerImage = Safe32x32(bytesPerRow, rowsPerImage);
if (bytesPerImage > std::numeric_limits<uint64_t>::max() / copySize.depth) { if (bytesPerImage > std::numeric_limits<uint64_t>::max() / copySize.depth) {
return DAWN_VALIDATION_ERROR("requiredBytesInCopy is too large."); return DAWN_VALIDATION_ERROR("requiredBytesInCopy is too large.");
} }
uint64_t requiredBytesInCopy = bytesPerImage * (copySize.depth - 1); uint64_t requiredBytesInCopy = bytesPerImage * (copySize.depth - 1);
if (heightInBlocks > 0) { if (heightInBlocks > 0) {
ASSERT(heightInBlocks <= 1 || bytesPerRow != wgpu::kStrideUndefined);
uint64_t bytesInLastImage = Safe32x32(bytesPerRow, heightInBlocks - 1) + bytesInLastRow; uint64_t bytesInLastImage = Safe32x32(bytesPerRow, heightInBlocks - 1) + bytesInLastRow;
requiredBytesInCopy += bytesInLastImage; requiredBytesInCopy += bytesInLastImage;
} }
@ -442,40 +445,98 @@ namespace dawn_native {
return {}; return {};
} }
MaybeError ValidateLinearTextureData(TextureDataLayout layout, TextureDataLayout FixUpDeprecatedTextureDataLayoutOptions(
uint64_t byteSize, DeviceBase* device,
const TexelBlockInfo& blockInfo, const TextureDataLayout& originalLayout,
const Extent3D& copyExtent) { const TexelBlockInfo& blockInfo,
ASSERT(copyExtent.width % blockInfo.width == 0); const Extent3D& copyExtent) {
uint32_t widthInBlocks = copyExtent.width / blockInfo.width; // TODO(crbug.com/dawn/520): Remove deprecated functionality.
ASSERT(copyExtent.height % blockInfo.height == 0); TextureDataLayout layout = originalLayout;
uint32_t heightInBlocks = copyExtent.height / blockInfo.height;
// Default value for rowsPerImage if (copyExtent.height != 0 && layout.rowsPerImage == 0) {
if (layout.rowsPerImage == 0) { if (copyExtent.depth > 1) {
layout.rowsPerImage = heightInBlocks; device->EmitDeprecationWarning(
} "rowsPerImage soon must be non-zero if copy depth > 1 (it will no longer "
"default to the copy height).");
// Validation for other members in layout: ASSERT(copyExtent.height % blockInfo.height == 0);
ASSERT(Safe32x32(widthInBlocks, blockInfo.byteSize) <= uint32_t heightInBlocks = copyExtent.height / blockInfo.height;
std::numeric_limits<uint32_t>::max()); layout.rowsPerImage = heightInBlocks;
uint32_t lastRowBytes = widthInBlocks * blockInfo.byteSize; } else if (copyExtent.depth == 1) {
if (lastRowBytes > layout.bytesPerRow) { device->EmitDeprecationWarning(
if (copyExtent.height > 1 || copyExtent.depth > 1) { "rowsPerImage soon must be non-zero or unspecified if copy depth == 1 (it will "
return DAWN_VALIDATION_ERROR("The byte size of a row must be <= bytesPerRow."); "no longer default to the copy height).");
} else { layout.rowsPerImage = wgpu::kStrideUndefined;
// bytesPerRow is unused. Populate it with a valid value for later validation.
layout.bytesPerRow = lastRowBytes;
} }
} }
// TODO(tommek@google.com): to match the spec there should be another condition here // Only bother to fix-up for height == 1 && depth == 1.
// on rowsPerImage >= copyExtent.height if copyExtent.depth > 1. // The other cases that used to be allowed were zero-size copies.
ASSERT(copyExtent.width % blockInfo.width == 0);
uint32_t widthInBlocks = copyExtent.width / blockInfo.width;
uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize;
if (copyExtent.height == 1 && copyExtent.depth == 1 &&
bytesInLastRow > layout.bytesPerRow) {
device->EmitDeprecationWarning(
"Soon, even if copy height == 1, bytesPerRow must be >= the byte size of each row "
"or left unspecified.");
layout.bytesPerRow = wgpu::kStrideUndefined;
}
return layout;
}
// Validation for the copy being in-bounds: // Replace wgpu::kStrideUndefined with real values, so backends don't have to think about it.
if (layout.rowsPerImage != 0 && layout.rowsPerImage < heightInBlocks) { void ApplyDefaultTextureDataLayoutOptions(TextureDataLayout* layout,
const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent) {
ASSERT(layout != nullptr);
ASSERT(copyExtent.height % blockInfo.height == 0);
uint32_t heightInBlocks = copyExtent.height / blockInfo.height;
if (layout->bytesPerRow == wgpu::kStrideUndefined) {
ASSERT(copyExtent.width % blockInfo.width == 0);
uint32_t widthInBlocks = copyExtent.width / blockInfo.width;
uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize;
ASSERT(heightInBlocks <= 1 && copyExtent.depth <= 1);
layout->bytesPerRow = Align(bytesInLastRow, kTextureBytesPerRowAlignment);
}
if (layout->rowsPerImage == wgpu::kStrideUndefined) {
ASSERT(copyExtent.depth <= 1);
layout->rowsPerImage = heightInBlocks;
}
}
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
uint64_t byteSize,
const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent) {
ASSERT(copyExtent.height % blockInfo.height == 0);
uint32_t heightInBlocks = copyExtent.height / blockInfo.height;
if (copyExtent.depth > 1 && (layout.bytesPerRow == wgpu::kStrideUndefined ||
layout.rowsPerImage == wgpu::kStrideUndefined)) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"rowsPerImage must not be less than the copy height in blocks."); "If copy depth > 1, bytesPerRow and rowsPerImage must be specified.");
}
if (heightInBlocks > 1 && layout.bytesPerRow == wgpu::kStrideUndefined) {
return DAWN_VALIDATION_ERROR("If heightInBlocks > 1, bytesPerRow must be specified.");
}
// Validation for other members in layout:
ASSERT(copyExtent.width % blockInfo.width == 0);
uint32_t widthInBlocks = copyExtent.width / blockInfo.width;
ASSERT(Safe32x32(widthInBlocks, blockInfo.byteSize) <=
std::numeric_limits<uint32_t>::max());
uint32_t bytesInLastRow = widthInBlocks * blockInfo.byteSize;
// These != wgpu::kStrideUndefined checks are technically redundant with the > checks, but
// they should get optimized out.
if (layout.bytesPerRow != wgpu::kStrideUndefined && bytesInLastRow > layout.bytesPerRow) {
return DAWN_VALIDATION_ERROR("The byte size of each row must be <= bytesPerRow.");
}
if (layout.rowsPerImage != wgpu::kStrideUndefined && heightInBlocks > layout.rowsPerImage) {
return DAWN_VALIDATION_ERROR(
"The height of each image, in blocks, must be <= rowsPerImage.");
} }
// We compute required bytes in copy after validating texel block alignments // We compute required bytes in copy after validating texel block alignments
@ -499,8 +560,10 @@ namespace dawn_native {
MaybeError ValidateBufferCopyView(DeviceBase const* device, MaybeError ValidateBufferCopyView(DeviceBase const* device,
const BufferCopyView& bufferCopyView) { const BufferCopyView& bufferCopyView) {
DAWN_TRY(device->ValidateObject(bufferCopyView.buffer)); DAWN_TRY(device->ValidateObject(bufferCopyView.buffer));
if (bufferCopyView.layout.bytesPerRow % kTextureBytesPerRowAlignment != 0) { if (bufferCopyView.layout.bytesPerRow != wgpu::kStrideUndefined) {
return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256"); if (bufferCopyView.layout.bytesPerRow % kTextureBytesPerRowAlignment != 0) {
return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256");
}
} }
return {}; return {};

View File

@ -51,7 +51,15 @@ namespace dawn_native {
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage); uint32_t rowsPerImage);
MaybeError ValidateLinearTextureData(TextureDataLayout layout, TextureDataLayout FixUpDeprecatedTextureDataLayoutOptions(
DeviceBase* device,
const TextureDataLayout& originalLayout,
const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent);
void ApplyDefaultTextureDataLayoutOptions(TextureDataLayout* layout,
const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent);
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
uint64_t byteSize, uint64_t byteSize,
const TexelBlockInfo& blockInfo, const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent); const Extent3D& copyExtent);

View File

@ -127,6 +127,10 @@ namespace dawn_native {
// formats are set exactly once. // formats are set exactly once.
ASSERT(!formatsSet[index]); ASSERT(!formatsSet[index]);
// Vulkan describes bytesPerRow in units of texels. If there's any format for which this
// ASSERT isn't true, then additional validation on bytesPerRow must be added.
ASSERT((kTextureBytesPerRowAlignment % format.firstAspect.block.byteSize) == 0);
table[index] = format; table[index] = format;
formatsSet.set(index); formatsSet.set(index);
}; };

View File

@ -441,10 +441,13 @@ namespace dawn_native {
// copyExtent.height by blockHeight while the divisibility conditions are // copyExtent.height by blockHeight while the divisibility conditions are
// checked in validating texture copy range. // checked in validating texture copy range.
DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize)); DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize));
DAWN_TRY(ValidateLinearTextureData(
*dataLayout, dataSize, const TexelBlockInfo& blockInfo =
destination->texture->GetFormat().GetAspectInfo(destination->aspect).block, destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
*writeSize));
TextureDataLayout layout = FixUpDeprecatedTextureDataLayoutOptions(GetDevice(), *dataLayout,
blockInfo, *writeSize);
DAWN_TRY(ValidateLinearTextureData(layout, dataSize, blockInfo, *writeSize));
DAWN_TRY(destination->texture->ValidateCanUseInSubmitNow()); DAWN_TRY(destination->texture->ValidateCanUseInSubmitNow());

View File

@ -889,7 +889,7 @@ std::ostringstream& DawnTestBase::AddTextureExpectationImpl(const char* file,
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, level, {x, y, slice}, aspect); utils::CreateTextureCopyView(texture, level, {x, y, slice}, aspect);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(readback.buffer, readback.offset, bytesPerRow, 0); utils::CreateBufferCopyView(readback.buffer, readback.offset, bytesPerRow, rowsPerImage);
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();

View File

@ -304,7 +304,7 @@ TEST_P(BindGroupTests, UBOSamplerAndTexture) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, widthInBytes, 0); utils::CreateBufferCopyView(stagingBuffer, 0, widthInBytes);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);

View File

@ -30,7 +30,7 @@ struct CopyConfig {
uint32_t viewMipmapLevel = 0; uint32_t viewMipmapLevel = 0;
uint32_t bufferOffset = 0; uint32_t bufferOffset = 0;
uint32_t bytesPerRowAlignment = kTextureBytesPerRowAlignment; uint32_t bytesPerRowAlignment = kTextureBytesPerRowAlignment;
uint32_t rowsPerImage = 0; uint32_t rowsPerImage = wgpu::kStrideUndefined;
}; };
class CompressedTextureBCFormatTest : public DawnTest { class CompressedTextureBCFormatTest : public DawnTest {
@ -60,7 +60,7 @@ class CompressedTextureBCFormatTest : public DawnTest {
utils::GetTexelBlockSizeInBytes(copyConfig.textureDescriptor.format); utils::GetTexelBlockSizeInBytes(copyConfig.textureDescriptor.format);
} }
uint32_t copyRowsPerImage = copyConfig.rowsPerImage; uint32_t copyRowsPerImage = copyConfig.rowsPerImage;
if (copyRowsPerImage == 0) { if (copyRowsPerImage == wgpu::kStrideUndefined) {
copyRowsPerImage = copyHeightInBlock; copyRowsPerImage = copyHeightInBlock;
} }
uint32_t copyBytesPerImage = copyBytesPerRow * copyRowsPerImage; uint32_t copyBytesPerImage = copyBytesPerRow * copyRowsPerImage;
@ -1028,6 +1028,7 @@ TEST_P(CompressedTextureBCFormatTest, CopyWhole2DArrayTexture) {
CopyConfig config; CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage; config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, kArrayLayerCount}; config.textureDescriptor.size = {8, 8, kArrayLayerCount};
config.rowsPerImage = 8;
config.copyExtent3D = config.textureDescriptor.size; config.copyExtent3D = config.textureDescriptor.size;
config.copyExtent3D.depth = kArrayLayerCount; config.copyExtent3D.depth = kArrayLayerCount;
@ -1054,6 +1055,7 @@ TEST_P(CompressedTextureBCFormatTest, CopyMultiple2DArrayLayers) {
CopyConfig config; CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage; config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, kArrayLayerCount}; config.textureDescriptor.size = {8, 8, kArrayLayerCount};
config.rowsPerImage = 8;
constexpr uint32_t kCopyBaseArrayLayer = 1; constexpr uint32_t kCopyBaseArrayLayer = 1;
constexpr uint32_t kCopyLayerCount = 2; constexpr uint32_t kCopyLayerCount = 2;
@ -1087,7 +1089,7 @@ TEST_P(CompressedTextureBCFormatTest, UnalignedDynamicUploader) {
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, 256, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, 256);
wgpu::Extent3D copyExtent = {4, 4, 1}; wgpu::Extent3D copyExtent = {4, 4, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();

View File

@ -21,6 +21,9 @@
#include "utils/TextureFormatUtils.h" #include "utils/TextureFormatUtils.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
// For MinimumBufferSpec bytesPerRow and rowsPerImage, compute a default from the copy extent.
constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul;
class CopyTests : public DawnTest { class CopyTests : public DawnTest {
protected: protected:
static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
@ -56,18 +59,27 @@ class CopyTests : public DawnTest {
return textureData; return textureData;
} }
static BufferSpec MinimumBufferSpec(uint32_t width, static BufferSpec MinimumBufferSpec(uint32_t width, uint32_t height, uint32_t depth = 1) {
uint32_t height, return MinimumBufferSpec({width, height, depth}, kStrideComputeDefault,
uint32_t arrayLayer = 1, depth == 1 ? wgpu::kStrideUndefined : kStrideComputeDefault);
bool testZeroRowsPerImage = true) {
const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, width);
const uint32_t rowsPerImage = height;
const uint32_t totalBufferSize = utils::RequiredBytesInCopy(
bytesPerRow, rowsPerImage, {width, height, arrayLayer}, kTextureFormat);
uint32_t appliedRowsPerImage = testZeroRowsPerImage ? 0 : height;
return {totalBufferSize, 0, bytesPerRow, appliedRowsPerImage};
} }
static BufferSpec MinimumBufferSpec(wgpu::Extent3D copyExtent,
uint32_t overrideBytesPerRow = kStrideComputeDefault,
uint32_t overrideRowsPerImage = kStrideComputeDefault) {
uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, copyExtent.width);
if (overrideBytesPerRow != kStrideComputeDefault) {
bytesPerRow = overrideBytesPerRow;
}
uint32_t rowsPerImage = copyExtent.height;
if (overrideRowsPerImage != kStrideComputeDefault) {
rowsPerImage = overrideRowsPerImage;
}
uint32_t totalDataSize =
utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, copyExtent, kTextureFormat);
return {totalDataSize, 0, bytesPerRow, rowsPerImage};
}
static void PackTextureData(const RGBA8* srcData, static void PackTextureData(const RGBA8* srcData,
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
@ -100,10 +112,11 @@ class CopyTests_T2B : public CopyTests {
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
wgpu::Texture texture = device.CreateTexture(&descriptor); wgpu::Texture texture = device.CreateTexture(&descriptor);
// Layout for initial data upload to texture.
// Some parts of this result are also reused later.
const utils::TextureDataCopyLayout copyLayout = const utils::TextureDataCopyLayout copyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
kTextureFormat, textureSpec.textureSize, textureSpec.level, kTextureFormat, textureSpec.textureSize, textureSpec.level);
bufferSpec.rowsPerImage);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -113,7 +126,7 @@ class CopyTests_T2B : public CopyTests {
wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( wgpu::Buffer uploadBuffer = utils::CreateBufferFromData(
device, textureArrayData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); device, textureArrayData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
uploadBuffer, 0, copyLayout.bytesPerRow, bufferSpec.rowsPerImage); uploadBuffer, 0, copyLayout.bytesPerRow, copyLayout.rowsPerImage);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0}); utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0});
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize);
@ -156,22 +169,23 @@ class CopyTests_T2B : public CopyTests {
texelIndexOffset + (textureSpec.copyOrigin.x + texelIndexOffset + (textureSpec.copyOrigin.x +
textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow); textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow);
PackTextureData(&textureArrayData[expectedTexelArrayDataStartIndex], copySize.width, PackTextureData(textureArrayData.data() + expectedTexelArrayDataStartIndex,
copySize.height, copyLayout.texelBlocksPerRow, expected.data(), copySize.width, copySize.height, copyLayout.texelBlocksPerRow,
bufferSpec.bytesPerRow / bytesPerTexel); expected.data(), bufferSpec.bytesPerRow / bytesPerTexel);
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer,
bufferOffset, static_cast<uint32_t>(expected.size())) bufferOffset, static_cast<uint32_t>(expected.size()))
<< "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x << "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x
<< ", " << textureSpec.copyOrigin.y << "), (" << ", " << textureSpec.copyOrigin.y << ", " << textureSpec.copyOrigin.z << "), ("
<< textureSpec.copyOrigin.x + copySize.width << ", " << textureSpec.copyOrigin.x + copySize.width << ", "
<< textureSpec.copyOrigin.y + copySize.height << ")) from " << textureSpec.copyOrigin.y + copySize.height << ", "
<< textureSpec.copyOrigin.z + copySize.depth << ")) from "
<< textureSpec.textureSize.width << " x " << textureSpec.textureSize.height << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height
<< " texture at mip level " << textureSpec.level << " layer " << slice << " to " << " texture at mip level " << textureSpec.level << " layer " << slice << " to "
<< bufferSpec.size << "-byte buffer with offset " << bufferOffset << bufferSpec.size << "-byte buffer with offset " << bufferOffset
<< " and bytes per row " << bufferSpec.bytesPerRow << std::endl; << " and bytes per row " << bufferSpec.bytesPerRow << std::endl;
bufferOffset += copyLayout.bytesPerImage; bufferOffset += bufferSpec.bytesPerRow * bufferSpec.rowsPerImage;
} }
} }
}; };
@ -232,7 +246,7 @@ class CopyTests_B2T : public CopyTests {
// Pack the data used to create the buffer in the specified copy region to have the same // Pack the data used to create the buffer in the specified copy region to have the same
// format as the expected texture data. // format as the expected texture data.
std::vector<RGBA8> expected(texelCountLastLayer); std::vector<RGBA8> expected(texelCountLastLayer);
PackTextureData(&bufferData[bufferOffset / bytesPerTexel], copySize.width, PackTextureData(bufferData.data() + bufferOffset / bytesPerTexel, copySize.width,
copySize.height, bufferSpec.bytesPerRow / bytesPerTexel, copySize.height, bufferSpec.bytesPerRow / bytesPerTexel,
expected.data(), copySize.width); expected.data(), copySize.width);
@ -288,14 +302,14 @@ class CopyTests_T2T : public CopyTests {
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
kTextureFormat, kTextureFormat,
{srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth}, {srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth},
srcSpec.level, 0); srcSpec.level);
const std::vector<RGBA8> textureArrayCopyData = GetExpectedTextureData(copyLayout); const std::vector<RGBA8> textureArrayCopyData = GetExpectedTextureData(copyLayout);
wgpu::Buffer uploadBuffer = utils::CreateBufferFromData( wgpu::Buffer uploadBuffer = utils::CreateBufferFromData(
device, textureArrayCopyData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc); device, textureArrayCopyData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
utils::CreateBufferCopyView(uploadBuffer, 0, copyLayout.bytesPerRow, 0); uploadBuffer, 0, copyLayout.bytesPerRow, copyLayout.rowsPerImage);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z}); utils::CreateTextureCopyView(srcTexture, srcSpec.level, {0, 0, srcSpec.copyOrigin.z});
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize);
@ -633,7 +647,7 @@ TEST_P(CopyTests_T2B, OffsetBufferUnaligned) {
// Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row
// works // works
TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) { TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallBytesPerRow) {
constexpr uint32_t kWidth = 32; constexpr uint32_t kWidth = 32;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
@ -652,7 +666,7 @@ TEST_P(CopyTests_T2B, OffsetBufferUnalignedSmallRowPitch) {
} }
// Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works
TEST_P(CopyTests_T2B, RowPitchAligned) { TEST_P(CopyTests_T2B, BytesPerRowAligned) {
constexpr uint32_t kWidth = 256; constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
@ -671,7 +685,7 @@ TEST_P(CopyTests_T2B, RowPitchAligned) {
// Test that copying with a greater bytes per row than needed on a texture that is not 256-byte // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte
// aligned works // aligned works
TEST_P(CopyTests_T2B, RowPitchUnaligned) { TEST_P(CopyTests_T2B, BytesPerRowUnaligned) {
constexpr uint32_t kWidth = 259; constexpr uint32_t kWidth = 259;
constexpr uint32_t kHeight = 127; constexpr uint32_t kHeight = 127;
@ -699,18 +713,55 @@ TEST_P(CopyTests_T2B, BytesPerRowWithOneRowCopy) {
textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.textureSize = {kWidth, kHeight, 1};
textureSpec.level = 0; textureSpec.level = 0;
// bytesPerRow = 0
{ {
BufferSpec bufferSpec = MinimumBufferSpec(5, 1); BufferSpec bufferSpec = MinimumBufferSpec(5, 1);
// bytesPerRow = 0
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
bufferSpec.bytesPerRow = 0; bufferSpec.bytesPerRow = 0;
EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {5, 1, 1}));
// bytesPerRow undefined
bufferSpec.bytesPerRow = wgpu::kStrideUndefined;
DoTest(textureSpec, bufferSpec, {5, 1, 1}); DoTest(textureSpec, bufferSpec, {5, 1, 1});
} }
// bytesPerRow < bytesInACompleteRow // bytesPerRow < bytesInACompleteRow
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
{ {
BufferSpec bufferSpec = MinimumBufferSpec(259, 1); BufferSpec bufferSpec = MinimumBufferSpec(259, 1);
bufferSpec.bytesPerRow = 256; bufferSpec.bytesPerRow = 256;
DoTest(textureSpec, bufferSpec, {259, 1, 1}); EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {259, 1, 1}));
}
}
TEST_P(CopyTests_T2B, StrideSpecialCases) {
TextureSpec textureSpec;
textureSpec.copyOrigin = {0, 0, 0};
textureSpec.textureSize = {4, 4, 4};
textureSpec.level = 0;
// bytesPerRow 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent);
}
// bytesPerRow undefined
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent);
}
// rowsPerImage 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent);
}
// rowsPerImage undefined
for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent);
} }
} }
@ -780,7 +831,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionNonzeroRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
} }
@ -801,7 +852,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetOddRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.offset += 128u; bufferSpec.offset += 128u;
bufferSpec.size += 128u; bufferSpec.size += 128u;
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;
@ -824,7 +875,7 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionWithOffsetEvenRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.offset += 128u; bufferSpec.offset += 128u;
bufferSpec.size += 128u; bufferSpec.size += 128u;
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;
@ -1083,7 +1134,7 @@ TEST_P(CopyTests_B2T, OffsetBufferUnaligned) {
// Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row // Test that copying without a 512-byte aligned buffer offset that is greater than the bytes per row
// works // works
TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) { TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallBytesPerRow) {
constexpr uint32_t kWidth = 32; constexpr uint32_t kWidth = 32;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
@ -1102,7 +1153,7 @@ TEST_P(CopyTests_B2T, OffsetBufferUnalignedSmallRowPitch) {
} }
// Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works // Test that copying with a greater bytes per row than needed on a 256-byte aligned texture works
TEST_P(CopyTests_B2T, RowPitchAligned) { TEST_P(CopyTests_B2T, BytesPerRowAligned) {
constexpr uint32_t kWidth = 256; constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
@ -1121,7 +1172,7 @@ TEST_P(CopyTests_B2T, RowPitchAligned) {
// Test that copying with a greater bytes per row than needed on a texture that is not 256-byte // Test that copying with a greater bytes per row than needed on a texture that is not 256-byte
// aligned works // aligned works
TEST_P(CopyTests_B2T, RowPitchUnaligned) { TEST_P(CopyTests_B2T, BytesPerRowUnaligned) {
constexpr uint32_t kWidth = 259; constexpr uint32_t kWidth = 259;
constexpr uint32_t kHeight = 127; constexpr uint32_t kHeight = 127;
@ -1149,18 +1200,55 @@ TEST_P(CopyTests_B2T, BytesPerRowWithOneRowCopy) {
textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.textureSize = {kWidth, kHeight, 1};
textureSpec.level = 0; textureSpec.level = 0;
// bytesPerRow = 0
{ {
BufferSpec bufferSpec = MinimumBufferSpec(5, 1); BufferSpec bufferSpec = MinimumBufferSpec(5, 1);
// bytesPerRow = 0
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
bufferSpec.bytesPerRow = 0; bufferSpec.bytesPerRow = 0;
EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {5, 1, 1}));
// bytesPerRow undefined
bufferSpec.bytesPerRow = wgpu::kStrideUndefined;
DoTest(textureSpec, bufferSpec, {5, 1, 1}); DoTest(textureSpec, bufferSpec, {5, 1, 1});
} }
// bytesPerRow < bytesInACompleteRow // bytesPerRow < bytesInACompleteRow
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
{ {
BufferSpec bufferSpec = MinimumBufferSpec(259, 1); BufferSpec bufferSpec = MinimumBufferSpec(259, 1);
bufferSpec.bytesPerRow = 256; bufferSpec.bytesPerRow = 256;
DoTest(textureSpec, bufferSpec, {259, 1, 1}); EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, bufferSpec, {259, 1, 1}));
}
}
TEST_P(CopyTests_B2T, StrideSpecialCases) {
TextureSpec textureSpec;
textureSpec.copyOrigin = {0, 0, 0};
textureSpec.textureSize = {4, 4, 4};
textureSpec.level = 0;
// bytesPerRow 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 0, 2), copyExtent);
}
// bytesPerRow undefined
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent);
}
// rowsPerImage 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, 0), copyExtent);
}
// rowsPerImage undefined
for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) {
DoTest(textureSpec, MinimumBufferSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent);
} }
} }
@ -1211,7 +1299,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionNonzeroRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
} }
@ -1232,7 +1320,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetOddRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.offset += 128u; bufferSpec.offset += 128u;
bufferSpec.size += 128u; bufferSpec.size += 128u;
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;
@ -1255,7 +1343,7 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionWithOffsetEvenRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kLayers}; textureSpec.textureSize = {kWidth, kHeight, kLayers};
textureSpec.level = 0; textureSpec.level = 0;
BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers, false); BufferSpec bufferSpec = MinimumBufferSpec(kWidth, kRowsPerImage, kCopyLayers);
bufferSpec.offset += 128u; bufferSpec.offset += 128u;
bufferSpec.size += 128u; bufferSpec.size += 128u;
bufferSpec.rowsPerImage = kRowsPerImage; bufferSpec.rowsPerImage = kRowsPerImage;

View File

@ -92,7 +92,7 @@ class CopyTextureForBrowserTests : public DawnTest {
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTexture2DAtLevel(
kTextureFormat, kTextureFormat,
{srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth}, {srcSpec.textureSize.width, srcSpec.textureSize.height, copySize.depth},
srcSpec.level, 0); srcSpec.level);
const std::vector<RGBA8> textureArrayCopyData = GetExpectedTextureData(copyLayout); const std::vector<RGBA8> textureArrayCopyData = GetExpectedTextureData(copyLayout);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
@ -101,7 +101,7 @@ class CopyTextureForBrowserTests : public DawnTest {
wgpu::TextureDataLayout textureDataLayout; wgpu::TextureDataLayout textureDataLayout;
textureDataLayout.offset = 0; textureDataLayout.offset = 0;
textureDataLayout.bytesPerRow = copyLayout.bytesPerRow; textureDataLayout.bytesPerRow = copyLayout.bytesPerRow;
textureDataLayout.rowsPerImage = copyLayout.bytesPerImage / copyLayout.bytesPerRow; textureDataLayout.rowsPerImage = copyLayout.rowsPerImage;
device.GetDefaultQueue().WriteTexture(&textureCopyView, textureArrayCopyData.data(), device.GetDefaultQueue().WriteTexture(&textureCopyView, textureArrayCopyData.data(),
textureArrayCopyData.size() * sizeof(RGBA8), textureArrayCopyData.size() * sizeof(RGBA8),

View File

@ -134,7 +134,7 @@ TEST_P(NonzeroTextureCreationTests, NonrenderableTextureFormat) {
wgpu::Buffer bufferDst = utils::CreateBufferFromData( wgpu::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -168,7 +168,7 @@ TEST_P(NonzeroTextureCreationTests, NonRenderableTextureClearWithMultiArrayLayer
wgpu::Buffer bufferDst = utils::CreateBufferFromData( wgpu::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, kSize * 4);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};

View File

@ -199,6 +199,9 @@ DAWN_INSTANTIATE_TEST(QueueWriteBufferTests,
OpenGLBackend(), OpenGLBackend(),
VulkanBackend()); VulkanBackend());
// For MinimumDataSpec bytesPerRow and rowsPerImage, compute a default from the copy extent.
constexpr uint32_t kStrideComputeDefault = 0xFFFF'FFFEul;
class QueueWriteTextureTests : public DawnTest { class QueueWriteTextureTests : public DawnTest {
protected: protected:
static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
@ -217,14 +220,17 @@ class QueueWriteTextureTests : public DawnTest {
}; };
static DataSpec MinimumDataSpec(wgpu::Extent3D writeSize, static DataSpec MinimumDataSpec(wgpu::Extent3D writeSize,
uint32_t bytesPerRow = 0, uint32_t overrideBytesPerRow = kStrideComputeDefault,
uint32_t rowsPerImage = 0) { uint32_t overrideRowsPerImage = kStrideComputeDefault) {
if (bytesPerRow == 0) { uint32_t bytesPerRow = writeSize.width * utils::GetTexelBlockSizeInBytes(kTextureFormat);
bytesPerRow = writeSize.width * utils::GetTexelBlockSizeInBytes(kTextureFormat); if (overrideBytesPerRow != kStrideComputeDefault) {
bytesPerRow = overrideBytesPerRow;
} }
if (rowsPerImage == 0) { uint32_t rowsPerImage = writeSize.height;
rowsPerImage = writeSize.height; if (overrideRowsPerImage != kStrideComputeDefault) {
rowsPerImage = overrideRowsPerImage;
} }
uint32_t totalDataSize = uint32_t totalDataSize =
utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, writeSize, kTextureFormat); utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, writeSize, kTextureFormat);
return {totalDataSize, 0, bytesPerRow, rowsPerImage}; return {totalDataSize, 0, bytesPerRow, rowsPerImage};
@ -282,10 +288,14 @@ class QueueWriteTextureTests : public DawnTest {
wgpu::Extent3D mipSize = {textureSpec.textureSize.width >> textureSpec.level, wgpu::Extent3D mipSize = {textureSpec.textureSize.width >> textureSpec.level,
textureSpec.textureSize.height >> textureSpec.level, textureSpec.textureSize.height >> textureSpec.level,
textureSpec.textureSize.depth}; textureSpec.textureSize.depth};
uint32_t alignedBytesPerRow = Align(dataSpec.bytesPerRow, bytesPerTexel); uint32_t bytesPerRow = dataSpec.bytesPerRow;
if (bytesPerRow == wgpu::kStrideUndefined) {
bytesPerRow = mipSize.width * bytesPerTexel;
}
uint32_t alignedBytesPerRow = Align(bytesPerRow, bytesPerTexel);
uint32_t appliedRowsPerImage = uint32_t appliedRowsPerImage =
dataSpec.rowsPerImage > 0 ? dataSpec.rowsPerImage : mipSize.height; dataSpec.rowsPerImage > 0 ? dataSpec.rowsPerImage : mipSize.height;
uint32_t bytesPerImage = dataSpec.bytesPerRow * appliedRowsPerImage; uint32_t bytesPerImage = bytesPerRow * appliedRowsPerImage;
const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth; const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth;
@ -296,7 +306,7 @@ class QueueWriteTextureTests : public DawnTest {
// Pack the data in the specified copy region to have the same // Pack the data in the specified copy region to have the same
// format as the expected texture data. // format as the expected texture data.
std::vector<RGBA8> expected(texelCountLastLayer); std::vector<RGBA8> expected(texelCountLastLayer);
PackTextureData(&data[dataOffset], copySize.width, copySize.height, PackTextureData(data.data() + dataOffset, copySize.width, copySize.height,
dataSpec.bytesPerRow, expected.data(), copySize.width, bytesPerTexel); dataSpec.bytesPerRow, expected.data(), copySize.width, bytesPerTexel);
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.copyOrigin.x, EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, textureSpec.copyOrigin.x,
@ -468,7 +478,7 @@ TEST_P(QueueWriteTextureTests, VaryingRowsPerImage) {
textureSpec.textureSize = {kWidth, kHeight, kDepth}; textureSpec.textureSize = {kWidth, kHeight, kDepth};
textureSpec.level = 0; textureSpec.level = 0;
DataSpec dataSpec = MinimumDataSpec(copySize, 0, copySize.height + r); DataSpec dataSpec = MinimumDataSpec(copySize, kStrideComputeDefault, copySize.height + r);
DoTest(textureSpec, dataSpec, copySize); DoTest(textureSpec, dataSpec, copySize);
} }
} }
@ -488,7 +498,7 @@ TEST_P(QueueWriteTextureTests, VaryingBytesPerRow) {
for (unsigned int b : {1, 2, 3, 4}) { for (unsigned int b : {1, 2, 3, 4}) {
uint32_t bytesPerRow = uint32_t bytesPerRow =
copyExtent.width * utils::GetTexelBlockSizeInBytes(kTextureFormat) + b; copyExtent.width * utils::GetTexelBlockSizeInBytes(kTextureFormat) + b;
DoTest(textureSpec, MinimumDataSpec(copyExtent, bytesPerRow, 0), copyExtent); DoTest(textureSpec, MinimumDataSpec(copyExtent, bytesPerRow), copyExtent);
} }
} }
@ -503,22 +513,27 @@ TEST_P(QueueWriteTextureTests, BytesPerRowWithOneRowCopy) {
textureSpec.textureSize = {kWidth, kHeight, 1}; textureSpec.textureSize = {kWidth, kHeight, 1};
textureSpec.level = 0; textureSpec.level = 0;
// bytesPerRow = 0
{ {
constexpr wgpu::Extent3D copyExtent = {5, 1, 1}; constexpr wgpu::Extent3D copyExtent = {5, 1, 1};
DataSpec dataSpec = MinimumDataSpec(copyExtent); DataSpec dataSpec = MinimumDataSpec(copyExtent);
// bytesPerRow = 0
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
dataSpec.bytesPerRow = 0; dataSpec.bytesPerRow = 0;
EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, dataSpec, copyExtent));
// bytesPerRow undefined
dataSpec.bytesPerRow = wgpu::kStrideUndefined;
DoTest(textureSpec, dataSpec, copyExtent); DoTest(textureSpec, dataSpec, copyExtent);
} }
// bytesPerRow < bytesInACompleteRow // bytesPerRow < bytesInACompleteRow
// TODO(crbug.com/dawn/520): This behavior is deprecated; remove this case.
{ {
constexpr wgpu::Extent3D copyExtent = {259, 1, 1}; constexpr wgpu::Extent3D copyExtent = {259, 1, 1};
DataSpec dataSpec = MinimumDataSpec(copyExtent); DataSpec dataSpec = MinimumDataSpec(copyExtent);
dataSpec.bytesPerRow = 256; dataSpec.bytesPerRow = 256;
DoTest(textureSpec, dataSpec, copyExtent); EXPECT_DEPRECATION_WARNING(DoTest(textureSpec, dataSpec, copyExtent));
} }
} }
@ -552,6 +567,37 @@ TEST_P(QueueWriteTextureTests, VaryingArrayBytesPerRow) {
} }
} }
// Test valid special cases of bytesPerRow and rowsPerImage (0 or undefined).
TEST_P(QueueWriteTextureTests, StrideSpecialCases) {
TextureSpec textureSpec;
textureSpec.copyOrigin = {0, 0, 0};
textureSpec.textureSize = {4, 4, 4};
textureSpec.level = 0;
// bytesPerRow 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{0, 2, 2}, {0, 0, 2}, {0, 2, 0}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumDataSpec(copyExtent, 0, 2), copyExtent);
}
// bytesPerRow undefined
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 1, 1}, {2, 0, 1}, {2, 1, 0}, {2, 0, 0}}) {
DoTest(textureSpec, MinimumDataSpec(copyExtent, wgpu::kStrideUndefined, 2), copyExtent);
}
// rowsPerImage 0
for (const wgpu::Extent3D copyExtent :
{wgpu::Extent3D{2, 0, 2}, {2, 0, 0}, {0, 0, 2}, {0, 0, 0}}) {
DoTest(textureSpec, MinimumDataSpec(copyExtent, 256, 0), copyExtent);
}
// rowsPerImage undefined
for (const wgpu::Extent3D copyExtent : {wgpu::Extent3D{2, 2, 1}, {2, 2, 0}}) {
DoTest(textureSpec, MinimumDataSpec(copyExtent, 256, wgpu::kStrideUndefined), copyExtent);
}
}
// Testing a special code path: writing when dynamic uploader already contatins some unaligned // Testing a special code path: writing when dynamic uploader already contatins some unaligned
// data, it might be necessary to use a ring buffer with properly aligned offset. // data, it might be necessary to use a ring buffer with properly aligned offset.
TEST_P(QueueWriteTextureTests, UnalignedDynamicUploader) { TEST_P(QueueWriteTextureTests, UnalignedDynamicUploader) {

View File

@ -123,7 +123,7 @@ class RenderPassLoadOpTests : public DawnTest {
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(buffer, 0, kTextureBytesPerRowAlignment, 0); utils::CreateBufferCopyView(buffer, 0, kTextureBytesPerRowAlignment);
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &kTextureSize); encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &kTextureSize);
wgpu::CommandBuffer commandBuffer = encoder.Finish(); wgpu::CommandBuffer commandBuffer = encoder.Finish();

View File

@ -104,7 +104,7 @@ class SamplerTest : public DawnTest {
wgpu::Buffer stagingBuffer = wgpu::Buffer stagingBuffer =
utils::CreateBufferFromData(device, data, sizeof(data), wgpu::BufferUsage::CopySrc); utils::CreateBufferFromData(device, data, sizeof(data), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 256, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 256);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {2, 2, 1}; wgpu::Extent3D copySize = {2, 2, 1};

View File

@ -464,7 +464,7 @@ class StorageTextureTests : public DawnTest {
const wgpu::Extent3D copyExtent = {kWidth, kHeight, arrayLayerCount}; const wgpu::Extent3D copyExtent = {kWidth, kHeight, arrayLayerCount};
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(uploadBuffer, 0, kTextureBytesPerRowAlignment, 0); utils::CreateBufferCopyView(uploadBuffer, 0, kTextureBytesPerRowAlignment, kHeight);
wgpu::TextureCopyView textureCopyView; wgpu::TextureCopyView textureCopyView;
textureCopyView.texture = outputTexture; textureCopyView.texture = outputTexture;
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyExtent); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyExtent);
@ -640,7 +640,7 @@ class StorageTextureTests : public DawnTest {
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(writeonlyStorageTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(writeonlyStorageTexture, 0, {0, 0, 0});
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(resultBuffer, 0, kTextureBytesPerRowAlignment, 0); utils::CreateBufferCopyView(resultBuffer, 0, kTextureBytesPerRowAlignment, kHeight);
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copyExtent); encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copyExtent);
wgpu::CommandBuffer commandBuffer = encoder.Finish(); wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer); queue.Submit(1, &commandBuffer);

View File

@ -240,7 +240,7 @@ class TextureFormatTest : public DawnTest {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{ {
wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(uploadBuffer, 0, 256, 0); wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(uploadBuffer, 0, 256);
wgpu::TextureCopyView textureView = wgpu::TextureCopyView textureView =
utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 0});
wgpu::Extent3D extent{width, 1, 1}; wgpu::Extent3D extent{width, 1, 1};
@ -255,8 +255,7 @@ class TextureFormatTest : public DawnTest {
renderPass.EndPass(); renderPass.EndPass();
{ {
wgpu::BufferCopyView bufferView = wgpu::BufferCopyView bufferView = utils::CreateBufferCopyView(readbackBuffer, 0, 256);
utils::CreateBufferCopyView(readbackBuffer, 0, 256, 0);
wgpu::TextureCopyView textureView = wgpu::TextureCopyView textureView =
utils::CreateTextureCopyView(renderTarget, 0, {0, 0, 0}); utils::CreateTextureCopyView(renderTarget, 0, {0, 0, 0});
wgpu::Extent3D extent{width, 1, 1}; wgpu::Extent3D extent{width, 1, 1};

View File

@ -134,7 +134,7 @@ class TextureViewSamplingTest : public DawnTest {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), data.size() * sizeof(RGBA8), wgpu::BufferUsage::CopySrc); device, data.data(), data.size() * sizeof(RGBA8), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kTextureBytesPerRowAlignment, 0); utils::CreateBufferCopyView(stagingBuffer, 0, kTextureBytesPerRowAlignment);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(mTexture, level, {0, 0, layer}); utils::CreateTextureCopyView(mTexture, level, {0, 0, layer});
wgpu::Extent3D copySize = {texWidth, texHeight, 1}; wgpu::Extent3D copySize = {texWidth, texHeight, 1};

View File

@ -153,7 +153,7 @@ TEST_P(TextureZeroInitTest, CopyMultipleTextureArrayLayersToBufferSource) {
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
const wgpu::BufferCopyView bufferCopyView = const wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(buffer, 0, bytesPerRow, 0); utils::CreateBufferCopyView(buffer, 0, bytesPerRow, kSize);
const wgpu::TextureCopyView textureCopyView = const wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
const wgpu::Extent3D copySize = {kSize, kSize, kArrayLayers}; const wgpu::Extent3D copySize = {kSize, kSize, kArrayLayers};
@ -275,7 +275,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint32_t), 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint32_t));
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -306,7 +306,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) {
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint16_t), 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * sizeof(uint16_t));
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize / 2, kSize, 1}; wgpu::Extent3D copySize = {kSize / 2, kSize, 1};
@ -340,7 +340,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureMultipleArrayLayers) {
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
const wgpu::BufferCopyView bufferCopyView = const wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, kSize);
const wgpu::TextureCopyView textureCopyView = const wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, 0, {0, 0, kBaseArrayLayer}); utils::CreateTextureCopyView(texture, 0, {0, 0, kBaseArrayLayer});
const wgpu::Extent3D copySize = {kSize, kSize, kCopyLayerCount}; const wgpu::Extent3D copySize = {kSize, kSize, kCopyLayerCount};
@ -414,7 +414,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(srcTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(srcTexture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -965,7 +965,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClear) {
wgpu::Buffer bufferDst = utils::CreateBufferFromData( wgpu::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -996,7 +996,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClearUnalignedSize) {
std::vector<uint8_t> data(bufferSize, 100); std::vector<uint8_t> data(bufferSize, 100);
wgpu::Buffer bufferDst = utils::CreateBufferFromData( wgpu::Buffer bufferDst = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow, 0); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(bufferDst, 0, bytesPerRow);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1}; wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1};
@ -1026,7 +1026,7 @@ TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) {
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(bufferDst, 0, kSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(bufferDst, 0, kSize * kFormatBlockByteSize);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 1});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -1064,7 +1064,7 @@ TEST_P(TextureZeroInitTest, RenderPassStoreOpClear) {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -1212,7 +1212,7 @@ TEST_P(TextureZeroInitTest, PreservesInitializedMip) {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, mipSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(stagingBuffer, 0, mipSize * kFormatBlockByteSize);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(sampleTexture, 1, {0, 0, 0}); utils::CreateTextureCopyView(sampleTexture, 1, {0, 0, 0});
wgpu::Extent3D copySize = {mipSize, mipSize, 1}; wgpu::Extent3D copySize = {mipSize, mipSize, 1};
@ -1290,7 +1290,7 @@ TEST_P(TextureZeroInitTest, PreservesInitializedArrayLayer) {
wgpu::Buffer stagingBuffer = utils::CreateBufferFromData( wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc); device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize, 0); utils::CreateBufferCopyView(stagingBuffer, 0, kSize * kFormatBlockByteSize);
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 1}); utils::CreateTextureCopyView(sampleTexture, 0, {0, 0, 1});
wgpu::Extent3D copySize = {kSize, kSize, 1}; wgpu::Extent3D copySize = {kSize, kSize, 1};
@ -1374,8 +1374,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToBufferNonRenderableUnaligned) {
bufferSize, wgpu::BufferUsage::CopyDst); bufferSize, wgpu::BufferUsage::CopyDst);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::BufferCopyView bufferCopyView = wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(buffer, 0, bytesPerRow);
utils::CreateBufferCopyView(buffer, 0, bytesPerRow, 0);
wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1}; wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();

View File

@ -367,51 +367,75 @@ TEST_F(CopyCommandTest_B2T, Success) {
// Different copies, including some that touch the OOB condition // Different copies, including some that touch the OOB condition
{ {
// Copy 4x4 block in corner of first mip. // Copy 4x4 block in corner of first mip.
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
// Copy 4x4 block in opposite corner of first mip. // Copy 4x4 block in opposite corner of first mip.
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {12, 12, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {12, 12, 0},
{4, 4, 1}); {4, 4, 1});
// Copy 4x4 block in the 4x4 mip. // Copy 4x4 block in the 4x4 mip.
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 2, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 2, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
// Copy with a buffer offset // Copy with a buffer offset
TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 1, destination, 0,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256,
wgpu::kStrideUndefined, destination, 0, {0, 0, 0}, {1, 1, 1});
} }
// Copies with a 256-byte aligned bytes per row but unaligned texture region // Copies with a 256-byte aligned bytes per row but unaligned texture region
{ {
// Unaligned region // Unaligned region
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0},
{3, 4, 1}); {3, 4, 1});
// Unaligned region with texture offset // Unaligned region with texture offset
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {5, 7, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 3, destination, 0, {5, 7, 0},
{2, 3, 1}); {2, 3, 1});
// Unaligned region, with buffer offset // Unaligned region, with buffer offset
TestB2TCopy(utils::Expectation::Success, source, 31 * 4, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 31 * 4, 256, 3, destination, 0, {0, 0, 0},
{3, 3, 1}); {3, 3, 1});
} }
// bytesPerRow is undefined
{
TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 2, destination,
0, {0, 0, 0}, {1, 1, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 2, destination,
0, {0, 0, 0}, {3, 1, 1});
// Fail because height or depth is greater than 1:
TestB2TCopy(utils::Expectation::Failure, source, 0, wgpu::kStrideUndefined, 2, destination,
0, {0, 0, 0}, {1, 2, 1});
TestB2TCopy(utils::Expectation::Failure, source, 0, wgpu::kStrideUndefined, 2, destination,
0, {0, 0, 0}, {1, 1, 2});
}
// Empty copies are valid // Empty copies are valid
{ {
// An empty copy // An empty copy
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0},
{0, 0, 1}); {0, 0, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination,
0, {0, 0, 0}, {0, 0, 1});
// An empty copy with depth = 0 // An empty copy with depth = 0
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0},
{0, 0, 0}); {0, 0, 0});
TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination,
0, {0, 0, 0}, {0, 0, 0});
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
TestB2TCopy(utils::Expectation::Success, source, bufferSize, 0, 0, destination, 0, TestB2TCopy(utils::Expectation::Success, source, bufferSize, 0, 0, destination, 0,
{0, 0, 0}, {0, 0, 1}); {0, 0, 0}, {0, 0, 1});
TestB2TCopy(utils::Expectation::Success, source, bufferSize, wgpu::kStrideUndefined, 0,
destination, 0, {0, 0, 0}, {0, 0, 1});
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {16, 16, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {16, 16, 0},
{0, 0, 1}); {0, 0, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, wgpu::kStrideUndefined, 0, destination,
0, {16, 16, 0}, {0, 0, 1});
// An empty copy with depth = 1 and bytesPerRow > 0 // An empty copy with depth = 1 and bytesPerRow > 0
TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 0, TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 0,
destination, 0, {0, 0, 0}, {0, 0, 1}); destination, 0, {0, 0, 0}, {0, 0, 1});
// An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0 // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0
TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 16, TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 3,
destination, 0, {0, 0, 0}, {0, 1, 0}); destination, 0, {0, 0, 0}, {0, 1, 0});
} }
} }
@ -424,16 +448,16 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
// OOB on the buffer because we copy too many pixels // OOB on the buffer because we copy too many pixels
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 5, destination, 0, {0, 0, 0},
{4, 5, 1}); {4, 5, 1});
// OOB on the buffer because of the offset // OOB on the buffer because of the offset
TestB2TCopy(utils::Expectation::Failure, source, 4, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 4, 256, 4, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
// OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth // OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth
// overflows // overflows
TestB2TCopy(utils::Expectation::Failure, source, 0, 512, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 512, 3, destination, 0, {0, 0, 0},
{4, 3, 1}); {4, 3, 1});
// Not OOB on the buffer although bytes per row * height overflows // Not OOB on the buffer although bytes per row * height overflows
@ -443,7 +467,7 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnBuffer) {
ASSERT_TRUE(256 * 3 > sourceBufferSize) << "bytes per row * height should overflow buffer"; ASSERT_TRUE(256 * 3 > sourceBufferSize) << "bytes per row * height should overflow buffer";
wgpu::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer sourceBuffer = CreateBuffer(sourceBufferSize, wgpu::BufferUsage::CopySrc);
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 3, destination, 0, {0, 0, 0},
{7, 3, 1}); {7, 3, 1});
} }
} }
@ -456,15 +480,15 @@ TEST_F(CopyCommandTest_B2T, OutOfBoundsOnTexture) {
Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); Create2DTexture(16, 16, 5, 2, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {13, 12, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 0, {13, 12, 0},
{4, 4, 1}); {4, 4, 1});
// OOB on the texture because y + width overflows // OOB on the texture because y + width overflows
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {12, 13, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 0, {12, 13, 0},
{4, 4, 1}); {4, 4, 1});
// OOB on the texture because we overflow a non-zero mip // OOB on the texture because we overflow a non-zero mip
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 2, {1, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, destination, 2, {1, 0, 0},
{4, 4, 1}); {4, 4, 1});
// 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.
@ -494,80 +518,106 @@ TEST_F(CopyCommandTest_B2T, IncorrectUsage) {
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::Sampled); Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::Sampled);
// Incorrect source usage // Incorrect source usage
TestB2TCopy(utils::Expectation::Failure, vertex, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, vertex, 0, 256, 4, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
// Incorrect destination usage // Incorrect destination usage
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, sampled, 0, {0, 0, 0}, {4, 4, 1}); TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 4, sampled, 0, {0, 0, 0}, {4, 4, 1});
} }
TEST_F(CopyCommandTest_B2T, IncorrectBytesPerRow) { TEST_F(CopyCommandTest_B2T, BytesPerRowConstraints) {
uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc);
wgpu::Texture destination = Create2DTexture(128, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::Texture destination = Create2DTexture(128, 16, 5, 5, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
// bytes per row is 0 // bytes per row is 0
{ {
// copyHeight > 1 // copyHeight > 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 4, destination, 0, {0, 0, 0},
{64, 4, 1}); {64, 4, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 4, destination, 0, {0, 0, 0},
{0, 4, 1});
// copyDepth > 1 // copyDepth > 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 1, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 0, 1, destination, 0, {0, 0, 0},
{64, 1, 4}); {64, 1, 4});
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 1, destination, 0, {0, 0, 0},
{0, 1, 4});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {0, 0, 0}, // TODO(crbug.com/dawn/520): Change to ::Failure.
{64, 1, 1}); EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 0, 1,
destination, 0, {0, 0, 0}, {64, 1, 1}));
} }
// bytes per row is not 256-byte aligned // bytes per row is not 256-byte aligned
{ {
// copyHeight > 1 // copyHeight > 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 4, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 128, 1, destination, 0, {0, 0, 0},
{4, 1, 1}); {4, 1, 1});
} }
// bytes per row is less than width * bytesPerPixel // bytes per row is less than width * bytesPerPixel
{ {
// copyHeight > 1 // copyHeight > 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, 0, {0, 0, 0},
{65, 2, 1}); {65, 2, 1});
// copyHeight == 0
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0},
{65, 0, 1});
// copyDepth > 1 // copyDepth > 1
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0},
{65, 1, 2}); {65, 1, 2});
// copyDepth == 0
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0},
{65, 1, 0});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, // TODO(crbug.com/dawn/520): Change to ::Failure.
{65, 1, 1}); EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1,
destination, 0, {0, 0, 0}, {65, 1, 1}));
} }
} }
TEST_F(CopyCommandTest_B2T, ImageHeightConstraint) { TEST_F(CopyCommandTest_B2T, RowsPerImageConstraints) {
uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 1); uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 6);
wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer source = CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc);
wgpu::Texture destination = wgpu::Texture destination =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); Create2DTexture(16, 16, 1, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
// Image height is zero (Valid) // rowsPerImage is zero
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, // TODO(crbug.com/dawn/520): Change to ::Failure.
EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0,
destination, 0, {0, 0, 0}, {1, 1, 1}));
EXPECT_DEPRECATION_WARNING(TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0,
destination, 0, {0, 0, 0}, {4, 4, 1}));
// rowsPerImage is undefined
TestB2TCopy(utils::Expectation::Success, source, 0, 256, wgpu::kStrideUndefined, destination, 0,
{0, 0, 0}, {4, 4, 1});
// Fail because depth > 1:
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, wgpu::kStrideUndefined, destination, 0,
{0, 0, 0}, {4, 4, 2});
// rowsPerImage is equal to copy height (Valid)
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 4, destination, 0, {0, 0, 0},
{4, 4, 2});
// Image height is equal to copy height (Valid) // rowsPerImage is larger than copy height (Valid)
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0},
{4, 4, 1});
// Image height is larger than copy height (Valid)
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 5, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 5, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 5, destination, 0, {0, 0, 0},
{4, 4, 2});
// Image height is less than copy height (Invalid) // rowsPerImage is less than copy height (Invalid)
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 3, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 3, destination, 0, {0, 0, 0},
{4, 4, 1}); {4, 4, 1});
} }
@ -580,16 +630,16 @@ TEST_F(CopyCommandTest_B2T, IncorrectBufferOffset) {
Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); Create2DTexture(16, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
// Correct usage // Correct usage
TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 0, destination, 0, TestB2TCopy(utils::Expectation::Success, source, bufferSize - 4, 256, 1, destination, 0,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
// Incorrect usages // Incorrect usages
{ {
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 5, 256, 0, destination, 0, TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 5, 256, 1, destination, 0,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 6, 256, 0, destination, 0, TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 6, 256, 1, destination, 0,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 7, 256, 0, destination, 0, TestB2TCopy(utils::Expectation::Failure, source, bufferSize - 7, 256, 1, destination, 0,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
} }
} }
@ -601,7 +651,7 @@ TEST_F(CopyCommandTest_B2T, CopyToMultisampledTexture) {
wgpu::Texture destination = Create2DTexture(2, 2, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::Texture destination = Create2DTexture(2, 2, 1, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst, 4); wgpu::TextureUsage::CopyDst, 4);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, 0, {0, 0, 0},
{2, 2, 1}); {2, 2, 1});
} }
@ -663,8 +713,8 @@ TEST_F(CopyCommandTest_B2T, TextureCopyBufferSizeLastRowComputation) {
wgpu::Buffer source = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer source = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopySrc);
wgpu::Texture destination = wgpu::Texture destination =
Create2DTexture(kWidth, kHeight, 1, 1, format, wgpu::TextureUsage::CopyDst); Create2DTexture(kWidth, kHeight, 1, 1, format, wgpu::TextureUsage::CopyDst);
TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, 0, destination, 0, TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, kHeight, destination,
{0, 0, 0}, {kWidth, kHeight, 1}); 0, {0, 0, 0}, {kWidth, kHeight, 1});
} }
} }
@ -679,14 +729,14 @@ TEST_F(CopyCommandTest_B2T, TextureCopyBufferSizeLastRowComputation) {
{ {
uint32_t invalidBuffferSize = validBufferSize - 1; uint32_t invalidBuffferSize = validBufferSize - 1;
wgpu::Buffer source = CreateBuffer(invalidBuffferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer source = CreateBuffer(invalidBuffferSize, wgpu::BufferUsage::CopySrc);
TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, 0, destination, 0, TestB2TCopy(utils::Expectation::Failure, source, 0, kBytesPerRow, kHeight,
{0, 0, 0}, {kWidth, kHeight, 1}); destination, 0, {0, 0, 0}, {kWidth, kHeight, 1});
} }
{ {
wgpu::Buffer source = CreateBuffer(validBufferSize, wgpu::BufferUsage::CopySrc); wgpu::Buffer source = CreateBuffer(validBufferSize, wgpu::BufferUsage::CopySrc);
TestB2TCopy(utils::Expectation::Success, source, 0, kBytesPerRow, 0, destination, 0, TestB2TCopy(utils::Expectation::Success, source, 0, kBytesPerRow, kHeight,
{0, 0, 0}, {kWidth, kHeight, 1}); destination, 0, {0, 0, 0}, {kWidth, kHeight, 1});
} }
} }
} }
@ -701,19 +751,19 @@ TEST_F(CopyCommandTest_B2T, CopyToMipmapOfNonSquareTexture) {
4, 2, maxMipmapLevel, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst); 4, 2, maxMipmapLevel, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopyDst);
// Copy to top level mip map // Copy to top level mip map
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, maxMipmapLevel - 1, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1, destination, maxMipmapLevel - 1,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
// Copy to high level mip map // Copy to high level mip map
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, maxMipmapLevel - 2, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 1, destination, maxMipmapLevel - 2,
{0, 0, 0}, {2, 1, 1}); {0, 0, 0}, {2, 1, 1});
// Mip level out of range // Mip level out of range
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, maxMipmapLevel,
{0, 0, 0}, {1, 1, 1}); {0, 0, 0}, {1, 1, 1});
// Copy origin out of range // Copy origin out of range
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel - 2, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, maxMipmapLevel - 2,
{1, 0, 0}, {2, 1, 1}); {1, 0, 0}, {2, 1, 1});
// Copy size out of range // Copy size out of range
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, maxMipmapLevel - 2, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 2, destination, maxMipmapLevel - 2,
{0, 0, 0}, {2, 2, 1}); {0, 0, 0}, {2, 2, 1});
} }
@ -727,10 +777,10 @@ TEST_F(CopyCommandTest_B2T, CopyToDepthAspect) {
wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth32Float, wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth32Float,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::All); {16, 16, 1}, wgpu::TextureAspect::All);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::DepthOnly); {16, 16, 1}, wgpu::TextureAspect::DepthOnly);
} }
@ -760,12 +810,12 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
wgpu::Texture destination = Create2DTexture( wgpu::Texture destination = Create2DTexture(
16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst);
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
// And that it fails if the buffer is one byte too small // And that it fails if the buffer is one byte too small
wgpu::Buffer sourceSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopySrc); wgpu::Buffer sourceSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopySrc);
TestB2TCopy(utils::Expectation::Failure, sourceSmall, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, sourceSmall, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -777,7 +827,7 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24Plus, wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24Plus,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -789,7 +839,7 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Uint, wgpu::Texture destination = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Uint,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 16, destination, 0, {0, 0, 0},
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -802,10 +852,10 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 15, destination, 0, {0, 0, 0},
{15, 15, 1}, wgpu::TextureAspect::StencilOnly); {15, 15, 1}, wgpu::TextureAspect::StencilOnly);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 0, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 0, {0, 0, 0},
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -820,14 +870,14 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Whole mip is success // Whole mip is success
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 8, destination, 1, {0, 0, 0},
{8, 8, 1}, wgpu::TextureAspect::StencilOnly); {8, 8, 1}, wgpu::TextureAspect::StencilOnly);
// Partial mip fails // Partial mip fails
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 7, destination, 1, {0, 0, 0},
{7, 7, 1}, wgpu::TextureAspect::StencilOnly); {7, 7, 1}, wgpu::TextureAspect::StencilOnly);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 1, {0, 0, 0},
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -842,14 +892,14 @@ TEST_F(CopyCommandTest_B2T, CopyToStencilAspect) {
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment); wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
// Whole mip is success // Whole mip is success
TestB2TCopy(utils::Expectation::Success, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Success, source, 0, 256, 8, destination, 1, {0, 0, 0},
{8, 8, 1}, wgpu::TextureAspect::StencilOnly); {8, 8, 1}, wgpu::TextureAspect::StencilOnly);
// Partial mip fails // Partial mip fails
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 7, destination, 1, {0, 0, 0},
{7, 7, 1}, wgpu::TextureAspect::StencilOnly); {7, 7, 1}, wgpu::TextureAspect::StencilOnly);
TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 0, destination, 1, {0, 0, 0}, TestB2TCopy(utils::Expectation::Failure, source, 0, 256, 1, destination, 1, {0, 0, 0},
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
} }
@ -880,46 +930,76 @@ TEST_F(CopyCommandTest_T2B, Success) {
// Different copies, including some that touch the OOB condition // Different copies, including some that touch the OOB condition
{ {
// Copy from 4x4 block in corner of first mip. // Copy from 4x4 block in corner of first mip.
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// Copy from 4x4 block in opposite corner of first mip. // Copy from 4x4 block in opposite corner of first mip.
TestT2BCopy(utils::Expectation::Success, source, 0, {12, 12, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {12, 12, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// Copy from 4x4 block in the 4x4 mip. // Copy from 4x4 block in the 4x4 mip.
TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// Copy with a buffer offset // Copy with a buffer offset
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4,
256, 0, {1, 1, 1}); 256, 1, {1, 1, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4,
256, wgpu::kStrideUndefined, {1, 1, 1});
} }
// Copies with a 256-byte aligned bytes per row but unaligned texture region // Copies with a 256-byte aligned bytes per row but unaligned texture region
{ {
// Unaligned region // Unaligned region
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4,
{3, 4, 1}); {3, 4, 1});
// Unaligned region with texture offset // Unaligned region with texture offset
TestT2BCopy(utils::Expectation::Success, source, 0, {5, 7, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {5, 7, 0}, destination, 0, 256, 3,
{2, 3, 1}); {2, 3, 1});
// Unaligned region, with buffer offset // Unaligned region, with buffer offset
TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 31 * 4, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 2, {0, 0, 0}, destination, 31 * 4, 256, 3,
{3, 3, 1}); {3, 3, 1});
} }
// bytesPerRow is undefined
{
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 2, {1, 1, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 2, {3, 1, 1});
// Fail because height or depth is greater than 1:
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 2, {1, 2, 1});
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 2, {1, 1, 2});
}
// Empty copies are valid // Empty copies are valid
{ {
// An empty copy // An empty copy
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0,
{0, 0, 1}); {0, 0, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 0, {0, 0, 1});
// An empty copy with depth = 0 // An empty copy with depth = 0
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0,
{0, 0, 0}); {0, 0, 0});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
wgpu::kStrideUndefined, 0, {0, 0, 0});
// An empty copy touching the end of the buffer // An empty copy touching the end of the buffer
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize, 0,
0, {0, 0, 1}); 0, {0, 0, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize,
wgpu::kStrideUndefined, 0, {0, 0, 1});
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
TestT2BCopy(utils::Expectation::Success, source, 0, {16, 16, 0}, destination, 0, 0, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {16, 16, 0}, destination, 0, 0, 0,
{0, 0, 1}); {0, 0, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {16, 16, 0}, destination, 0,
wgpu::kStrideUndefined, 0, {0, 0, 1});
// An empty copy with depth = 1 and bytesPerRow > 0
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
kTextureBytesPerRowAlignment, 0, {0, 0, 1});
// An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
kTextureBytesPerRowAlignment, 3, {0, 1, 0});
} }
} }
@ -959,19 +1039,19 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnTexture) {
wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst);
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
TestT2BCopy(utils::Expectation::Failure, source, 0, {13, 12, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {13, 12, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// OOB on the texture because y + width overflows // OOB on the texture because y + width overflows
TestT2BCopy(utils::Expectation::Failure, source, 0, {12, 13, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {12, 13, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// OOB on the texture because we overflow a non-zero mip // OOB on the texture because we overflow a non-zero mip
TestT2BCopy(utils::Expectation::Failure, source, 2, {1, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 2, {1, 0, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// 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.
TestT2BCopy(utils::Expectation::Failure, source, 5, {0, 0, 0}, destination, 0, 0, 0, {0, 0, 1}); TestT2BCopy(utils::Expectation::Failure, source, 5, {0, 0, 0}, destination, 0, 0, 4, {0, 0, 1});
} }
// Test OOB conditions on the buffer // Test OOB conditions on the buffer
@ -982,16 +1062,16 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst);
// OOB on the buffer because we copy too many pixels // OOB on the buffer because we copy too many pixels
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 5,
{4, 5, 1}); {4, 5, 1});
// OOB on the buffer because of the offset // OOB on the buffer because of the offset
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 4, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 4, 256, 4,
{4, 4, 1}); {4, 4, 1});
// OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth // OOB on the buffer because (bytes per row * (height - 1) + width * bytesPerPixel) * depth
// overflows // overflows
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 512, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 512, 3,
{4, 3, 1}); {4, 3, 1});
// Not OOB on the buffer although bytes per row * height overflows // Not OOB on the buffer although bytes per row * height overflows
@ -1002,7 +1082,7 @@ TEST_F(CopyCommandTest_T2B, OutOfBoundsOnBuffer) {
<< "bytes per row * height should overflow buffer"; << "bytes per row * height should overflow buffer";
wgpu::Buffer destinationBuffer = wgpu::Buffer destinationBuffer =
CreateBuffer(destinationBufferSize, wgpu::BufferUsage::CopyDst); CreateBuffer(destinationBufferSize, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destinationBuffer, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destinationBuffer, 0, 256, 3,
{7, 3, 1}); {7, 3, 1});
} }
} }
@ -1029,80 +1109,106 @@ TEST_F(CopyCommandTest_T2B, IncorrectUsage) {
wgpu::Buffer vertex = CreateBuffer(bufferSize, wgpu::BufferUsage::Vertex); wgpu::Buffer vertex = CreateBuffer(bufferSize, wgpu::BufferUsage::Vertex);
// Incorrect source usage // Incorrect source usage
TestT2BCopy(utils::Expectation::Failure, sampled, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, sampled, 0, {0, 0, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
// Incorrect destination usage // Incorrect destination usage
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, vertex, 0, 256, 0, {4, 4, 1}); TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, vertex, 0, 256, 4, {4, 4, 1});
} }
TEST_F(CopyCommandTest_T2B, IncorrectBytesPerRow) { TEST_F(CopyCommandTest_T2B, BytesPerRowConstraints) {
uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1); uint64_t bufferSize = BufferSizeForTextureCopy(128, 16, 1);
wgpu::Texture source = Create2DTexture(128, 16, 5, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::Texture source = Create2DTexture(128, 16, 5, 5, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopySrc); wgpu::TextureUsage::CopySrc);
wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst);
// bytes per row is 0 // bytes per row is 0
{ {
// copyHeight > 1 // copyHeight > 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 4,
{64, 4, 1}); {64, 4, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 4,
{0, 4, 1});
// copyDepth > 1 // copyDepth > 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 1, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 0, 1,
{64, 1, 4}); {64, 1, 4});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 1,
{0, 1, 4});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 0, 0, // TODO(crbug.com/dawn/520): Change to ::Failure.
{64, 1, 1}); EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0},
destination, 0, 0, 1, {64, 1, 1}));
} }
// bytes per row is not 256-byte aligned // bytes per row is not 256-byte aligned
{ {
// copyHeight > 1 // copyHeight > 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 4,
{4, 4, 1}); {4, 4, 1});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 128, 1,
{4, 1, 1}); {4, 1, 1});
} }
// bytes per row is less than width * bytesPerPixel // bytes per row is less than width * bytesPerPixel
{ {
// copyHeight > 1 // copyHeight > 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 2,
{65, 2, 1}); {65, 2, 1});
// copyHeight == 0
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0,
{65, 0, 1});
// copyDepth > 1 // copyDepth > 1
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1,
{65, 1, 2}); {65, 1, 2});
// copyDepth == 0
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1,
{65, 1, 0});
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, // TODO(crbug.com/dawn/520): Change to ::Failure.
{65, 1, 1}); EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0},
destination, 0, 256, 1, {65, 1, 1}));
} }
} }
TEST_F(CopyCommandTest_T2B, ImageHeightConstraint) { TEST_F(CopyCommandTest_T2B, RowsPerImageConstraints) {
uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 1); uint64_t bufferSize = BufferSizeForTextureCopy(5, 5, 6);
wgpu::Texture source = wgpu::Texture source =
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc); Create2DTexture(16, 16, 1, 5, wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureUsage::CopySrc);
wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst);
// Image height is zero (Valid) // rowsPerImage is zero (Valid)
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, // TODO(crbug.com/dawn/520): Change to ::Failure.
{4, 4, 1}); EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0},
destination, 0, 256, 0, {1, 1, 1}));
EXPECT_DEPRECATION_WARNING(TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0},
destination, 0, 256, 0, {4, 4, 1}));
// Image height is equal to copy height (Valid) // rowsPerImage is undefined
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256,
wgpu::kStrideUndefined, {4, 4, 1});
// Fail because depth > 1:
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256,
wgpu::kStrideUndefined, {4, 4, 2});
// rowsPerImage is equal to copy height (Valid)
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4,
{4, 4, 1}); {4, 4, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 4,
{4, 4, 2});
// Image height exceeds copy height (Valid) // rowsPerImage exceeds copy height (Valid)
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 5, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 5,
{4, 4, 1}); {4, 4, 1});
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 5,
{4, 4, 2});
// Image height is less than copy height (Invalid) // rowsPerImage is less than copy height (Invalid)
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 3, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 3,
{4, 4, 1}); {4, 4, 1});
} }
@ -1116,15 +1222,15 @@ TEST_F(CopyCommandTest_T2B, IncorrectBufferOffset) {
// Correct usage // Correct usage
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, 256, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, bufferSize - 4, 256,
0, {1, 1, 1}); 1, {1, 1, 1});
// Incorrect usages // Incorrect usages
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 5, 256, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 5, 256,
0, {1, 1, 1}); 1, {1, 1, 1});
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 6, 256, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 6, 256,
0, {1, 1, 1}); 1, {1, 1, 1});
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 7, 256, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, bufferSize - 7, 256,
0, {1, 1, 1}); 1, {1, 1, 1});
} }
// Test multisampled textures cannot be used in T2B copies. // Test multisampled textures cannot be used in T2B copies.
@ -1134,7 +1240,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromMultisampledTexture) {
uint64_t bufferSize = BufferSizeForTextureCopy(16, 16, 1); uint64_t bufferSize = BufferSizeForTextureCopy(16, 16, 1);
wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(bufferSize, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 2,
{2, 2, 1}); {2, 2, 1});
} }
@ -1198,7 +1304,7 @@ TEST_F(CopyCommandTest_T2B, TextureCopyBufferSizeLastRowComputation) {
wgpu::Buffer destination = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopyDst); wgpu::Buffer destination = CreateBuffer(kInvalidBufferSize, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
kBytesPerRow, 0, {kWidth, kHeight, 1}); kBytesPerRow, kHeight, {kWidth, kHeight, 1});
} }
} }
@ -1215,14 +1321,14 @@ TEST_F(CopyCommandTest_T2B, TextureCopyBufferSizeLastRowComputation) {
wgpu::Buffer destination = wgpu::Buffer destination =
CreateBuffer(invalidBufferSize, wgpu::BufferUsage::CopyDst); CreateBuffer(invalidBufferSize, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0,
kBytesPerRow, 0, {kWidth, kHeight, 1}); kBytesPerRow, kHeight, {kWidth, kHeight, 1});
} }
{ {
wgpu::Buffer destination = wgpu::Buffer destination =
CreateBuffer(validBufferSize, wgpu::BufferUsage::CopyDst); CreateBuffer(validBufferSize, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0,
kBytesPerRow, 0, {kWidth, kHeight, 1}); kBytesPerRow, kHeight, {kWidth, kHeight, 1});
} }
} }
} }
@ -1238,19 +1344,19 @@ TEST_F(CopyCommandTest_T2B, CopyFromMipmapOfNonSquareTexture) {
// Copy from top level mip map // Copy from top level mip map
TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 1, {0, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 1, {0, 0, 0}, destination, 0,
256, 0, {1, 1, 1}); 256, 1, {1, 1, 1});
// Copy from high level mip map // Copy from high level mip map
TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 2, {0, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Success, source, maxMipmapLevel - 2, {0, 0, 0}, destination, 0,
256, 0, {2, 1, 1}); 256, 1, {2, 1, 1});
// Mip level out of range // Mip level out of range
TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel, {0, 0, 0}, destination, 0, 256, TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel, {0, 0, 0}, destination, 0, 256,
0, {2, 1, 1}); 1, {2, 1, 1});
// Copy origin out of range // Copy origin out of range
TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {2, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {2, 0, 0}, destination, 0,
256, 0, {2, 1, 1}); 256, 1, {2, 1, 1});
// Copy size out of range // Copy size out of range
TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {1, 0, 0}, destination, 0, TestT2BCopy(utils::Expectation::Failure, source, maxMipmapLevel - 2, {1, 0, 0}, destination, 0,
256, 0, {2, 1, 1}); 256, 1, {2, 1, 1});
} }
// Test copy from only the depth aspect of a texture // Test copy from only the depth aspect of a texture
@ -1262,11 +1368,11 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) {
wgpu::TextureUsage::CopySrc); wgpu::TextureUsage::CopySrc);
// Test "all" of a depth texture which is only the depth aspect. // Test "all" of a depth texture which is only the depth aspect.
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::All); {16, 16, 1}, wgpu::TextureAspect::All);
// Test it is valid to copy the depth aspect of a depth texture // Test it is valid to copy the depth aspect of a depth texture
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::DepthOnly); {16, 16, 1}, wgpu::TextureAspect::DepthOnly);
} }
{ {
@ -1274,7 +1380,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) {
wgpu::TextureUsage::CopySrc); wgpu::TextureUsage::CopySrc);
// Test it is invalid to copy from the depth aspect of depth24plus // Test it is invalid to copy from the depth aspect of depth24plus
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::DepthOnly); {16, 16, 1}, wgpu::TextureAspect::DepthOnly);
} }
{ {
@ -1282,7 +1388,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) {
16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
// Test it is invalid to copy from the depth aspect of depth24plus-stencil8 // Test it is invalid to copy from the depth aspect of depth24plus-stencil8
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::DepthOnly); {16, 16, 1}, wgpu::TextureAspect::DepthOnly);
} }
{ {
@ -1290,7 +1396,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromDepthAspect) {
wgpu::TextureUsage::CopySrc); wgpu::TextureUsage::CopySrc);
// Test it is invalid to copy from the depth aspect of a color texture // Test it is invalid to copy from the depth aspect of a color texture
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::DepthOnly); {16, 16, 1}, wgpu::TextureAspect::DepthOnly);
} }
} }
@ -1304,12 +1410,12 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
// Test it is valid to copy from the stencil aspect of a depth24plus-stencil8 texture // Test it is valid to copy from the stencil aspect of a depth24plus-stencil8 texture
TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
// Test it is invalid if the buffer is too small // Test it is invalid if the buffer is too small
wgpu::Buffer destinationSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopyDst); wgpu::Buffer destinationSmall = CreateBuffer(bufferSize - 1, wgpu::BufferUsage::CopyDst);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destinationSmall, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destinationSmall, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
{ {
@ -1317,7 +1423,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::R8Uint, wgpu::TextureUsage::CopySrc); Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::R8Uint, wgpu::TextureUsage::CopySrc);
// Test it is invalid to copy from the stencil aspect of a color texture // Test it is invalid to copy from the stencil aspect of a color texture
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
{ {
@ -1325,7 +1431,7 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
wgpu::TextureUsage::CopySrc); wgpu::TextureUsage::CopySrc);
// Test it is invalid to copy from the stencil aspect of a depth-only texture // Test it is invalid to copy from the stencil aspect of a depth-only texture
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 16,
{16, 16, 1}, wgpu::TextureAspect::StencilOnly); {16, 16, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -1335,10 +1441,10 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
wgpu::Texture source = Create2DTexture( wgpu::Texture source = Create2DTexture(
16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 15,
{15, 15, 1}, wgpu::TextureAspect::StencilOnly); {15, 15, 1}, wgpu::TextureAspect::StencilOnly);
TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 0, {0, 0, 0}, destination, 0, 256, 1,
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -1349,14 +1455,14 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
16, 16, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); 16, 16, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
// Whole mip is success // Whole mip is success
TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 8,
{8, 8, 1}, wgpu::TextureAspect::StencilOnly); {8, 8, 1}, wgpu::TextureAspect::StencilOnly);
// Partial mip fails // Partial mip fails
TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 7,
{7, 7, 1}, wgpu::TextureAspect::StencilOnly); {7, 7, 1}, wgpu::TextureAspect::StencilOnly);
TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 1,
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
@ -1367,14 +1473,14 @@ TEST_F(CopyCommandTest_T2B, CopyFromStencilAspect) {
17, 17, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc); 17, 17, 2, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
// Whole mip is success // Whole mip is success
TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Success, source, 1, {0, 0, 0}, destination, 0, 256, 8,
{8, 8, 1}, wgpu::TextureAspect::StencilOnly); {8, 8, 1}, wgpu::TextureAspect::StencilOnly);
// Partial mip fails // Partial mip fails
TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 7,
{7, 7, 1}, wgpu::TextureAspect::StencilOnly); {7, 7, 1}, wgpu::TextureAspect::StencilOnly);
TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 0, TestT2BCopy(utils::Expectation::Failure, source, 1, {0, 0, 0}, destination, 0, 256, 1,
{1, 1, 1}, wgpu::TextureAspect::StencilOnly); {1, 1, 1}, wgpu::TextureAspect::StencilOnly);
} }
} }

View File

@ -99,38 +99,53 @@ namespace {
// Different copies, including some that touch the OOB condition // Different copies, including some that touch the OOB condition
{ {
// Copy 4x4 block in corner of first mip. // Copy 4x4 block in corner of first mip.
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1});
// Copy 4x4 block in opposite corner of first mip. // Copy 4x4 block in opposite corner of first mip.
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {12, 12, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {12, 12, 0}, {4, 4, 1});
// Copy 4x4 block in the 4x4 mip. // Copy 4x4 block in the 4x4 mip.
TestWriteTexture(dataSize, 0, 256, 0, destination, 2, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, 4, destination, 2, {0, 0, 0}, {4, 4, 1});
// Copy with a data offset // Copy with a data offset
TestWriteTexture(dataSize, dataSize - 4, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); TestWriteTexture(dataSize, dataSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1});
TestWriteTexture(dataSize, dataSize - 4, 256, wgpu::kStrideUndefined, destination, 0,
{0, 0, 0}, {1, 1, 1});
} }
// Copies with a 256-byte aligned bytes per row but unaligned texture region // Copies with a 256-byte aligned bytes per row but unaligned texture region
{ {
// Unaligned region // Unaligned region
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {3, 4, 1}); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {3, 4, 1});
// Unaligned region with texture offset // Unaligned region with texture offset
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {5, 7, 0}, {2, 3, 1}); TestWriteTexture(dataSize, 0, 256, 3, destination, 0, {5, 7, 0}, {2, 3, 1});
// Unaligned region, with data offset // Unaligned region, with data offset
TestWriteTexture(dataSize, 31 * 4, 256, 0, destination, 0, {0, 0, 0}, {3, 3, 1}); TestWriteTexture(dataSize, 31 * 4, 256, 3, destination, 0, {0, 0, 0}, {3, 3, 1});
} }
// Empty copies are valid // Empty copies are valid
{ {
// An empty copy // An empty copy
TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1});
TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {0, 0, 0},
{0, 0, 1});
// An empty copy with depth = 0 // An empty copy with depth = 0
TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 0}); TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 0});
TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {0, 0, 0},
{0, 0, 0});
// An empty copy touching the end of the data // An empty copy touching the end of the data
TestWriteTexture(dataSize, dataSize, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); TestWriteTexture(dataSize, dataSize, 0, 0, destination, 0, {0, 0, 0}, {0, 0, 1});
TestWriteTexture(dataSize, dataSize, 0, wgpu::kStrideUndefined, destination, 0,
{0, 0, 0}, {0, 0, 1});
// An empty copy touching the side of the texture // An empty copy touching the side of the texture
TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {16, 16, 0}, {0, 0, 1}); TestWriteTexture(dataSize, 0, 0, 0, destination, 0, {16, 16, 0}, {0, 0, 1});
TestWriteTexture(dataSize, 0, 0, wgpu::kStrideUndefined, destination, 0, {16, 16, 0},
{0, 0, 1});
// An empty copy with depth = 1 and bytesPerRow > 0 // An empty copy with depth = 1 and bytesPerRow > 0
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {0, 0, 1}); TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {0, 0, 1});
TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0},
{0, 0, 1});
// An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0 // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0
TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0},
{0, 1, 0});
TestWriteTexture(dataSize, 0, 256, 1, destination, 0, {0, 0, 0}, {0, 1, 0});
TestWriteTexture(dataSize, 0, 256, 16, destination, 0, {0, 0, 0}, {0, 1, 0}); TestWriteTexture(dataSize, 0, 256, 16, destination, 0, {0, 0, 0}, {0, 1, 0});
} }
} }
@ -144,15 +159,15 @@ namespace {
// OOB on the data because we copy too many pixels // OOB on the data because we copy too many pixels
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 5, 1})); TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 5, 1}));
// OOB on the data because of the offset // OOB on the data because of the offset
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 4, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 4, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}));
// OOB on the data because utils::RequiredBytesInCopy overflows // OOB on the data because utils::RequiredBytesInCopy overflows
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 512, 0, destination, 0, {0, 0, 0}, {4, 3, 1})); TestWriteTexture(dataSize, 0, 512, 3, destination, 0, {0, 0, 0}, {4, 3, 1}));
// Not OOB on the data although bytes per row * height overflows // Not OOB on the data although bytes per row * height overflows
// but utils::RequiredBytesInCopy * depth does not overflow // but utils::RequiredBytesInCopy * depth does not overflow
@ -161,7 +176,7 @@ namespace {
utils::RequiredBytesInCopy(256, 0, {7, 3, 1}, wgpu::TextureFormat::RGBA8Unorm); utils::RequiredBytesInCopy(256, 0, {7, 3, 1}, wgpu::TextureFormat::RGBA8Unorm);
ASSERT_TRUE(256 * 3 > sourceDataSize) << "bytes per row * height should overflow data"; ASSERT_TRUE(256 * 3 > sourceDataSize) << "bytes per row * height should overflow data";
TestWriteTexture(sourceDataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {7, 3, 1}); TestWriteTexture(sourceDataSize, 0, 256, 3, destination, 0, {0, 0, 0}, {7, 3, 1});
} }
} }
@ -174,15 +189,15 @@ namespace {
// OOB on the texture because x + width overflows // OOB on the texture because x + width overflows
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {13, 12, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {13, 12, 0}, {4, 4, 1}));
// OOB on the texture because y + width overflows // OOB on the texture because y + width overflows
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {12, 13, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {12, 13, 0}, {4, 4, 1}));
// OOB on the texture because we overflow a non-zero mip // OOB on the texture because we overflow a non-zero mip
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, destination, 2, {1, 0, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 0, 256, 4, destination, 2, {1, 0, 0}, {4, 4, 1}));
// OOB on the texture even on an empty copy when we copy to a non-existent mip. // OOB on the texture even on an empty copy when we copy to a non-existent mip.
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
@ -214,68 +229,91 @@ namespace {
// Incorrect destination usage // Incorrect destination usage
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, sampled, 0, {0, 0, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 0, 256, 4, sampled, 0, {0, 0, 0}, {4, 4, 1}));
} }
// Test incorrect values of bytesPerRow and that values not divisible by 256 are allowed. // Test incorrect values of bytesPerRow and that values not divisible by 256 are allowed.
TEST_F(QueueWriteTextureValidationTest, BytesPerRowLimitations) { TEST_F(QueueWriteTextureValidationTest, BytesPerRowConstraints) {
wgpu::Texture destination = Create2DTexture({3, 7, 1}, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::Texture destination = Create2DTexture({3, 7, 2}, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
// bytesPerRow = 0 // bytesPerRow = 0 or wgpu::kStrideUndefined
{ {
// copyHeight > 1 // copyHeight > 1
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 0, 0, destination, 0, {0, 0, 0}, {3, 7, 1})); TestWriteTexture(128, 0, 0, 7, destination, 0, {0, 0, 0}, {3, 7, 1}));
TestWriteTexture(128, 0, 0, 7, destination, 0, {0, 0, 0}, {0, 7, 1});
ASSERT_DEVICE_ERROR(TestWriteTexture(128, 0, wgpu::kStrideUndefined, 7, destination, 0,
{0, 0, 0}, {0, 7, 1}));
// copyDepth > 1 // copyDepth > 1
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {3, 1, 2})); TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {3, 1, 2}));
TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {0, 1, 2});
ASSERT_DEVICE_ERROR(TestWriteTexture(128, 0, wgpu::kStrideUndefined, 1, destination, 0,
{0, 0, 0}, {0, 1, 2}));
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestWriteTexture(128, 0, 0, 0, destination, 0, {0, 0, 0}, {3, 1, 1}); // TODO(crbug.com/dawn/520): Change to ASSERT_DEVICE_ERROR.
EXPECT_DEPRECATION_WARNING(
TestWriteTexture(128, 0, 0, 1, destination, 0, {0, 0, 0}, {3, 1, 1}));
TestWriteTexture(128, 0, wgpu::kStrideUndefined, 1, destination, 0, {0, 0, 0},
{3, 1, 1});
} }
// bytesPerRow = 11 is invalid since a row takes 12 bytes. // bytesPerRow = 11 is invalid since a row takes 12 bytes.
{ {
// copyHeight > 1 // copyHeight > 1
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 7, 1})); TestWriteTexture(128, 0, 11, 7, destination, 0, {0, 0, 0}, {3, 7, 1}));
// copyHeight == 0
ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 0, 1}));
// copyDepth > 1 // copyDepth > 1
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 2})); TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 2}));
// copyDepth == 0
ASSERT_DEVICE_ERROR(
TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 0}));
// copyHeight = 1 and copyDepth = 1 // copyHeight = 1 and copyDepth = 1
TestWriteTexture(128, 0, 11, 0, destination, 0, {0, 0, 0}, {3, 1, 1}); // TODO(crbug.com/dawn/520): Change to ASSERT_DEVICE_ERROR. bytesPerRow used to be only
// validated if height > 1 || depth > 1.
EXPECT_DEPRECATION_WARNING(
TestWriteTexture(128, 0, 11, 1, destination, 0, {0, 0, 0}, {3, 1, 1}));
} }
// bytesPerRow = 12 is valid since a row takes 12 bytes. // bytesPerRow = 12 is valid since a row takes 12 bytes.
TestWriteTexture(128, 0, 12, 0, destination, 0, {0, 0, 0}, {3, 7, 1}); TestWriteTexture(128, 0, 12, 7, destination, 0, {0, 0, 0}, {3, 7, 1});
// bytesPerRow = 13 is valid since a row takes 12 bytes. // bytesPerRow = 13 is valid since a row takes 12 bytes.
TestWriteTexture(128, 0, 13, 0, destination, 0, {0, 0, 0}, {3, 7, 1}); TestWriteTexture(128, 0, 13, 7, destination, 0, {0, 0, 0}, {3, 7, 1});
} }
// Test that if rowsPerImage is greater than 0, it must be at least copy height. // Test that if rowsPerImage is greater than 0, it must be at least copy height.
TEST_F(QueueWriteTextureValidationTest, ImageHeightConstraint) { TEST_F(QueueWriteTextureValidationTest, RowsPerImageConstraints) {
uint64_t dataSize = uint64_t dataSize =
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm); utils::RequiredBytesInCopy(256, 5, {4, 4, 2}, wgpu::TextureFormat::RGBA8Unorm);
wgpu::Texture destination = Create2DTexture({16, 16, 1}, 1, wgpu::TextureFormat::RGBA8Unorm, wgpu::Texture destination = Create2DTexture({16, 16, 2}, 1, wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
// Image height is zero (Valid) // rowsPerImage is wgpu::kStrideUndefined
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, wgpu::kStrideUndefined, destination, 0, {0, 0, 0},
{4, 4, 1});
// Image height is equal to copy height (Valid) // rowsPerImage is equal to copy height (Valid)
TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, 4, destination, 0, {0, 0, 0}, {4, 4, 1});
// Image height is larger than copy height (Valid) // rowsPerImage is larger than copy height (Valid)
TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 1});
TestWriteTexture(dataSize, 0, 256, 5, destination, 0, {0, 0, 0}, {4, 4, 2});
// Image height is less than copy height (Invalid) // rowsPerImage is less than copy height (Invalid)
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 3, destination, 0, {0, 0, 0}, {4, 4, 1})); TestWriteTexture(dataSize, 0, 256, 3, destination, 0, {0, 0, 0}, {4, 4, 1}));
EXPECT_DEPRECATION_WARNING(
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}));
} }
// Test WriteTexture with data offset // Test WriteTexture with data offset
@ -286,12 +324,12 @@ namespace {
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
// Offset aligned // Offset aligned
TestWriteTexture(dataSize, dataSize - 4, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); TestWriteTexture(dataSize, dataSize - 4, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1});
// Offset not aligned // Offset not aligned
TestWriteTexture(dataSize, dataSize - 5, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1}); TestWriteTexture(dataSize, dataSize - 5, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1});
// Offset+size too large // Offset+size too large
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, dataSize - 3, 256, 0, destination, 0, {0, 0, 0}, {1, 1, 1})); TestWriteTexture(dataSize, dataSize - 3, 256, 1, destination, 0, {0, 0, 0}, {1, 1, 1}));
} }
// Test multisampled textures can be used in WriteTexture. // Test multisampled textures can be used in WriteTexture.
@ -302,7 +340,7 @@ namespace {
wgpu::TextureUsage::CopyDst, 4); wgpu::TextureUsage::CopyDst, 4);
ASSERT_DEVICE_ERROR( ASSERT_DEVICE_ERROR(
TestWriteTexture(dataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {2, 2, 1})); TestWriteTexture(dataSize, 0, 256, 2, destination, 0, {0, 0, 0}, {2, 2, 1}));
} }
// Test that WriteTexture cannot be run with a destroyed texture. // Test that WriteTexture cannot be run with a destroyed texture.
@ -366,7 +404,7 @@ namespace {
for (wgpu::TextureFormat format : kFormats) { for (wgpu::TextureFormat format : kFormats) {
wgpu::Texture destination = wgpu::Texture destination =
Create2DTexture({kWidth, kHeight, 1}, 1, format, wgpu::TextureUsage::CopyDst); Create2DTexture({kWidth, kHeight, 1}, 1, format, wgpu::TextureUsage::CopyDst);
ASSERT_DEVICE_ERROR(TestWriteTexture(kInvalidDataSize, 0, kBytesPerRow, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(kInvalidDataSize, 0, kBytesPerRow, kHeight,
destination, 0, {0, 0, 0}, destination, 0, {0, 0, 0},
{kWidth, kHeight, 1})); {kWidth, kHeight, 1}));
} }
@ -383,14 +421,14 @@ namespace {
// data size in this test. // data size in this test.
{ {
uint32_t invalidDataSize = validDataSize - 1; uint32_t invalidDataSize = validDataSize - 1;
ASSERT_DEVICE_ERROR(TestWriteTexture(invalidDataSize, 0, kBytesPerRow, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(invalidDataSize, 0, kBytesPerRow, kHeight,
destination, 0, {0, 0, 0}, destination, 0, {0, 0, 0},
{kWidth, kHeight, 1})); {kWidth, kHeight, 1}));
} }
{ {
TestWriteTexture(validDataSize, 0, kBytesPerRow, 0, destination, 0, {0, 0, 0}, TestWriteTexture(validDataSize, 0, kBytesPerRow, kHeight, destination, 0,
{kWidth, kHeight, 1}); {0, 0, 0}, {kWidth, kHeight, 1});
} }
} }
} }
@ -406,19 +444,19 @@ namespace {
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
// Copy to top level mip map // Copy to top level mip map
TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 1, {0, 0, 0}, TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 1, {0, 0, 0},
{1, 1, 1}); {1, 1, 1});
// Copy to high level mip map // Copy to high level mip map
TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, {0, 0, 0}, TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 2, {0, 0, 0},
{2, 1, 1}); {2, 1, 1});
// Mip level out of range // Mip level out of range
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel,
{0, 0, 0}, {1, 1, 1})); {0, 0, 0}, {1, 1, 1}));
// Copy origin out of range // Copy origin out of range
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 1, destination, maxMipmapLevel - 2,
{1, 0, 0}, {2, 1, 1})); {1, 0, 0}, {2, 1, 1}));
// Copy size out of range // Copy size out of range
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 0, destination, maxMipmapLevel - 2, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, 256, 2, destination, maxMipmapLevel - 2,
{0, 0, 0}, {2, 2, 1})); {0, 0, 0}, {2, 2, 1}));
} }
@ -460,10 +498,10 @@ namespace {
wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture(
{4, 4, 1}, 1, wgpu::TextureFormat::Depth32Float, wgpu::TextureUsage::CopyDst); {4, 4, 1}, 1, wgpu::TextureFormat::Depth32Float, wgpu::TextureUsage::CopyDst);
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All)); {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All));
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::DepthOnly)); wgpu::TextureAspect::DepthOnly));
} }
@ -473,10 +511,10 @@ namespace {
wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture(
{4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst); {4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst);
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All)); {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::All));
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::DepthOnly)); wgpu::TextureAspect::DepthOnly));
} }
@ -494,16 +532,16 @@ namespace {
{4, 4, 1}, 1, wgpu::TextureFormat::Depth24PlusStencil8, {4, 4, 1}, 1, wgpu::TextureFormat::Depth24PlusStencil8,
wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, {0, 0, 0}, {4, 4, 1}, TestWriteTexture(dataSize, 0, bytesPerRow, wgpu::kStrideUndefined, destination, 0,
wgpu::TextureAspect::StencilOnly); {0, 0, 0}, {4, 4, 1}, wgpu::TextureAspect::StencilOnly);
// And that it fails if the buffer is one byte too small // And that it fails if the buffer is one byte too small
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize - 1, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize - 1, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::StencilOnly)); wgpu::TextureAspect::StencilOnly));
// It is invalid to write just part of the subresource size // It is invalid to write just part of the subresource size
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 3, destination, 0,
{0, 0, 0}, {3, 3, 1}, {0, 0, 0}, {3, 3, 1},
wgpu::TextureAspect::StencilOnly)); wgpu::TextureAspect::StencilOnly));
} }
@ -513,7 +551,7 @@ namespace {
wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture( wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture(
{4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst); {4, 4, 1}, 1, wgpu::TextureFormat::Depth24Plus, wgpu::TextureUsage::CopyDst);
ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 0, destination, 0, ASSERT_DEVICE_ERROR(TestWriteTexture(dataSize, 0, bytesPerRow, 4, destination, 0,
{0, 0, 0}, {4, 4, 1}, {0, 0, 0}, {4, 4, 1},
wgpu::TextureAspect::StencilOnly)); wgpu::TextureAspect::StencilOnly));
} }
@ -608,14 +646,14 @@ namespace {
// Valid usage of bytesPerRow in WriteTexture with compressed texture formats. // Valid usage of bytesPerRow in WriteTexture with compressed texture formats.
{ {
constexpr uint32_t kValidBytesPerRow = 20; constexpr uint32_t kValidBytesPerRow = 20;
TestWriteTexture(512, 0, kValidBytesPerRow, 0, texture, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(512, 0, kValidBytesPerRow, 4, texture, 0, {0, 0, 0}, {4, 4, 1});
} }
// Valid bytesPerRow. // Valid bytesPerRow.
// Note that image width is not a multiple of blockWidth. // Note that image width is not a multiple of blockWidth.
{ {
constexpr uint32_t kValidBytesPerRow = 17; constexpr uint32_t kValidBytesPerRow = 17;
TestWriteTexture(512, 0, kValidBytesPerRow, 0, texture, 0, {0, 0, 0}, {4, 4, 1}); TestWriteTexture(512, 0, kValidBytesPerRow, 4, texture, 0, {0, 0, 0}, {4, 4, 1});
} }
} }
} }

View File

@ -533,7 +533,7 @@ namespace dawn_native { namespace vulkan {
// Copy |deviceWrappedTexture| into |copyDstBuffer| // Copy |deviceWrappedTexture| into |copyDstBuffer|
wgpu::TextureCopyView copySrc = wgpu::TextureCopyView copySrc =
utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0});
wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256, 0); wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256);
wgpu::Extent3D copySize = {1, 1, 1}; wgpu::Extent3D copySize = {1, 1, 1};
@ -585,7 +585,7 @@ namespace dawn_native { namespace vulkan {
utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201});
// Copy |copySrcBuffer| into |secondDeviceWrappedTexture| // Copy |copySrcBuffer| into |secondDeviceWrappedTexture|
wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256, 0); wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256);
wgpu::TextureCopyView copyDst = wgpu::TextureCopyView copyDst =
utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0});
@ -817,7 +817,7 @@ namespace dawn_native { namespace vulkan {
wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData(
secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView copySrc = wgpu::BufferCopyView copySrc =
utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow, 0); utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow);
wgpu::TextureCopyView copyDst = wgpu::TextureCopyView copyDst =
utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};
@ -846,7 +846,7 @@ namespace dawn_native { namespace vulkan {
wgpu::TextureCopyView copySrc = wgpu::TextureCopyView copySrc =
utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0});
wgpu::BufferCopyView copyDst = wgpu::BufferCopyView copyDst =
utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow, 0); utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow);
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};

View File

@ -667,7 +667,7 @@ namespace dawn_native { namespace vulkan {
// Copy |deviceWrappedTexture| into |copyDstBuffer| // Copy |deviceWrappedTexture| into |copyDstBuffer|
wgpu::TextureCopyView copySrc = wgpu::TextureCopyView copySrc =
utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(deviceWrappedTexture, 0, {0, 0, 0});
wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256, 0); wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, 256);
wgpu::Extent3D copySize = {1, 1, 1}; wgpu::Extent3D copySize = {1, 1, 1};
@ -721,7 +721,7 @@ namespace dawn_native { namespace vulkan {
utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201});
// Copy |copySrcBuffer| into |secondDeviceWrappedTexture| // Copy |copySrcBuffer| into |secondDeviceWrappedTexture|
wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256, 0); wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, 256);
wgpu::TextureCopyView copyDst = wgpu::TextureCopyView copyDst =
utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(secondDeviceWrappedTexture, 0, {0, 0, 0});
@ -980,7 +980,7 @@ namespace dawn_native { namespace vulkan {
wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData(
secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc);
wgpu::BufferCopyView copySrc = wgpu::BufferCopyView copySrc =
utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow, 0); utils::CreateBufferCopyView(copySrcBuffer, 0, bytesPerRow);
wgpu::TextureCopyView copyDst = wgpu::TextureCopyView copyDst =
utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(wrappedTexture, 0, {0, 0, 0});
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};
@ -1012,7 +1012,7 @@ namespace dawn_native { namespace vulkan {
wgpu::TextureCopyView copySrc = wgpu::TextureCopyView copySrc =
utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0}); utils::CreateTextureCopyView(nextWrappedTexture, 0, {0, 0, 0});
wgpu::BufferCopyView copyDst = wgpu::BufferCopyView copyDst =
utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow, 0); utils::CreateBufferCopyView(copyDstBuffer, 0, bytesPerRow);
wgpu::Extent3D copySize = {width, height, 1}; wgpu::Extent3D copySize = {width, height, 1};

View File

@ -44,8 +44,12 @@ namespace utils {
layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width); layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width);
uint32_t appliedRowsPerImage = rowsPerImage > 0 ? rowsPerImage : layout.mipSize.height; if (rowsPerImage == wgpu::kStrideUndefined) {
layout.bytesPerImage = layout.bytesPerRow * appliedRowsPerImage; rowsPerImage = layout.mipSize.height;
}
layout.rowsPerImage = rowsPerImage;
layout.bytesPerImage = layout.bytesPerRow * rowsPerImage;
// TODO(kainino@chromium.org): Remove this intermediate variable. // TODO(kainino@chromium.org): Remove this intermediate variable.
// It is currently needed because of an issue in the D3D12 copy splitter // It is currently needed because of an issue in the D3D12 copy splitter
@ -54,9 +58,9 @@ namespace utils {
// the actual height. // the actual height.
wgpu::Extent3D mipSizeWithHeightWorkaround = layout.mipSize; wgpu::Extent3D mipSizeWithHeightWorkaround = layout.mipSize;
mipSizeWithHeightWorkaround.height = mipSizeWithHeightWorkaround.height =
appliedRowsPerImage * utils::GetTextureFormatBlockHeight(format); rowsPerImage * utils::GetTextureFormatBlockHeight(format);
layout.byteLength = RequiredBytesInCopy(layout.bytesPerRow, appliedRowsPerImage, layout.byteLength = RequiredBytesInCopy(layout.bytesPerRow, rowsPerImage,
mipSizeWithHeightWorkaround, format); mipSizeWithHeightWorkaround, format);
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format); const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(format);
@ -120,7 +124,8 @@ namespace utils {
wgpu::Texture texture = device.CreateTexture(&descriptor); wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0}); wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, {0, 0, 0});
wgpu::TextureDataLayout textureDataLayout = utils::CreateTextureDataLayout(0, 0, 0); wgpu::TextureDataLayout textureDataLayout =
utils::CreateTextureDataLayout(0, wgpu::kStrideUndefined);
wgpu::Extent3D copyExtent = {1, 1, 1}; wgpu::Extent3D copyExtent = {1, 1, 1};
// WriteTexture with exactly 1 byte of data. // WriteTexture with exactly 1 byte of data.

View File

@ -23,6 +23,7 @@ namespace utils {
uint64_t byteLength; uint64_t byteLength;
uint64_t texelBlockCount; uint64_t texelBlockCount;
uint32_t bytesPerRow; uint32_t bytesPerRow;
uint32_t rowsPerImage;
uint32_t texelBlocksPerRow; uint32_t texelBlocksPerRow;
uint32_t bytesPerImage; uint32_t bytesPerImage;
uint32_t texelBlocksPerImage; uint32_t texelBlocksPerImage;
@ -34,7 +35,7 @@ namespace utils {
wgpu::TextureFormat format, wgpu::TextureFormat format,
wgpu::Extent3D textureSizeAtLevel0, wgpu::Extent3D textureSizeAtLevel0,
uint32_t mipmapLevel, uint32_t mipmapLevel,
uint32_t rowsPerImage); uint32_t rowsPerImage = wgpu::kStrideUndefined);
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow, uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
uint64_t rowsPerImage, uint64_t rowsPerImage,

View File

@ -53,7 +53,7 @@ namespace utils {
wgpu::BufferCopyView CreateBufferCopyView(wgpu::Buffer buffer, wgpu::BufferCopyView CreateBufferCopyView(wgpu::Buffer buffer,
uint64_t offset, uint64_t offset,
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage); uint32_t rowsPerImage = wgpu::kStrideUndefined);
wgpu::TextureCopyView CreateTextureCopyView( wgpu::TextureCopyView CreateTextureCopyView(
wgpu::Texture texture, wgpu::Texture texture,
uint32_t level, uint32_t level,
@ -61,7 +61,7 @@ namespace utils {
wgpu::TextureAspect aspect = wgpu::TextureAspect::All); wgpu::TextureAspect aspect = wgpu::TextureAspect::All);
wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset, wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset,
uint32_t bytesPerRow, uint32_t bytesPerRow,
uint32_t rowsPerImage); uint32_t rowsPerImage = wgpu::kStrideUndefined);
struct ComboRenderPassDescriptor : public wgpu::RenderPassDescriptor { struct ComboRenderPassDescriptor : public wgpu::RenderPassDescriptor {
public: public: