Add texture aspect to texture copy view and validation tests
Bug: dawn:439
Change-Id: I0ca283f58fe2b63ac3a8c468f8ea1bb2d300856f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24683
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 1a387b7..71a66fc 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -100,6 +100,12 @@
return DAWN_VALIDATION_ERROR("Source and destination texture formats must match.");
}
+ if (src.aspect != wgpu::TextureAspect::All || dst.aspect != wgpu::TextureAspect::All) {
+ // Metal cannot select a single aspect for texture-to-texture copies
+ return DAWN_VALIDATION_ERROR(
+ "Texture aspect must be \"all\" for texture to texture copies");
+ }
+
if (src.texture->GetFormat().HasDepthOrStencil()) {
// D3D12 requires entire subresource to be copied when using CopyTextureRegion is
// used with depth/stencil.
@@ -119,6 +125,55 @@
return {};
}
+ MaybeError ValidateTextureToBufferCopyRestrictions(const TextureCopyView& src) {
+ const Format& format = src.texture->GetFormat();
+
+ bool depthSelected = false;
+ switch (src.aspect) {
+ case wgpu::TextureAspect::All:
+ switch (format.aspects) {
+ case Aspect::Color:
+ case Aspect::Stencil:
+ break;
+ case Aspect::Depth:
+ depthSelected = true;
+ break;
+ default:
+ return DAWN_VALIDATION_ERROR(
+ "A single aspect must be selected for multi planar formats in "
+ "texture to buffer copies");
+ }
+ break;
+ case wgpu::TextureAspect::DepthOnly:
+ ASSERT(format.aspects & Aspect::Depth);
+ depthSelected = true;
+ break;
+ case wgpu::TextureAspect::StencilOnly:
+ ASSERT(format.aspects & Aspect::Stencil);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ if (depthSelected) {
+ switch (format.format) {
+ case wgpu::TextureFormat::Depth24Plus:
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ return DAWN_VALIDATION_ERROR(
+ "The depth aspect of depth24plus texture cannot be selected in a "
+ "texture to buffer copy");
+ break;
+ case wgpu::TextureFormat::Depth32Float:
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ return {};
+ }
+
MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
ASSERT(wgpu::HasZeroOrOneBits(usage));
if (!(buffer->GetUsage() & usage)) {
@@ -661,8 +716,11 @@
// copyExtent.height by blockHeight while the divisibility conditions are
// checked in validating texture copy range.
DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
- DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
- destination->texture->GetFormat(), *copySize));
+ DAWN_TRY(ValidateBufferToTextureCopyRestrictions(*destination));
+ DAWN_TRY(ValidateLinearTextureData(
+ source->layout, source->buffer->GetSize(),
+ destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect),
+ *copySize));
mTopLevelBuffers.insert(source->buffer);
mTopLevelTextures.insert(destination->texture);
@@ -718,9 +776,10 @@
// copyExtent.height by blockHeight while the divisibility conditions are
// checked in validating texture copy range.
DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
- DAWN_TRY(ValidateLinearTextureData(destination->layout,
- destination->buffer->GetSize(),
- source->texture->GetFormat(), *copySize));
+ DAWN_TRY(ValidateTextureToBufferCopyRestrictions(*source));
+ DAWN_TRY(ValidateLinearTextureData(
+ destination->layout, destination->buffer->GetSize(),
+ source->texture->GetFormat().GetTexelBlockInfo(source->aspect), *copySize));
mTopLevelTextures.insert(source->texture);
mTopLevelBuffers.insert(destination->buffer);
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 11a363a..095cf61 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -370,7 +370,7 @@
static_cast<uint64_t>(maxStart);
}
- uint32_t ComputeRequiredBytesInCopy(const Format& textureFormat,
+ uint32_t ComputeRequiredBytesInCopy(const TexelBlockInfo& blockInfo,
const Extent3D& copySize,
uint32_t bytesPerRow,
uint32_t rowsPerImage) {
@@ -386,11 +386,11 @@
ASSERT(copySize.height >= 1);
ASSERT(copySize.depth >= 1);
- uint64_t texelBlockRowsPerImage = rowsPerImage / textureFormat.blockHeight;
+ uint64_t texelBlockRowsPerImage = rowsPerImage / blockInfo.blockHeight;
uint64_t bytesPerImage = bytesPerRow * texelBlockRowsPerImage;
uint64_t bytesInLastSlice =
- bytesPerRow * (copySize.height / textureFormat.blockHeight - 1) +
- (copySize.width / textureFormat.blockWidth * textureFormat.blockByteSize);
+ bytesPerRow * (copySize.height / blockInfo.blockHeight - 1) +
+ (copySize.width / blockInfo.blockWidth * blockInfo.blockByteSize);
return bytesPerImage * (copySize.depth - 1) + bytesInLastSlice;
}
@@ -408,15 +408,15 @@
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
uint64_t byteSize,
- const Format& format,
+ const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent) {
// Validation for the texel block alignments:
- if (layout.rowsPerImage % format.blockHeight != 0) {
+ if (layout.rowsPerImage % blockInfo.blockHeight != 0) {
return DAWN_VALIDATION_ERROR(
"rowsPerImage must be a multiple of compressed texture format block height");
}
- if (layout.offset % format.blockByteSize != 0) {
+ if (layout.offset % blockInfo.blockByteSize != 0) {
return DAWN_VALIDATION_ERROR("Offset must be a multiple of the texel or block size");
}
@@ -429,8 +429,8 @@
// because the divisibility conditions are necessary for the algorithm to be valid.
// TODO(tommek@google.com): to match the spec this should only be checked when
// copyExtent.depth > 1.
- uint32_t requiredBytesInCopy =
- ComputeRequiredBytesInCopy(format, copyExtent, layout.bytesPerRow, layout.rowsPerImage);
+ uint32_t requiredBytesInCopy = ComputeRequiredBytesInCopy(
+ blockInfo, copyExtent, layout.bytesPerRow, layout.rowsPerImage);
bool fitsInData =
layout.offset <= byteSize && (requiredBytesInCopy <= (byteSize - layout.offset));
@@ -440,7 +440,8 @@
}
// Validation for other members in layout:
- if (layout.bytesPerRow < copyExtent.width / format.blockWidth * format.blockByteSize) {
+ if (layout.bytesPerRow <
+ copyExtent.width / blockInfo.blockWidth * blockInfo.blockByteSize) {
return DAWN_VALIDATION_ERROR(
"bytesPerRow must not be less than the number of bytes per row");
}
@@ -482,6 +483,26 @@
"Offset.y must be a multiple of compressed texture format block height");
}
+ switch (textureCopy.aspect) {
+ case wgpu::TextureAspect::All:
+ break;
+ case wgpu::TextureAspect::DepthOnly:
+ if ((textureCopy.texture->GetFormat().aspects & Aspect::Depth) == 0) {
+ return DAWN_VALIDATION_ERROR(
+ "Texture does not have depth aspect for texture copy");
+ }
+ break;
+ case wgpu::TextureAspect::StencilOnly:
+ if ((textureCopy.texture->GetFormat().aspects & Aspect::Stencil) == 0) {
+ return DAWN_VALIDATION_ERROR(
+ "Texture does not have stencil aspect for texture copy");
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
return {};
}
@@ -523,4 +544,37 @@
return {};
}
+ MaybeError ValidateBufferToTextureCopyRestrictions(const TextureCopyView& dst) {
+ const Format& format = dst.texture->GetFormat();
+
+ bool depthSelected = false;
+ switch (dst.aspect) {
+ case wgpu::TextureAspect::All:
+ switch (format.aspects) {
+ case Aspect::Color:
+ case Aspect::Stencil:
+ break;
+ case Aspect::Depth:
+ depthSelected = true;
+ break;
+ default:
+ return DAWN_VALIDATION_ERROR(
+ "A single aspect must be selected for multi planar formats in buffer "
+ "to texture copies");
+ }
+ break;
+ case wgpu::TextureAspect::DepthOnly:
+ ASSERT(format.aspects & Aspect::Depth);
+ depthSelected = true;
+ break;
+ case wgpu::TextureAspect::StencilOnly:
+ ASSERT(format.aspects & Aspect::Stencil);
+ break;
+ }
+ if (depthSelected) {
+ return DAWN_VALIDATION_ERROR("Cannot copy into the depth aspect of a texture");
+ }
+ return {};
+ }
+
} // namespace dawn_native
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index ae0464c..719ce17 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -27,6 +27,7 @@
class QuerySetBase;
struct BeginRenderPassCmd;
struct PassResourceUsage;
+ struct TexelBlockInfo;
MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize);
MaybeError ValidateFinalDebugGroupStackSize(uint64_t debugGroupStackSize);
@@ -40,17 +41,18 @@
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
- uint32_t ComputeRequiredBytesInCopy(const Format& textureFormat,
+ uint32_t ComputeRequiredBytesInCopy(const TexelBlockInfo& blockInfo,
const Extent3D& copySize,
uint32_t bytesPerRow,
uint32_t rowsPerImage);
MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
uint64_t byteSize,
- const Format& format,
+ const TexelBlockInfo& blockInfo,
const Extent3D& copyExtent);
MaybeError ValidateTextureCopyRange(const TextureCopyView& textureCopyView,
const Extent3D& copySize);
+ MaybeError ValidateBufferToTextureCopyRestrictions(const TextureCopyView& dst);
MaybeError ValidateBufferCopyView(DeviceBase const* device,
const BufferCopyView& bufferCopyView);
diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp
index d80db78..92a8a60 100644
--- a/src/dawn_native/Format.cpp
+++ b/src/dawn_native/Format.cpp
@@ -79,6 +79,47 @@
return componentType == type;
}
+ TexelBlockInfo Format::GetTexelBlockInfo(wgpu::TextureAspect aspect) const {
+ switch (aspect) {
+ case wgpu::TextureAspect::All:
+ switch (aspects) {
+ case Aspect::Color:
+ case Aspect::Depth:
+ case Aspect::Stencil:
+ break;
+ default:
+ UNREACHABLE();
+ }
+ return *this;
+
+ case wgpu::TextureAspect::DepthOnly:
+ ASSERT(HasDepth());
+ switch (format) {
+ case wgpu::TextureFormat::Depth32Float:
+ return *this;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+
+ case wgpu::TextureAspect::StencilOnly:
+ ASSERT(HasStencil());
+ switch (format) {
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ return {1, 1, 1};
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
size_t Format::GetIndex() const {
return ComputeFormatIndex(format);
}
diff --git a/src/dawn_native/Format.h b/src/dawn_native/Format.h
index a8907ad..f57370e 100644
--- a/src/dawn_native/Format.h
+++ b/src/dawn_native/Format.h
@@ -29,12 +29,18 @@
enum class Aspect : uint8_t;
class DeviceBase;
+ struct TexelBlockInfo {
+ uint32_t blockByteSize;
+ uint32_t blockWidth;
+ uint32_t blockHeight;
+ };
+
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
// exact number of known format.
static constexpr size_t kKnownFormatCount = 52;
// A wgpu::TextureFormat along with all the information about it necessary for validation.
- struct Format {
+ struct Format : TexelBlockInfo {
enum class Type {
Float,
Sint,
@@ -51,10 +57,6 @@
Type type;
Aspect aspects;
- uint32_t blockByteSize;
- uint32_t blockWidth;
- uint32_t blockHeight;
-
static Type TextureComponentTypeToFormatType(wgpu::TextureComponentType componentType);
static wgpu::TextureComponentType FormatTypeToTextureComponentType(Type type);
@@ -64,6 +66,8 @@
bool HasDepthOrStencil() const;
bool HasComponentType(Type componentType) const;
+ TexelBlockInfo GetTexelBlockInfo(wgpu::TextureAspect aspect) const;
+
// The index of the format in the list of all known formats: a unique number for each format
// in [0, kKnownFormatCount)
size_t GetIndex() const;
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index 372885b..900b92a 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -275,8 +275,10 @@
// copyExtent.height by blockHeight while the divisibility conditions are
// checked in validating texture copy range.
DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize));
- DAWN_TRY(ValidateLinearTextureData(*dataLayout, dataSize, destination->texture->GetFormat(),
- *writeSize));
+ DAWN_TRY(ValidateBufferToTextureCopyRestrictions(*destination));
+ DAWN_TRY(ValidateLinearTextureData(
+ *dataLayout, dataSize,
+ destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect), *writeSize));
return {};
}