mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-15 03:41:34 +00:00
Rephrasing CopyBufferToTexture validation
Moved some of the validation helper functions from CommandEncoder.cpp to CommandValidation.cpp. This will make them accessible for Queue::WriteTexture. Also introduced ValidateLinearTextureData and ValidateTextureCopyRange which combine already implemented checks in a way that's defined in WebGPU spec. Bug: dawn:483 Change-Id: I04304c5e4906f3745c6adf75758fae179c6ffcfe Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24283 Commit-Queue: Tomek Ponitka <tommek@google.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
92554d75f3
commit
0f5d496f12
@ -1536,6 +1536,15 @@
|
|||||||
{"name": "origin", "type": "origin 3D"}
|
{"name": "origin", "type": "origin 3D"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"texture data layout": {
|
||||||
|
"category": "structure",
|
||||||
|
"extensible": true,
|
||||||
|
"members": [
|
||||||
|
{"name": "offset", "type": "uint64_t", "default": 0},
|
||||||
|
{"name": "bytes per row", "type": "uint32_t"},
|
||||||
|
{"name": "rows per image", "type": "uint32_t", "default": 0}
|
||||||
|
]
|
||||||
|
},
|
||||||
"texture descriptor": {
|
"texture descriptor": {
|
||||||
"category": "structure",
|
"category": "structure",
|
||||||
"extensible": true,
|
"extensible": true,
|
||||||
|
@ -38,55 +38,6 @@ namespace dawn_native {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// TODO(jiawei.shao@intel.com): add validations on the texture-to-texture copies within the
|
|
||||||
// same texture.
|
|
||||||
MaybeError ValidateCopySizeFitsInTexture(const TextureCopyView& textureCopy,
|
|
||||||
const Extent3D& copySize) {
|
|
||||||
const TextureBase* texture = textureCopy.texture;
|
|
||||||
if (textureCopy.mipLevel >= texture->GetNumMipLevels()) {
|
|
||||||
return DAWN_VALIDATION_ERROR("Copy mipLevel out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
Extent3D mipSize = texture->GetMipLevelPhysicalSize(textureCopy.mipLevel);
|
|
||||||
// For 2D textures, include the array layer as depth so it can be checked with other
|
|
||||||
// dimensions.
|
|
||||||
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
|
|
||||||
mipSize.depth = texture->GetArrayLayers();
|
|
||||||
|
|
||||||
// All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
|
|
||||||
// overflows.
|
|
||||||
if (static_cast<uint64_t>(textureCopy.origin.x) +
|
|
||||||
static_cast<uint64_t>(copySize.width) >
|
|
||||||
static_cast<uint64_t>(mipSize.width) ||
|
|
||||||
static_cast<uint64_t>(textureCopy.origin.y) +
|
|
||||||
static_cast<uint64_t>(copySize.height) >
|
|
||||||
static_cast<uint64_t>(mipSize.height) ||
|
|
||||||
static_cast<uint64_t>(textureCopy.origin.z) +
|
|
||||||
static_cast<uint64_t>(copySize.depth) >
|
|
||||||
static_cast<uint64_t>(mipSize.depth)) {
|
|
||||||
return DAWN_VALIDATION_ERROR("Copy would touch outside of the texture");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
|
|
||||||
uint64_t offset,
|
|
||||||
uint64_t size) {
|
|
||||||
uint64_t bufferSize = buffer->GetSize();
|
|
||||||
bool fitsInBuffer = offset <= bufferSize && (size <= (bufferSize - offset));
|
|
||||||
if (!fitsInBuffer) {
|
|
||||||
return DAWN_VALIDATION_ERROR("Copy would overflow the buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateCopySizeFitsInBuffer(const BufferCopyView& bufferCopy,
|
|
||||||
uint64_t dataSize) {
|
|
||||||
return ValidateCopySizeFitsInBuffer(bufferCopy.buffer, bufferCopy.offset, dataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateB2BCopyAlignment(uint64_t dataSize,
|
MaybeError ValidateB2BCopyAlignment(uint64_t dataSize,
|
||||||
uint64_t srcOffset,
|
uint64_t srcOffset,
|
||||||
uint64_t dstOffset) {
|
uint64_t dstOffset) {
|
||||||
@ -104,31 +55,6 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ValidateTexelBufferOffset(const BufferCopyView& bufferCopy,
|
|
||||||
const Format& format) {
|
|
||||||
if (bufferCopy.offset % format.blockByteSize != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Buffer offset must be a multiple of the texel or block size");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateRowsPerImage(const Format& format,
|
|
||||||
uint32_t rowsPerImage,
|
|
||||||
uint32_t copyHeight) {
|
|
||||||
if (rowsPerImage < copyHeight) {
|
|
||||||
return DAWN_VALIDATION_ERROR("rowsPerImage must not be less than the copy height.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rowsPerImage % format.blockHeight != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"rowsPerImage must be a multiple of compressed texture format block height");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
|
MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
|
||||||
if (texture->GetSampleCount() > 1) {
|
if (texture->GetSampleCount() > 1) {
|
||||||
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
||||||
@ -193,77 +119,6 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ComputeTextureCopyBufferSize(const Format& textureFormat,
|
|
||||||
const Extent3D& copySize,
|
|
||||||
uint32_t bytesPerRow,
|
|
||||||
uint32_t rowsPerImage,
|
|
||||||
uint32_t* bufferSize) {
|
|
||||||
ASSERT(rowsPerImage >= copySize.height);
|
|
||||||
if (copySize.width == 0 || copySize.height == 0 || copySize.depth == 0) {
|
|
||||||
*bufferSize = 0;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t blockByteSize = textureFormat.blockByteSize;
|
|
||||||
uint32_t blockWidth = textureFormat.blockWidth;
|
|
||||||
uint32_t blockHeight = textureFormat.blockHeight;
|
|
||||||
|
|
||||||
// TODO(cwallez@chromium.org): check for overflows
|
|
||||||
uint32_t slicePitch = bytesPerRow * rowsPerImage / blockWidth;
|
|
||||||
|
|
||||||
ASSERT(copySize.height >= 1);
|
|
||||||
uint32_t sliceSize = bytesPerRow * (copySize.height / blockHeight - 1) +
|
|
||||||
(copySize.width / blockWidth) * blockByteSize;
|
|
||||||
|
|
||||||
ASSERT(copySize.depth >= 1);
|
|
||||||
*bufferSize = (slicePitch * (copySize.depth - 1)) + sliceSize;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateBytesPerRow(const Format& format,
|
|
||||||
const Extent3D& copySize,
|
|
||||||
uint32_t bytesPerRow) {
|
|
||||||
if (bytesPerRow % kTextureBytesPerRowAlignment != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesPerRow < copySize.width / format.blockWidth * format.blockByteSize) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"bytesPerRow must not be less than the number of bytes per row");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateImageOrigin(const Format& format, const Origin3D& offset) {
|
|
||||||
if (offset.x % format.blockWidth != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Offset.x must be a multiple of compressed texture format block width");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset.y % format.blockHeight != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Offset.y must be a multiple of compressed texture format block height");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateImageCopySize(const Format& format, const Extent3D& extent) {
|
|
||||||
if (extent.width % format.blockWidth != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Extent.width must be a multiple of compressed texture format block width");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extent.height % format.blockHeight != 0) {
|
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Extent.height must be a multiple of compressed texture format block height");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
|
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
|
||||||
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
ASSERT(wgpu::HasZeroOrOneBits(usage));
|
||||||
if (!(buffer->GetUsage() & usage)) {
|
if (!(buffer->GetUsage() & usage)) {
|
||||||
@ -692,10 +547,26 @@ namespace dawn_native {
|
|||||||
DAWN_TRY_ASSIGN(fixedDest, FixTextureCopyView(GetDevice(), destination));
|
DAWN_TRY_ASSIGN(fixedDest, FixTextureCopyView(GetDevice(), destination));
|
||||||
destination = &fixedDest;
|
destination = &fixedDest;
|
||||||
|
|
||||||
// Validate objects before doing the defaulting.
|
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(source->buffer));
|
DAWN_TRY(ValidateBufferCopyView(GetDevice(), *source));
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
||||||
|
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(destination->texture));
|
||||||
|
|
||||||
|
TextureDataLayout sourceAsTextureDataLayout;
|
||||||
|
sourceAsTextureDataLayout.offset = source->offset;
|
||||||
|
sourceAsTextureDataLayout.bytesPerRow = source->bytesPerRow;
|
||||||
|
sourceAsTextureDataLayout.rowsPerImage = source->rowsPerImage;
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateLinearTextureData(sourceAsTextureDataLayout,
|
||||||
|
source->buffer->GetSize(),
|
||||||
|
destination->texture->GetFormat(), *copySize));
|
||||||
|
DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(source->buffer);
|
||||||
|
mTopLevelTextures.insert(destination->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute default value for rowsPerImage
|
// Compute default value for rowsPerImage
|
||||||
@ -704,35 +575,6 @@ namespace dawn_native {
|
|||||||
defaultedRowsPerImage = copySize->height;
|
defaultedRowsPerImage = copySize->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the rest of the validation using the default values.
|
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
|
||||||
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(destination->texture));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateRowsPerImage(destination->texture->GetFormat(),
|
|
||||||
defaultedRowsPerImage, copySize->height));
|
|
||||||
DAWN_TRY(
|
|
||||||
ValidateImageOrigin(destination->texture->GetFormat(), destination->origin));
|
|
||||||
DAWN_TRY(ValidateImageCopySize(destination->texture->GetFormat(), *copySize));
|
|
||||||
|
|
||||||
uint32_t bufferCopySize = 0;
|
|
||||||
DAWN_TRY(ValidateBytesPerRow(destination->texture->GetFormat(), *copySize,
|
|
||||||
source->bytesPerRow));
|
|
||||||
|
|
||||||
DAWN_TRY(ComputeTextureCopyBufferSize(destination->texture->GetFormat(), *copySize,
|
|
||||||
source->bytesPerRow, defaultedRowsPerImage,
|
|
||||||
&bufferCopySize));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInTexture(*destination, *copySize));
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInBuffer(*source, bufferCopySize));
|
|
||||||
DAWN_TRY(ValidateTexelBufferOffset(*source, destination->texture->GetFormat()));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
|
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
|
||||||
|
|
||||||
mTopLevelBuffers.insert(source->buffer);
|
|
||||||
mTopLevelTextures.insert(destination->texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the copy command.
|
// Record the copy command.
|
||||||
CopyBufferToTextureCmd* copy =
|
CopyBufferToTextureCmd* copy =
|
||||||
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
||||||
@ -759,10 +601,26 @@ namespace dawn_native {
|
|||||||
DAWN_TRY_ASSIGN(fixedSrc, FixTextureCopyView(GetDevice(), source));
|
DAWN_TRY_ASSIGN(fixedSrc, FixTextureCopyView(GetDevice(), source));
|
||||||
source = &fixedSrc;
|
source = &fixedSrc;
|
||||||
|
|
||||||
// Validate objects before doing the defaulting.
|
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(source->texture));
|
DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source));
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(destination->buffer));
|
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
|
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(source->texture));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateBufferCopyView(GetDevice(), *destination));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
|
||||||
|
|
||||||
|
TextureDataLayout dstAsTextureDataLayout;
|
||||||
|
dstAsTextureDataLayout.offset = destination->offset;
|
||||||
|
dstAsTextureDataLayout.bytesPerRow = destination->bytesPerRow;
|
||||||
|
dstAsTextureDataLayout.rowsPerImage = destination->rowsPerImage;
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateLinearTextureData(dstAsTextureDataLayout,
|
||||||
|
destination->buffer->GetSize(),
|
||||||
|
source->texture->GetFormat(), *copySize));
|
||||||
|
DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
|
||||||
|
|
||||||
|
mTopLevelTextures.insert(source->texture);
|
||||||
|
mTopLevelBuffers.insert(destination->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute default value for rowsPerImage
|
// Compute default value for rowsPerImage
|
||||||
@ -771,33 +629,6 @@ namespace dawn_native {
|
|||||||
defaultedRowsPerImage = copySize->height;
|
defaultedRowsPerImage = copySize->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the rest of the validation using the default values.
|
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
|
||||||
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(source->texture));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateRowsPerImage(source->texture->GetFormat(), defaultedRowsPerImage,
|
|
||||||
copySize->height));
|
|
||||||
DAWN_TRY(ValidateImageOrigin(source->texture->GetFormat(), source->origin));
|
|
||||||
DAWN_TRY(ValidateImageCopySize(source->texture->GetFormat(), *copySize));
|
|
||||||
|
|
||||||
uint32_t bufferCopySize = 0;
|
|
||||||
DAWN_TRY(ValidateBytesPerRow(source->texture->GetFormat(), *copySize,
|
|
||||||
destination->bytesPerRow));
|
|
||||||
DAWN_TRY(ComputeTextureCopyBufferSize(source->texture->GetFormat(), *copySize,
|
|
||||||
destination->bytesPerRow,
|
|
||||||
defaultedRowsPerImage, &bufferCopySize));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInTexture(*source, *copySize));
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInBuffer(*destination, bufferCopySize));
|
|
||||||
DAWN_TRY(ValidateTexelBufferOffset(*destination, source->texture->GetFormat()));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
|
|
||||||
|
|
||||||
mTopLevelTextures.insert(source->texture);
|
|
||||||
mTopLevelBuffers.insert(destination->buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the copy command.
|
// Record the copy command.
|
||||||
CopyTextureToBufferCmd* copy =
|
CopyTextureToBufferCmd* copy =
|
||||||
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||||
@ -834,14 +665,11 @@ namespace dawn_native {
|
|||||||
DAWN_TRY(
|
DAWN_TRY(
|
||||||
ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
|
ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
|
||||||
|
|
||||||
DAWN_TRY(ValidateImageOrigin(source->texture->GetFormat(), source->origin));
|
DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
|
||||||
DAWN_TRY(ValidateImageCopySize(source->texture->GetFormat(), *copySize));
|
DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
|
||||||
DAWN_TRY(
|
|
||||||
ValidateImageOrigin(destination->texture->GetFormat(), destination->origin));
|
|
||||||
DAWN_TRY(ValidateImageCopySize(destination->texture->GetFormat(), *copySize));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInTexture(*source, *copySize));
|
DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source));
|
||||||
DAWN_TRY(ValidateCopySizeFitsInTexture(*destination, *copySize));
|
DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination));
|
||||||
|
|
||||||
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "dawn_native/Buffer.h"
|
#include "dawn_native/Buffer.h"
|
||||||
#include "dawn_native/CommandBufferStateTracker.h"
|
#include "dawn_native/CommandBufferStateTracker.h"
|
||||||
#include "dawn_native/Commands.h"
|
#include "dawn_native/Commands.h"
|
||||||
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/PassResourceUsage.h"
|
#include "dawn_native/PassResourceUsage.h"
|
||||||
#include "dawn_native/QuerySet.h"
|
#include "dawn_native/QuerySet.h"
|
||||||
#include "dawn_native/RenderBundle.h"
|
#include "dawn_native/RenderBundle.h"
|
||||||
@ -119,6 +120,36 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComputeRequiredBytesInCopy(const Format& textureFormat,
|
||||||
|
const Extent3D& copySize,
|
||||||
|
uint32_t bytesPerRow,
|
||||||
|
uint32_t rowsPerImage,
|
||||||
|
uint32_t* result) {
|
||||||
|
// Default value for rowsPerImage
|
||||||
|
if (rowsPerImage == 0) {
|
||||||
|
rowsPerImage = copySize.height;
|
||||||
|
}
|
||||||
|
ASSERT(rowsPerImage >= copySize.height);
|
||||||
|
if (copySize.width == 0 || copySize.height == 0 || copySize.depth == 0) {
|
||||||
|
*result = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t blockByteSize = textureFormat.blockByteSize;
|
||||||
|
uint32_t blockWidth = textureFormat.blockWidth;
|
||||||
|
uint32_t blockHeight = textureFormat.blockHeight;
|
||||||
|
|
||||||
|
// TODO(cwallez@chromium.org): check for overflows
|
||||||
|
uint32_t slicePitch = bytesPerRow * rowsPerImage / blockWidth;
|
||||||
|
|
||||||
|
ASSERT(copySize.height >= 1);
|
||||||
|
uint32_t sliceSize = bytesPerRow * (copySize.height / blockHeight - 1) +
|
||||||
|
(copySize.width / blockWidth) * blockByteSize;
|
||||||
|
|
||||||
|
ASSERT(copySize.depth >= 1);
|
||||||
|
*result = (slicePitch * (copySize.depth - 1)) + sliceSize;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize) {
|
MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize) {
|
||||||
@ -369,4 +400,127 @@ namespace dawn_native {
|
|||||||
static_cast<uint64_t>(maxStart);
|
static_cast<uint64_t>(maxStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
|
||||||
|
uint64_t offset,
|
||||||
|
uint64_t size) {
|
||||||
|
uint64_t bufferSize = buffer->GetSize();
|
||||||
|
bool fitsInBuffer = offset <= bufferSize && (size <= (bufferSize - offset));
|
||||||
|
if (!fitsInBuffer) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Copy would overflow the buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
|
||||||
|
uint64_t byteSize,
|
||||||
|
const Format& format,
|
||||||
|
const Extent3D& copyExtent) {
|
||||||
|
// Validation for the copy being in-bounds:
|
||||||
|
if (layout.rowsPerImage != 0 && layout.rowsPerImage < copyExtent.height) {
|
||||||
|
return DAWN_VALIDATION_ERROR("rowsPerImage must not be less than the copy height.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(tommek@google.com): to match the spec this should only be checked when
|
||||||
|
// copyExtent.depth > 1.
|
||||||
|
uint32_t requiredBytesInCopy = 0;
|
||||||
|
ComputeRequiredBytesInCopy(format, copyExtent, layout.bytesPerRow, layout.rowsPerImage,
|
||||||
|
&requiredBytesInCopy);
|
||||||
|
|
||||||
|
bool fitsInData =
|
||||||
|
layout.offset <= byteSize && (requiredBytesInCopy <= (byteSize - layout.offset));
|
||||||
|
if (!fitsInData) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Required size for texture data layout exceeds the given size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation for the texel block alignments:
|
||||||
|
if (layout.rowsPerImage % format.blockHeight != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"rowsPerImage must be a multiple of compressed texture format block height");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout.offset % format.blockByteSize != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Offset must be a multiple of the texel or block size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation for other members in layout:
|
||||||
|
if (layout.bytesPerRow < copyExtent.width / format.blockWidth * format.blockByteSize) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"bytesPerRow must not be less than the number of bytes per row");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(tommek@google.com): to match the spec there should be another condition here
|
||||||
|
// on rowsPerImage >= copyExtent.height if copyExtent.depth > 1.
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateBufferCopyView(DeviceBase const* device,
|
||||||
|
const BufferCopyView& bufferCopyView) {
|
||||||
|
DAWN_TRY(device->ValidateObject(bufferCopyView.buffer));
|
||||||
|
if (bufferCopyView.bytesPerRow % kTextureBytesPerRowAlignment != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateTextureCopyView(DeviceBase const* device,
|
||||||
|
const TextureCopyView& textureCopy) {
|
||||||
|
DAWN_TRY(device->ValidateObject(textureCopy.texture));
|
||||||
|
if (textureCopy.mipLevel >= textureCopy.texture->GetNumMipLevels()) {
|
||||||
|
return DAWN_VALIDATION_ERROR("mipLevel out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureCopy.origin.x % textureCopy.texture->GetFormat().blockWidth != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Offset.x must be a multiple of compressed texture format block width");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureCopy.origin.y % textureCopy.texture->GetFormat().blockHeight != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Offset.y must be a multiple of compressed texture format block height");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateTextureCopyRange(const TextureCopyView& textureCopy,
|
||||||
|
const Extent3D& copySize) {
|
||||||
|
// TODO(jiawei.shao@intel.com): add validations on the texture-to-texture copies within the
|
||||||
|
// same texture.
|
||||||
|
const TextureBase* texture = textureCopy.texture;
|
||||||
|
|
||||||
|
// Validation for the copy being in-bounds:
|
||||||
|
Extent3D mipSize = texture->GetMipLevelPhysicalSize(textureCopy.mipLevel);
|
||||||
|
// For 2D textures, include the array layer as depth so it can be checked with other
|
||||||
|
// dimensions.
|
||||||
|
ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
|
||||||
|
mipSize.depth = texture->GetArrayLayers();
|
||||||
|
|
||||||
|
// All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
|
||||||
|
// overflows.
|
||||||
|
if (static_cast<uint64_t>(textureCopy.origin.x) + static_cast<uint64_t>(copySize.width) >
|
||||||
|
static_cast<uint64_t>(mipSize.width) ||
|
||||||
|
static_cast<uint64_t>(textureCopy.origin.y) + static_cast<uint64_t>(copySize.height) >
|
||||||
|
static_cast<uint64_t>(mipSize.height) ||
|
||||||
|
static_cast<uint64_t>(textureCopy.origin.z) + static_cast<uint64_t>(copySize.depth) >
|
||||||
|
static_cast<uint64_t>(mipSize.depth)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Touching outside of the texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation for the texel block alignments:
|
||||||
|
if (copySize.width % textureCopy.texture->GetFormat().blockWidth != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"copySize.width must be a multiple of compressed texture format block width");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copySize.height % textureCopy.texture->GetFormat().blockHeight != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"copySize.height must be a multiple of compressed texture format block height");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "dawn_native/CommandAllocator.h"
|
#include "dawn_native/CommandAllocator.h"
|
||||||
#include "dawn_native/Error.h"
|
#include "dawn_native/Error.h"
|
||||||
|
#include "dawn_native/Texture.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -39,6 +40,28 @@ namespace dawn_native {
|
|||||||
|
|
||||||
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
|
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
|
||||||
|
|
||||||
|
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
|
||||||
|
uint64_t byteSize,
|
||||||
|
const Format& format,
|
||||||
|
const Extent3D& copyExtent);
|
||||||
|
MaybeError ValidateTextureCopyRange(const TextureCopyView& textureCopyView,
|
||||||
|
const Extent3D& copySize);
|
||||||
|
|
||||||
|
MaybeError ValidateBufferCopyView(DeviceBase const* device,
|
||||||
|
const BufferCopyView& bufferCopyView);
|
||||||
|
MaybeError ValidateTextureCopyView(DeviceBase const* device,
|
||||||
|
const TextureCopyView& textureCopyView);
|
||||||
|
|
||||||
|
MaybeError ValidateRowsPerImage(const Format& format,
|
||||||
|
uint32_t rowsPerImage,
|
||||||
|
uint32_t copyHeight);
|
||||||
|
MaybeError ValidateBytesPerRow(const Format& format,
|
||||||
|
const Extent3D& copySize,
|
||||||
|
uint32_t bytesPerRow);
|
||||||
|
MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
|
||||||
|
uint64_t offset,
|
||||||
|
uint64_t size);
|
||||||
|
|
||||||
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
|
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
Loading…
x
Reference in New Issue
Block a user