Improve validation errors, Part 3
Modified ConsumedError and TryEncode methods to allow for top-level error context messages. Applied them to: - ComputePassEncoder - ProgrammablePassEncoder - RenderEncoderBase - RenderPassEncoder - Device Bug: dawn:563 Change-Id: I4a989763f57afbcf6b1cfe87ccaaba502ebd29fe Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65101 Commit-Queue: Brandon Jones <bajones@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
caba9139a0
commit
9b643b72f7
|
@ -21,6 +21,36 @@
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structs (Manually written)
|
||||||
|
//
|
||||||
|
|
||||||
|
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
|
||||||
|
AbslFormatConvert(const Color* value,
|
||||||
|
const absl::FormatConversionSpec& spec,
|
||||||
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
|
s->Append(absl::StrFormat("[Color r:%f, g:%f, b:%f, a:%f]",
|
||||||
|
value->r, value->g, value->b, value->a));
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
|
|
||||||
|
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
|
||||||
|
AbslFormatConvert(const Extent3D* value,
|
||||||
|
const absl::FormatConversionSpec& spec,
|
||||||
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
|
s->Append(absl::StrFormat("[Extent3D width:%u, height:%u, depthOrArrayLayers:%u]",
|
||||||
|
value->width, value->height, value->depthOrArrayLayers));
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Objects
|
// Objects
|
||||||
//
|
//
|
||||||
|
@ -29,6 +59,10 @@ namespace dawn_native {
|
||||||
AbslFormatConvert(const DeviceBase* value,
|
AbslFormatConvert(const DeviceBase* value,
|
||||||
const absl::FormatConversionSpec& spec,
|
const absl::FormatConversionSpec& spec,
|
||||||
absl::FormatSink* s) {
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
s->Append("[Device");
|
s->Append("[Device");
|
||||||
const std::string& label = value->GetLabel();
|
const std::string& label = value->GetLabel();
|
||||||
if (!label.empty()) {
|
if (!label.empty()) {
|
||||||
|
@ -42,6 +76,10 @@ namespace dawn_native {
|
||||||
AbslFormatConvert(const ApiObjectBase* value,
|
AbslFormatConvert(const ApiObjectBase* value,
|
||||||
const absl::FormatConversionSpec& spec,
|
const absl::FormatConversionSpec& spec,
|
||||||
absl::FormatSink* s) {
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
s->Append("[");
|
s->Append("[");
|
||||||
s->Append(ObjectTypeAsString(value->GetType()));
|
s->Append(ObjectTypeAsString(value->GetType()));
|
||||||
const std::string& label = value->GetLabel();
|
const std::string& label = value->GetLabel();
|
||||||
|
@ -56,6 +94,10 @@ namespace dawn_native {
|
||||||
AbslFormatConvert(const TextureViewBase* value,
|
AbslFormatConvert(const TextureViewBase* value,
|
||||||
const absl::FormatConversionSpec& spec,
|
const absl::FormatConversionSpec& spec,
|
||||||
absl::FormatSink* s) {
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
s->Append("[");
|
s->Append("[");
|
||||||
s->Append(ObjectTypeAsString(value->GetType()));
|
s->Append(ObjectTypeAsString(value->GetType()));
|
||||||
const std::string& label = value->GetLabel();
|
const std::string& label = value->GetLabel();
|
||||||
|
@ -81,6 +123,10 @@ namespace dawn_native {
|
||||||
AbslFormatConvert(const {{as_cppType(type.name)}}* value,
|
AbslFormatConvert(const {{as_cppType(type.name)}}* value,
|
||||||
const absl::FormatConversionSpec& spec,
|
const absl::FormatConversionSpec& spec,
|
||||||
absl::FormatSink* s) {
|
absl::FormatSink* s) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
s->Append("[null]");
|
||||||
|
return {true};
|
||||||
|
}
|
||||||
s->Append("[{{as_cppType(type.name)}}");
|
s->Append("[{{as_cppType(type.name)}}");
|
||||||
if (value->label != nullptr) {
|
if (value->label != nullptr) {
|
||||||
s->Append(absl::StrFormat(" \"%s\"", value->label));
|
s->Append(absl::StrFormat(" \"%s\"", value->label));
|
||||||
|
|
|
@ -21,6 +21,22 @@
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structs (Manually written)
|
||||||
|
//
|
||||||
|
|
||||||
|
struct Color;
|
||||||
|
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
|
||||||
|
AbslFormatConvert(const Color* value,
|
||||||
|
const absl::FormatConversionSpec& spec,
|
||||||
|
absl::FormatSink* s);
|
||||||
|
|
||||||
|
struct Extent3D;
|
||||||
|
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
|
||||||
|
AbslFormatConvert(const Extent3D* value,
|
||||||
|
const absl::FormatConversionSpec& spec,
|
||||||
|
absl::FormatSink* s);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Objects
|
// Objects
|
||||||
//
|
//
|
||||||
|
|
|
@ -486,14 +486,16 @@ namespace dawn_native {
|
||||||
const ComputePassDescriptor* descriptor) {
|
const ComputePassDescriptor* descriptor) {
|
||||||
DeviceBase* device = GetDevice();
|
DeviceBase* device = GetDevice();
|
||||||
|
|
||||||
bool success =
|
bool success = mEncodingContext.TryEncode(
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
this,
|
||||||
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
|
DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
|
||||||
|
|
||||||
allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding BeginComputePass(%s).", descriptor);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
ComputePassEncoder* passEncoder =
|
ComputePassEncoder* passEncoder =
|
||||||
|
@ -513,8 +515,9 @@ namespace dawn_native {
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
Ref<AttachmentState> attachmentState;
|
Ref<AttachmentState> attachmentState;
|
||||||
bool success =
|
bool success = mEncodingContext.TryEncode(
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
this,
|
||||||
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
uint32_t sampleCount = 0;
|
uint32_t sampleCount = 0;
|
||||||
|
|
||||||
DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
|
DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
|
||||||
|
@ -576,7 +579,8 @@ namespace dawn_native {
|
||||||
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
|
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding BeginRenderPass(%s).", descriptor);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
RenderPassEncoder* passEncoder = new RenderPassEncoder(
|
RenderPassEncoder* passEncoder = new RenderPassEncoder(
|
||||||
|
@ -594,140 +598,152 @@ namespace dawn_native {
|
||||||
BufferBase* destination,
|
BufferBase* destination,
|
||||||
uint64_t destinationOffset,
|
uint64_t destinationOffset,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(source));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(destination));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(source));
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(destination));
|
||||||
|
|
||||||
if (source == destination) {
|
if (source == destination) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Source and destination cannot be the same buffer.");
|
"Source and destination cannot be the same buffer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateCopySizeFitsInBuffer(source, sourceOffset, size));
|
||||||
|
DAWN_TRY(ValidateCopySizeFitsInBuffer(destination, destinationOffset, size));
|
||||||
|
DAWN_TRY(ValidateB2BCopyAlignment(size, sourceOffset, destinationOffset));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateCanUseAs(source, wgpu::BufferUsage::CopySrc));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst));
|
||||||
|
|
||||||
|
mTopLevelBuffers.insert(source);
|
||||||
|
mTopLevelBuffers.insert(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_TRY(ValidateCopySizeFitsInBuffer(source, sourceOffset, size));
|
CopyBufferToBufferCmd* copy =
|
||||||
DAWN_TRY(ValidateCopySizeFitsInBuffer(destination, destinationOffset, size));
|
allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
||||||
DAWN_TRY(ValidateB2BCopyAlignment(size, sourceOffset, destinationOffset));
|
copy->source = source;
|
||||||
|
copy->sourceOffset = sourceOffset;
|
||||||
|
copy->destination = destination;
|
||||||
|
copy->destinationOffset = destinationOffset;
|
||||||
|
copy->size = size;
|
||||||
|
|
||||||
DAWN_TRY(ValidateCanUseAs(source, wgpu::BufferUsage::CopySrc));
|
return {};
|
||||||
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::CopyDst));
|
},
|
||||||
|
"encoding CopyBufferToBuffer(%s, %u, %s, %u, %u).", source, sourceOffset, destination,
|
||||||
mTopLevelBuffers.insert(source);
|
destinationOffset, size);
|
||||||
mTopLevelBuffers.insert(destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyBufferToBufferCmd* copy =
|
|
||||||
allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
|
||||||
copy->source = source;
|
|
||||||
copy->sourceOffset = sourceOffset;
|
|
||||||
copy->destination = destination;
|
|
||||||
copy->destinationOffset = destinationOffset;
|
|
||||||
copy->size = size;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APICopyBufferToTexture(const ImageCopyBuffer* source,
|
void CommandEncoder::APICopyBufferToTexture(const ImageCopyBuffer* source,
|
||||||
const ImageCopyTexture* destination,
|
const ImageCopyTexture* destination,
|
||||||
const Extent3D* copySize) {
|
const Extent3D* copySize) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *source));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *source));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
|
||||||
|
|
||||||
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
|
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
||||||
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
|
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
|
||||||
|
|
||||||
DAWN_TRY(ValidateLinearToDepthStencilCopyRestrictions(*destination));
|
DAWN_TRY(ValidateLinearToDepthStencilCopyRestrictions(*destination));
|
||||||
// We validate texture copy range before validating linear texture data,
|
// We validate texture copy range before validating linear texture data,
|
||||||
// because in the latter we divide copyExtent.width by blockWidth and
|
// because in the latter we divide copyExtent.width by blockWidth and
|
||||||
// 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(GetDevice(), *destination, *copySize));
|
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *destination, *copySize));
|
||||||
}
|
}
|
||||||
const TexelBlockInfo& blockInfo =
|
const TexelBlockInfo& blockInfo =
|
||||||
destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
|
destination->texture->GetFormat().GetAspectInfo(destination->aspect).block;
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
DAWN_TRY(ValidateLinearTextureCopyOffset(
|
DAWN_TRY(ValidateLinearTextureCopyOffset(
|
||||||
source->layout, blockInfo,
|
source->layout, blockInfo,
|
||||||
destination->texture->GetFormat().HasDepthOrStencil()));
|
destination->texture->GetFormat().HasDepthOrStencil()));
|
||||||
DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
|
DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
|
||||||
blockInfo, *copySize));
|
blockInfo, *copySize));
|
||||||
|
|
||||||
mTopLevelBuffers.insert(source->buffer);
|
mTopLevelBuffers.insert(source->buffer);
|
||||||
mTopLevelTextures.insert(destination->texture);
|
mTopLevelTextures.insert(destination->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureDataLayout srcLayout = source->layout;
|
TextureDataLayout srcLayout = source->layout;
|
||||||
ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
|
ApplyDefaultTextureDataLayoutOptions(&srcLayout, blockInfo, *copySize);
|
||||||
|
|
||||||
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 = srcLayout.offset;
|
copy->source.offset = srcLayout.offset;
|
||||||
copy->source.bytesPerRow = srcLayout.bytesPerRow;
|
copy->source.bytesPerRow = srcLayout.bytesPerRow;
|
||||||
copy->source.rowsPerImage = srcLayout.rowsPerImage;
|
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;
|
||||||
copy->destination.aspect =
|
copy->destination.aspect =
|
||||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||||
copy->copySize = *copySize;
|
copy->copySize = *copySize;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding CopyBufferToTexture(%s, %s, %s).", source->buffer, destination->texture,
|
||||||
|
copySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APICopyTextureToBuffer(const ImageCopyTexture* source,
|
void CommandEncoder::APICopyTextureToBuffer(const ImageCopyTexture* source,
|
||||||
const ImageCopyBuffer* destination,
|
const ImageCopyBuffer* destination,
|
||||||
const Extent3D* copySize) {
|
const Extent3D* copySize) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture));
|
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
|
||||||
DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source));
|
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
|
DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(source->texture));
|
||||||
|
DAWN_TRY(ValidateTextureDepthStencilToBufferCopyRestrictions(*source));
|
||||||
|
|
||||||
DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *destination));
|
DAWN_TRY(ValidateImageCopyBuffer(GetDevice(), *destination));
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
|
DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
|
||||||
|
|
||||||
// We validate texture copy range before validating linear texture data,
|
// We validate texture copy range before validating linear texture data,
|
||||||
// because in the latter we divide copyExtent.width by blockWidth and
|
// because in the latter we divide copyExtent.width by blockWidth and
|
||||||
// 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(GetDevice(), *source, *copySize));
|
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *source, *copySize));
|
||||||
}
|
}
|
||||||
const TexelBlockInfo& blockInfo =
|
const TexelBlockInfo& blockInfo =
|
||||||
source->texture->GetFormat().GetAspectInfo(source->aspect).block;
|
source->texture->GetFormat().GetAspectInfo(source->aspect).block;
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
DAWN_TRY(ValidateLinearTextureCopyOffset(
|
DAWN_TRY(ValidateLinearTextureCopyOffset(
|
||||||
destination->layout, blockInfo,
|
destination->layout, blockInfo,
|
||||||
source->texture->GetFormat().HasDepthOrStencil()));
|
source->texture->GetFormat().HasDepthOrStencil()));
|
||||||
DAWN_TRY(ValidateLinearTextureData(
|
DAWN_TRY(ValidateLinearTextureData(
|
||||||
destination->layout, destination->buffer->GetSize(), blockInfo, *copySize));
|
destination->layout, destination->buffer->GetSize(), blockInfo, *copySize));
|
||||||
|
|
||||||
mTopLevelTextures.insert(source->texture);
|
mTopLevelTextures.insert(source->texture);
|
||||||
mTopLevelBuffers.insert(destination->buffer);
|
mTopLevelBuffers.insert(destination->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureDataLayout dstLayout = destination->layout;
|
TextureDataLayout dstLayout = destination->layout;
|
||||||
ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
|
ApplyDefaultTextureDataLayoutOptions(&dstLayout, blockInfo, *copySize);
|
||||||
|
|
||||||
CopyTextureToBufferCmd* copy =
|
CopyTextureToBufferCmd* copy =
|
||||||
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||||
copy->source.texture = source->texture;
|
copy->source.texture = source->texture;
|
||||||
copy->source.origin = source->origin;
|
copy->source.origin = source->origin;
|
||||||
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 = dstLayout.offset;
|
copy->destination.offset = dstLayout.offset;
|
||||||
copy->destination.bytesPerRow = dstLayout.bytesPerRow;
|
copy->destination.bytesPerRow = dstLayout.bytesPerRow;
|
||||||
copy->destination.rowsPerImage = dstLayout.rowsPerImage;
|
copy->destination.rowsPerImage = dstLayout.rowsPerImage;
|
||||||
copy->copySize = *copySize;
|
copy->copySize = *copySize;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding CopyTextureToBuffer(%s, %s, %s).", source->texture, destination->buffer,
|
||||||
|
copySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APICopyTextureToTexture(const ImageCopyTexture* source,
|
void CommandEncoder::APICopyTextureToTexture(const ImageCopyTexture* source,
|
||||||
|
@ -746,51 +762,56 @@ namespace dawn_native {
|
||||||
void CommandEncoder::APICopyTextureToTextureHelper(const ImageCopyTexture* source,
|
void CommandEncoder::APICopyTextureToTextureHelper(const ImageCopyTexture* source,
|
||||||
const ImageCopyTexture* destination,
|
const ImageCopyTexture* destination,
|
||||||
const Extent3D* copySize) {
|
const Extent3D* copySize) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(source->texture));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(source->texture));
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
||||||
|
|
||||||
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
|
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *source, *copySize));
|
||||||
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
|
DAWN_TRY(ValidateImageCopyTexture(GetDevice(), *destination, *copySize));
|
||||||
|
|
||||||
DAWN_TRY(
|
|
||||||
ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
|
|
||||||
|
|
||||||
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *source, *copySize));
|
|
||||||
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *destination, *copySize));
|
|
||||||
|
|
||||||
// For internal usages (CopyToCopyInternal) we don't care if the user has added
|
|
||||||
// CopySrc as a usage for this texture, but we will always add it internally.
|
|
||||||
if (Internal) {
|
|
||||||
DAWN_TRY(
|
DAWN_TRY(
|
||||||
ValidateInternalCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
|
||||||
DAWN_TRY(ValidateInternalCanUseAs(destination->texture,
|
|
||||||
wgpu::TextureUsage::CopyDst));
|
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *source, *copySize));
|
||||||
} else {
|
DAWN_TRY(ValidateTextureCopyRange(GetDevice(), *destination, *copySize));
|
||||||
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
|
||||||
DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
// For internal usages (CopyToCopyInternal) we don't care if the user has added
|
||||||
|
// CopySrc as a usage for this texture, but we will always add it internally.
|
||||||
|
if (Internal) {
|
||||||
|
DAWN_TRY(
|
||||||
|
ValidateInternalCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
|
DAWN_TRY(ValidateInternalCanUseAs(destination->texture,
|
||||||
|
wgpu::TextureUsage::CopyDst));
|
||||||
|
} else {
|
||||||
|
DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
|
||||||
|
DAWN_TRY(
|
||||||
|
ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
|
||||||
|
}
|
||||||
|
|
||||||
|
mTopLevelTextures.insert(source->texture);
|
||||||
|
mTopLevelTextures.insert(destination->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
mTopLevelTextures.insert(source->texture);
|
CopyTextureToTextureCmd* copy =
|
||||||
mTopLevelTextures.insert(destination->texture);
|
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||||
}
|
copy->source.texture = source->texture;
|
||||||
|
copy->source.origin = source->origin;
|
||||||
|
copy->source.mipLevel = source->mipLevel;
|
||||||
|
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
||||||
|
copy->destination.texture = destination->texture;
|
||||||
|
copy->destination.origin = destination->origin;
|
||||||
|
copy->destination.mipLevel = destination->mipLevel;
|
||||||
|
copy->destination.aspect =
|
||||||
|
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
||||||
|
copy->copySize = *copySize;
|
||||||
|
|
||||||
CopyTextureToTextureCmd* copy =
|
return {};
|
||||||
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
},
|
||||||
copy->source.texture = source->texture;
|
"encoding CopyTextureToTexture(%s, %s, %s).", source->texture, destination->texture,
|
||||||
copy->source.origin = source->origin;
|
copySize);
|
||||||
copy->source.mipLevel = source->mipLevel;
|
|
||||||
copy->source.aspect = ConvertAspect(source->texture->GetFormat(), source->aspect);
|
|
||||||
copy->destination.texture = destination->texture;
|
|
||||||
copy->destination.origin = destination->origin;
|
|
||||||
copy->destination.mipLevel = destination->mipLevel;
|
|
||||||
copy->destination.aspect =
|
|
||||||
ConvertAspect(destination->texture->GetFormat(), destination->aspect);
|
|
||||||
copy->copySize = *copySize;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIInjectValidationError(const char* message) {
|
void CommandEncoder::APIInjectValidationError(const char* message) {
|
||||||
|
@ -800,45 +821,55 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIInsertDebugMarker(const char* groupLabel) {
|
void CommandEncoder::APIInsertDebugMarker(const char* groupLabel) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
InsertDebugMarkerCmd* cmd =
|
this,
|
||||||
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->length = strlen(groupLabel);
|
InsertDebugMarkerCmd* cmd =
|
||||||
|
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
||||||
|
cmd->length = strlen(groupLabel);
|
||||||
|
|
||||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||||
memcpy(label, groupLabel, cmd->length + 1);
|
memcpy(label, groupLabel, cmd->length + 1);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding InsertDebugMarker(\"%s\").", groupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIPopDebugGroup() {
|
void CommandEncoder::APIPopDebugGroup() {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
if (mDebugGroupStackSize == 0) {
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push.");
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
if (mDebugGroupStackSize == 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Pop must be balanced by a corresponding Push.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
||||||
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
mDebugGroupStackSize--;
|
||||||
mDebugGroupStackSize--;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding PopDebugGroup().");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIPushDebugGroup(const char* groupLabel) {
|
void CommandEncoder::APIPushDebugGroup(const char* groupLabel) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
PushDebugGroupCmd* cmd =
|
this,
|
||||||
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->length = strlen(groupLabel);
|
PushDebugGroupCmd* cmd =
|
||||||
|
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
||||||
|
cmd->length = strlen(groupLabel);
|
||||||
|
|
||||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||||
memcpy(label, groupLabel, cmd->length + 1);
|
memcpy(label, groupLabel, cmd->length + 1);
|
||||||
|
|
||||||
mDebugGroupStackSize++;
|
mDebugGroupStackSize++;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding PushDebugGroup(\"%s\").", groupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIResolveQuerySet(QuerySetBase* querySet,
|
void CommandEncoder::APIResolveQuerySet(QuerySetBase* querySet,
|
||||||
|
@ -846,77 +877,87 @@ namespace dawn_native {
|
||||||
uint32_t queryCount,
|
uint32_t queryCount,
|
||||||
BufferBase* destination,
|
BufferBase* destination,
|
||||||
uint64_t destinationOffset) {
|
uint64_t destinationOffset) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(destination));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(destination));
|
||||||
|
|
||||||
DAWN_TRY(ValidateQuerySetResolve(querySet, firstQuery, queryCount, destination,
|
DAWN_TRY(ValidateQuerySetResolve(querySet, firstQuery, queryCount, destination,
|
||||||
destinationOffset));
|
destinationOffset));
|
||||||
|
|
||||||
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
|
DAWN_TRY(ValidateCanUseAs(destination, wgpu::BufferUsage::QueryResolve));
|
||||||
|
|
||||||
TrackUsedQuerySet(querySet);
|
TrackUsedQuerySet(querySet);
|
||||||
mTopLevelBuffers.insert(destination);
|
mTopLevelBuffers.insert(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveQuerySetCmd* cmd =
|
ResolveQuerySetCmd* cmd =
|
||||||
allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
|
allocator->Allocate<ResolveQuerySetCmd>(Command::ResolveQuerySet);
|
||||||
cmd->querySet = querySet;
|
cmd->querySet = querySet;
|
||||||
cmd->firstQuery = firstQuery;
|
cmd->firstQuery = firstQuery;
|
||||||
cmd->queryCount = queryCount;
|
cmd->queryCount = queryCount;
|
||||||
cmd->destination = destination;
|
cmd->destination = destination;
|
||||||
cmd->destinationOffset = destinationOffset;
|
cmd->destinationOffset = destinationOffset;
|
||||||
|
|
||||||
// Encode internal compute pipeline for timestamp query
|
// Encode internal compute pipeline for timestamp query
|
||||||
if (querySet->GetQueryType() == wgpu::QueryType::Timestamp) {
|
if (querySet->GetQueryType() == wgpu::QueryType::Timestamp) {
|
||||||
DAWN_TRY(EncodeTimestampsToNanosecondsConversion(
|
DAWN_TRY(EncodeTimestampsToNanosecondsConversion(
|
||||||
this, querySet, firstQuery, queryCount, destination, destinationOffset));
|
this, querySet, firstQuery, queryCount, destination, destinationOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding ResolveQuerySet(%s, %u, %u, %s, %u).", querySet, firstQuery, queryCount,
|
||||||
|
destination, destinationOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIWriteBuffer(BufferBase* buffer,
|
void CommandEncoder::APIWriteBuffer(BufferBase* buffer,
|
||||||
uint64_t bufferOffset,
|
uint64_t bufferOffset,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(ValidateWriteBuffer(GetDevice(), buffer, bufferOffset, size));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
}
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateWriteBuffer(GetDevice(), buffer, bufferOffset, size));
|
||||||
|
}
|
||||||
|
|
||||||
WriteBufferCmd* cmd = allocator->Allocate<WriteBufferCmd>(Command::WriteBuffer);
|
WriteBufferCmd* cmd = allocator->Allocate<WriteBufferCmd>(Command::WriteBuffer);
|
||||||
cmd->buffer = buffer;
|
cmd->buffer = buffer;
|
||||||
cmd->offset = bufferOffset;
|
cmd->offset = bufferOffset;
|
||||||
cmd->size = size;
|
cmd->size = size;
|
||||||
|
|
||||||
uint8_t* inlinedData = allocator->AllocateData<uint8_t>(size);
|
uint8_t* inlinedData = allocator->AllocateData<uint8_t>(size);
|
||||||
memcpy(inlinedData, data, size);
|
memcpy(inlinedData, data, size);
|
||||||
|
|
||||||
mTopLevelBuffers.insert(buffer);
|
mTopLevelBuffers.insert(buffer);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding WriteBuffer(%s, %u, ..., %u).", buffer, bufferOffset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
void CommandEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
||||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext.TryEncode(
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
}
|
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
||||||
|
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
||||||
|
}
|
||||||
|
|
||||||
TrackQueryAvailability(querySet, queryIndex);
|
TrackQueryAvailability(querySet, queryIndex);
|
||||||
|
|
||||||
WriteTimestampCmd* cmd =
|
WriteTimestampCmd* cmd =
|
||||||
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
||||||
cmd->querySet = querySet;
|
cmd->querySet = querySet;
|
||||||
cmd->queryIndex = queryIndex;
|
cmd->queryIndex = queryIndex;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding WriteTimestamp(%s, %u).", querySet, queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandBufferBase* CommandEncoder::APIFinish(const CommandBufferDescriptor* descriptor) {
|
CommandBufferBase* CommandEncoder::APIFinish(const CommandBufferDescriptor* descriptor) {
|
||||||
|
|
|
@ -63,137 +63,157 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APIEndPass() {
|
void ComputePassEncoder::APIEndPass() {
|
||||||
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
if (mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
}
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
||||||
|
}
|
||||||
|
|
||||||
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
|
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
})) {
|
},
|
||||||
|
"encoding EndPass()")) {
|
||||||
mEncodingContext->ExitComputePass(this, mUsageTracker.AcquireResourceUsage());
|
mEncodingContext->ExitComputePass(this, mUsageTracker.AcquireResourceUsage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APIDispatch(uint32_t x, uint32_t y, uint32_t z) {
|
void ComputePassEncoder::APIDispatch(uint32_t x, uint32_t y, uint32_t z) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(x));
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(y));
|
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
||||||
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(z));
|
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(x));
|
||||||
}
|
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(y));
|
||||||
|
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(z));
|
||||||
|
}
|
||||||
|
|
||||||
// Record the synchronization scope for Dispatch, which is just the current bindgroups.
|
// Record the synchronization scope for Dispatch, which is just the current
|
||||||
AddDispatchSyncScope();
|
// bindgroups.
|
||||||
|
AddDispatchSyncScope();
|
||||||
|
|
||||||
DispatchCmd* dispatch = allocator->Allocate<DispatchCmd>(Command::Dispatch);
|
DispatchCmd* dispatch = allocator->Allocate<DispatchCmd>(Command::Dispatch);
|
||||||
dispatch->x = x;
|
dispatch->x = x;
|
||||||
dispatch->y = y;
|
dispatch->y = y;
|
||||||
dispatch->z = z;
|
dispatch->z = z;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding Dispatch (x: %u, y: %u, z: %u)", x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APIDispatchIndirect(BufferBase* indirectBuffer,
|
void ComputePassEncoder::APIDispatchIndirect(BufferBase* indirectBuffer,
|
||||||
uint64_t indirectOffset) {
|
uint64_t indirectOffset) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
||||||
|
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
||||||
|
|
||||||
// Indexed dispatches need a compute-shader based validation to check that the
|
// Indexed dispatches need a compute-shader based validation to check that the
|
||||||
// dispatch sizes aren't too big. Disallow them as unsafe until the validation is
|
// dispatch sizes aren't too big. Disallow them as unsafe until the validation
|
||||||
// implemented.
|
// is implemented.
|
||||||
if (GetDevice()->IsToggleEnabled(Toggle::DisallowUnsafeAPIs)) {
|
if (GetDevice()->IsToggleEnabled(Toggle::DisallowUnsafeAPIs)) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"DispatchIndirect is disallowed because it doesn't validate that the "
|
"DispatchIndirect is disallowed because it doesn't validate that the "
|
||||||
"dispatch "
|
"dispatch "
|
||||||
"size is valid yet.");
|
"size is valid yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indirectOffset % 4 != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indirectOffset >= indirectBuffer->GetSize() ||
|
||||||
|
indirectOffset + kDispatchIndirectSize > indirectBuffer->GetSize()) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indirectOffset % 4 != 0) {
|
// Record the synchronization scope for Dispatch, both the bindgroups and the
|
||||||
return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4");
|
// indirect buffer.
|
||||||
}
|
SyncScopeUsageTracker scope;
|
||||||
|
scope.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
||||||
|
mUsageTracker.AddReferencedBuffer(indirectBuffer);
|
||||||
|
AddDispatchSyncScope(std::move(scope));
|
||||||
|
|
||||||
if (indirectOffset >= indirectBuffer->GetSize() ||
|
DispatchIndirectCmd* dispatch =
|
||||||
indirectOffset + kDispatchIndirectSize > indirectBuffer->GetSize()) {
|
allocator->Allocate<DispatchIndirectCmd>(Command::DispatchIndirect);
|
||||||
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
|
dispatch->indirectBuffer = indirectBuffer;
|
||||||
}
|
dispatch->indirectOffset = indirectOffset;
|
||||||
}
|
|
||||||
|
|
||||||
// Record the synchronization scope for Dispatch, both the bindgroups and the indirect
|
return {};
|
||||||
// buffer.
|
},
|
||||||
SyncScopeUsageTracker scope;
|
"encoding DispatchIndirect with %s", indirectBuffer);
|
||||||
scope.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
|
||||||
mUsageTracker.AddReferencedBuffer(indirectBuffer);
|
|
||||||
AddDispatchSyncScope(std::move(scope));
|
|
||||||
|
|
||||||
DispatchIndirectCmd* dispatch =
|
|
||||||
allocator->Allocate<DispatchIndirectCmd>(Command::DispatchIndirect);
|
|
||||||
dispatch->indirectBuffer = indirectBuffer;
|
|
||||||
dispatch->indirectOffset = indirectOffset;
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APISetPipeline(ComputePipelineBase* pipeline) {
|
void ComputePassEncoder::APISetPipeline(ComputePipelineBase* pipeline) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
}
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
mCommandBufferState.SetComputePipeline(pipeline);
|
mCommandBufferState.SetComputePipeline(pipeline);
|
||||||
|
|
||||||
SetComputePipelineCmd* cmd =
|
SetComputePipelineCmd* cmd =
|
||||||
allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
||||||
cmd->pipeline = pipeline;
|
cmd->pipeline = pipeline;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetPipeline with %s", pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APISetBindGroup(uint32_t groupIndexIn,
|
void ComputePassEncoder::APISetBindGroup(uint32_t groupIndexIn,
|
||||||
BindGroupBase* group,
|
BindGroupBase* group,
|
||||||
uint32_t dynamicOffsetCount,
|
uint32_t dynamicOffsetCount,
|
||||||
const uint32_t* dynamicOffsets) {
|
const uint32_t* dynamicOffsets) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
BindGroupIndex groupIndex(groupIndexIn);
|
this,
|
||||||
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
BindGroupIndex groupIndex(groupIndexIn);
|
||||||
|
|
||||||
if (IsValidationEnabled()) {
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(
|
DAWN_TRY(ValidateSetBindGroup(groupIndex, group, dynamicOffsetCount,
|
||||||
ValidateSetBindGroup(groupIndex, group, dynamicOffsetCount, dynamicOffsets));
|
dynamicOffsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
mUsageTracker.AddResourcesReferencedByBindGroup(group);
|
mUsageTracker.AddResourcesReferencedByBindGroup(group);
|
||||||
|
|
||||||
RecordSetBindGroup(allocator, groupIndex, group, dynamicOffsetCount, dynamicOffsets);
|
RecordSetBindGroup(allocator, groupIndex, group, dynamicOffsetCount,
|
||||||
mCommandBufferState.SetBindGroup(groupIndex, group);
|
dynamicOffsets);
|
||||||
|
mCommandBufferState.SetBindGroup(groupIndex, group);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetBindGroup with %s at index %u", group, groupIndexIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
void ComputePassEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
if (IsValidationEnabled()) {
|
||||||
}
|
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
||||||
|
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
||||||
|
}
|
||||||
|
|
||||||
mCommandEncoder->TrackQueryAvailability(querySet, queryIndex);
|
mCommandEncoder->TrackQueryAvailability(querySet, queryIndex);
|
||||||
|
|
||||||
WriteTimestampCmd* cmd =
|
WriteTimestampCmd* cmd =
|
||||||
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
||||||
cmd->querySet = querySet;
|
cmd->querySet = querySet;
|
||||||
cmd->queryIndex = queryIndex;
|
cmd->queryIndex = queryIndex;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding WriteTimestamp to %s.", querySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePassEncoder::AddDispatchSyncScope(SyncScopeUsageTracker scope) {
|
void ComputePassEncoder::AddDispatchSyncScope(SyncScopeUsageTracker scope) {
|
||||||
|
|
|
@ -484,6 +484,7 @@ namespace dawn_native {
|
||||||
"%s is associated with %s, and cannot be used with %s.", object,
|
"%s is associated with %s, and cannot be used with %s.", object,
|
||||||
object->GetDevice(), this);
|
object->GetDevice(), this);
|
||||||
|
|
||||||
|
// TODO(dawn:563): Preserve labels for error objects.
|
||||||
DAWN_INVALID_IF(object->IsError(), "%s is an error.", object);
|
DAWN_INVALID_IF(object->IsError(), "%s is an error.", object);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -852,7 +853,8 @@ namespace dawn_native {
|
||||||
|
|
||||||
BindGroupBase* DeviceBase::APICreateBindGroup(const BindGroupDescriptor* descriptor) {
|
BindGroupBase* DeviceBase::APICreateBindGroup(const BindGroupDescriptor* descriptor) {
|
||||||
Ref<BindGroupBase> result;
|
Ref<BindGroupBase> result;
|
||||||
if (ConsumedError(CreateBindGroup(descriptor), &result)) {
|
if (ConsumedError(CreateBindGroup(descriptor), &result, "calling CreateBindGroup(%s).",
|
||||||
|
descriptor)) {
|
||||||
return BindGroupBase::MakeError(this);
|
return BindGroupBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -860,14 +862,16 @@ namespace dawn_native {
|
||||||
BindGroupLayoutBase* DeviceBase::APICreateBindGroupLayout(
|
BindGroupLayoutBase* DeviceBase::APICreateBindGroupLayout(
|
||||||
const BindGroupLayoutDescriptor* descriptor) {
|
const BindGroupLayoutDescriptor* descriptor) {
|
||||||
Ref<BindGroupLayoutBase> result;
|
Ref<BindGroupLayoutBase> result;
|
||||||
if (ConsumedError(CreateBindGroupLayout(descriptor), &result)) {
|
if (ConsumedError(CreateBindGroupLayout(descriptor), &result,
|
||||||
|
"calling CreateBindGroupLayout(%s).", descriptor)) {
|
||||||
return BindGroupLayoutBase::MakeError(this);
|
return BindGroupLayoutBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
}
|
}
|
||||||
BufferBase* DeviceBase::APICreateBuffer(const BufferDescriptor* descriptor) {
|
BufferBase* DeviceBase::APICreateBuffer(const BufferDescriptor* descriptor) {
|
||||||
Ref<BufferBase> result = nullptr;
|
Ref<BufferBase> result = nullptr;
|
||||||
if (ConsumedError(CreateBuffer(descriptor), &result)) {
|
if (ConsumedError(CreateBuffer(descriptor), &result, "calling CreateBuffer(%s).",
|
||||||
|
descriptor)) {
|
||||||
ASSERT(result == nullptr);
|
ASSERT(result == nullptr);
|
||||||
return BufferBase::MakeError(this, descriptor);
|
return BufferBase::MakeError(this, descriptor);
|
||||||
}
|
}
|
||||||
|
@ -880,7 +884,8 @@ namespace dawn_native {
|
||||||
ComputePipelineBase* DeviceBase::APICreateComputePipeline(
|
ComputePipelineBase* DeviceBase::APICreateComputePipeline(
|
||||||
const ComputePipelineDescriptor* descriptor) {
|
const ComputePipelineDescriptor* descriptor) {
|
||||||
Ref<ComputePipelineBase> result;
|
Ref<ComputePipelineBase> result;
|
||||||
if (ConsumedError(CreateComputePipeline(descriptor), &result)) {
|
if (ConsumedError(CreateComputePipeline(descriptor), &result,
|
||||||
|
"calling CreateComputePipeline(%s).", descriptor)) {
|
||||||
return ComputePipelineBase::MakeError(this);
|
return ComputePipelineBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -902,21 +907,24 @@ namespace dawn_native {
|
||||||
PipelineLayoutBase* DeviceBase::APICreatePipelineLayout(
|
PipelineLayoutBase* DeviceBase::APICreatePipelineLayout(
|
||||||
const PipelineLayoutDescriptor* descriptor) {
|
const PipelineLayoutDescriptor* descriptor) {
|
||||||
Ref<PipelineLayoutBase> result;
|
Ref<PipelineLayoutBase> result;
|
||||||
if (ConsumedError(CreatePipelineLayout(descriptor), &result)) {
|
if (ConsumedError(CreatePipelineLayout(descriptor), &result,
|
||||||
|
"calling CreatePipelineLayout(%s).", descriptor)) {
|
||||||
return PipelineLayoutBase::MakeError(this);
|
return PipelineLayoutBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
}
|
}
|
||||||
QuerySetBase* DeviceBase::APICreateQuerySet(const QuerySetDescriptor* descriptor) {
|
QuerySetBase* DeviceBase::APICreateQuerySet(const QuerySetDescriptor* descriptor) {
|
||||||
Ref<QuerySetBase> result;
|
Ref<QuerySetBase> result;
|
||||||
if (ConsumedError(CreateQuerySet(descriptor), &result)) {
|
if (ConsumedError(CreateQuerySet(descriptor), &result, "calling CreateQuerySet(%s).",
|
||||||
|
descriptor)) {
|
||||||
return QuerySetBase::MakeError(this);
|
return QuerySetBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
}
|
}
|
||||||
SamplerBase* DeviceBase::APICreateSampler(const SamplerDescriptor* descriptor) {
|
SamplerBase* DeviceBase::APICreateSampler(const SamplerDescriptor* descriptor) {
|
||||||
Ref<SamplerBase> result;
|
Ref<SamplerBase> result;
|
||||||
if (ConsumedError(CreateSampler(descriptor), &result)) {
|
if (ConsumedError(CreateSampler(descriptor), &result, "calling CreateSampler(%s).",
|
||||||
|
descriptor)) {
|
||||||
return SamplerBase::MakeError(this);
|
return SamplerBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -924,6 +932,7 @@ namespace dawn_native {
|
||||||
void DeviceBase::APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
void DeviceBase::APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
||||||
WGPUCreateRenderPipelineAsyncCallback callback,
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
|
// TODO(dawn:563): Add validation error context.
|
||||||
MaybeError maybeResult = CreateRenderPipelineAsync(descriptor, callback, userdata);
|
MaybeError maybeResult = CreateRenderPipelineAsync(descriptor, callback, userdata);
|
||||||
|
|
||||||
// Call the callback directly when a validation error has been found in the front-end
|
// Call the callback directly when a validation error has been found in the front-end
|
||||||
|
@ -938,7 +947,8 @@ namespace dawn_native {
|
||||||
RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder(
|
RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder(
|
||||||
const RenderBundleEncoderDescriptor* descriptor) {
|
const RenderBundleEncoderDescriptor* descriptor) {
|
||||||
Ref<RenderBundleEncoder> result;
|
Ref<RenderBundleEncoder> result;
|
||||||
if (ConsumedError(CreateRenderBundleEncoder(descriptor), &result)) {
|
if (ConsumedError(CreateRenderBundleEncoder(descriptor), &result,
|
||||||
|
"calling CreateRenderBundleEncoder(%s).", descriptor)) {
|
||||||
return RenderBundleEncoder::MakeError(this);
|
return RenderBundleEncoder::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -946,7 +956,8 @@ namespace dawn_native {
|
||||||
RenderPipelineBase* DeviceBase::APICreateRenderPipeline(
|
RenderPipelineBase* DeviceBase::APICreateRenderPipeline(
|
||||||
const RenderPipelineDescriptor* descriptor) {
|
const RenderPipelineDescriptor* descriptor) {
|
||||||
Ref<RenderPipelineBase> result;
|
Ref<RenderPipelineBase> result;
|
||||||
if (ConsumedError(CreateRenderPipeline(descriptor), &result)) {
|
if (ConsumedError(CreateRenderPipeline(descriptor), &result,
|
||||||
|
"calling CreateRenderPipeline(%s).", descriptor)) {
|
||||||
return RenderPipelineBase::MakeError(this);
|
return RenderPipelineBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -955,7 +966,8 @@ namespace dawn_native {
|
||||||
Ref<ShaderModuleBase> result;
|
Ref<ShaderModuleBase> result;
|
||||||
std::unique_ptr<OwnedCompilationMessages> compilationMessages(
|
std::unique_ptr<OwnedCompilationMessages> compilationMessages(
|
||||||
std::make_unique<OwnedCompilationMessages>());
|
std::make_unique<OwnedCompilationMessages>());
|
||||||
if (ConsumedError(CreateShaderModule(descriptor, compilationMessages.get()), &result)) {
|
if (ConsumedError(CreateShaderModule(descriptor, compilationMessages.get()), &result,
|
||||||
|
"calling CreateShaderModule(%s).", descriptor)) {
|
||||||
DAWN_ASSERT(result == nullptr);
|
DAWN_ASSERT(result == nullptr);
|
||||||
result = ShaderModuleBase::MakeError(this);
|
result = ShaderModuleBase::MakeError(this);
|
||||||
}
|
}
|
||||||
|
@ -968,14 +980,16 @@ namespace dawn_native {
|
||||||
SwapChainBase* DeviceBase::APICreateSwapChain(Surface* surface,
|
SwapChainBase* DeviceBase::APICreateSwapChain(Surface* surface,
|
||||||
const SwapChainDescriptor* descriptor) {
|
const SwapChainDescriptor* descriptor) {
|
||||||
Ref<SwapChainBase> result;
|
Ref<SwapChainBase> result;
|
||||||
if (ConsumedError(CreateSwapChain(surface, descriptor), &result)) {
|
if (ConsumedError(CreateSwapChain(surface, descriptor), &result,
|
||||||
|
"calling CreateSwapChain(%s).", descriptor)) {
|
||||||
return SwapChainBase::MakeError(this);
|
return SwapChainBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
}
|
}
|
||||||
TextureBase* DeviceBase::APICreateTexture(const TextureDescriptor* descriptor) {
|
TextureBase* DeviceBase::APICreateTexture(const TextureDescriptor* descriptor) {
|
||||||
Ref<TextureBase> result;
|
Ref<TextureBase> result;
|
||||||
if (ConsumedError(CreateTexture(descriptor), &result)) {
|
if (ConsumedError(CreateTexture(descriptor), &result, "calling CreateTexture(%s).",
|
||||||
|
descriptor)) {
|
||||||
return TextureBase::MakeError(this);
|
return TextureBase::MakeError(this);
|
||||||
}
|
}
|
||||||
return result.Detach();
|
return result.Detach();
|
||||||
|
@ -1042,7 +1056,8 @@ namespace dawn_native {
|
||||||
ExternalTextureBase* DeviceBase::APICreateExternalTexture(
|
ExternalTextureBase* DeviceBase::APICreateExternalTexture(
|
||||||
const ExternalTextureDescriptor* descriptor) {
|
const ExternalTextureDescriptor* descriptor) {
|
||||||
Ref<ExternalTextureBase> result = nullptr;
|
Ref<ExternalTextureBase> result = nullptr;
|
||||||
if (ConsumedError(CreateExternalTexture(descriptor), &result)) {
|
if (ConsumedError(CreateExternalTexture(descriptor), &result,
|
||||||
|
"calling CreateExternalTexture(%s).", descriptor)) {
|
||||||
return ExternalTextureBase::MakeError(this);
|
return ExternalTextureBase::MakeError(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,27 @@ namespace dawn_native {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
bool ConsumedError(ResultOrError<T> resultOrError,
|
||||||
|
T* result,
|
||||||
|
const char* formatStr,
|
||||||
|
const Args&... args) {
|
||||||
|
if (DAWN_UNLIKELY(resultOrError.IsError())) {
|
||||||
|
std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
|
||||||
|
if (error->GetType() == InternalErrorType::Validation) {
|
||||||
|
std::string out;
|
||||||
|
absl::UntypedFormatSpec format(formatStr);
|
||||||
|
if (absl::FormatUntyped(&out, format, {absl::FormatArg(args)...})) {
|
||||||
|
error->AppendContext(std::move(out));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConsumeError(std::move(error));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*result = resultOrError.AcquireSuccess();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError ValidateObject(const ApiObjectBase* object) const;
|
MaybeError ValidateObject(const ApiObjectBase* object) const;
|
||||||
|
|
||||||
AdapterBase* GetAdapter() const;
|
AdapterBase* GetAdapter() const;
|
||||||
|
|
|
@ -51,6 +51,25 @@ namespace dawn_native {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
inline bool ConsumedError(MaybeError maybeError,
|
||||||
|
const char* formatStr,
|
||||||
|
const Args&... args) {
|
||||||
|
if (DAWN_UNLIKELY(maybeError.IsError())) {
|
||||||
|
std::unique_ptr<ErrorData> error = maybeError.AcquireError();
|
||||||
|
if (error->GetType() == InternalErrorType::Validation) {
|
||||||
|
std::string out;
|
||||||
|
absl::UntypedFormatSpec format(formatStr);
|
||||||
|
if (absl::FormatUntyped(&out, format, {absl::FormatArg(args)...})) {
|
||||||
|
error->AppendContext(std::move(out));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HandleError(std::move(error));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool CheckCurrentEncoder(const ObjectBase* encoder) {
|
inline bool CheckCurrentEncoder(const ObjectBase* encoder) {
|
||||||
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
|
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
|
||||||
if (mCurrentEncoder != mTopLevelEncoder) {
|
if (mCurrentEncoder != mTopLevelEncoder) {
|
||||||
|
@ -74,6 +93,18 @@ namespace dawn_native {
|
||||||
return !ConsumedError(encodeFunction(&mPendingCommands));
|
return !ConsumedError(encodeFunction(&mPendingCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename EncodeFunction, typename... Args>
|
||||||
|
inline bool TryEncode(const ObjectBase* encoder,
|
||||||
|
EncodeFunction&& encodeFunction,
|
||||||
|
const char* formatStr,
|
||||||
|
const Args&... args) {
|
||||||
|
if (!CheckCurrentEncoder(encoder)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(!mWasMovedToIterator);
|
||||||
|
return !ConsumedError(encodeFunction(&mPendingCommands), formatStr, args...);
|
||||||
|
}
|
||||||
|
|
||||||
// Must be called prior to encoding a BeginRenderPassCmd. Note that it's OK to call this
|
// Must be called prior to encoding a BeginRenderPassCmd. Note that it's OK to call this
|
||||||
// and then not actually call EnterPass+ExitRenderPass, for example if some other pass setup
|
// and then not actually call EnterPass+ExitRenderPass, for example if some other pass setup
|
||||||
// failed validation before the BeginRenderPassCmd could be encoded.
|
// failed validation before the BeginRenderPassCmd could be encoded.
|
||||||
|
|
|
@ -55,45 +55,55 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgrammablePassEncoder::APIInsertDebugMarker(const char* groupLabel) {
|
void ProgrammablePassEncoder::APIInsertDebugMarker(const char* groupLabel) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
InsertDebugMarkerCmd* cmd =
|
this,
|
||||||
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->length = strlen(groupLabel);
|
InsertDebugMarkerCmd* cmd =
|
||||||
|
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
||||||
|
cmd->length = strlen(groupLabel);
|
||||||
|
|
||||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||||
memcpy(label, groupLabel, cmd->length + 1);
|
memcpy(label, groupLabel, cmd->length + 1);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding InsertDebugMarker(\"%s\")", groupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgrammablePassEncoder::APIPopDebugGroup() {
|
void ProgrammablePassEncoder::APIPopDebugGroup() {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
if (mDebugGroupStackSize == 0) {
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push.");
|
if (IsValidationEnabled()) {
|
||||||
|
if (mDebugGroupStackSize == 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Pop must be balanced by a corresponding Push.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
||||||
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
mDebugGroupStackSize--;
|
||||||
mDebugGroupStackSize--;
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding PopDebugGroup()");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgrammablePassEncoder::APIPushDebugGroup(const char* groupLabel) {
|
void ProgrammablePassEncoder::APIPushDebugGroup(const char* groupLabel) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
PushDebugGroupCmd* cmd =
|
this,
|
||||||
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->length = strlen(groupLabel);
|
PushDebugGroupCmd* cmd =
|
||||||
|
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
||||||
|
cmd->length = strlen(groupLabel);
|
||||||
|
|
||||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||||
memcpy(label, groupLabel, cmd->length + 1);
|
memcpy(label, groupLabel, cmd->length + 1);
|
||||||
|
|
||||||
mDebugGroupStackSize++;
|
mDebugGroupStackSize++;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding PushDebugGroup(\"%s\")", groupLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ProgrammablePassEncoder::ValidateSetBindGroup(
|
MaybeError ProgrammablePassEncoder::ValidateSetBindGroup(
|
||||||
|
|
|
@ -61,27 +61,31 @@ namespace dawn_native {
|
||||||
uint32_t instanceCount,
|
uint32_t instanceCount,
|
||||||
uint32_t firstVertex,
|
uint32_t firstVertex,
|
||||||
uint32_t firstInstance) {
|
uint32_t firstInstance) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
|
||||||
|
|
||||||
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
|
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
|
||||||
"First instance (%u) must be zero.", firstInstance);
|
"First instance (%u) must be zero.", firstInstance);
|
||||||
|
|
||||||
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForVertexBuffer(vertexCount,
|
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForVertexBuffer(vertexCount,
|
||||||
firstVertex));
|
firstVertex));
|
||||||
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForInstanceBuffer(instanceCount,
|
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForInstanceBuffer(
|
||||||
firstInstance));
|
instanceCount, firstInstance));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawCmd* draw = allocator->Allocate<DrawCmd>(Command::Draw);
|
DrawCmd* draw = allocator->Allocate<DrawCmd>(Command::Draw);
|
||||||
draw->vertexCount = vertexCount;
|
draw->vertexCount = vertexCount;
|
||||||
draw->instanceCount = instanceCount;
|
draw->instanceCount = instanceCount;
|
||||||
draw->firstVertex = firstVertex;
|
draw->firstVertex = firstVertex;
|
||||||
draw->firstInstance = firstInstance;
|
draw->firstInstance = firstInstance;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding Draw(%u, %u, %u, %u).", vertexCount, instanceCount, firstVertex,
|
||||||
|
firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APIDrawIndexed(uint32_t indexCount,
|
void RenderEncoderBase::APIDrawIndexed(uint32_t indexCount,
|
||||||
|
@ -89,268 +93,297 @@ namespace dawn_native {
|
||||||
uint32_t firstIndex,
|
uint32_t firstIndex,
|
||||||
int32_t baseVertex,
|
int32_t baseVertex,
|
||||||
uint32_t firstInstance) {
|
uint32_t firstInstance) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
||||||
|
|
||||||
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
|
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
|
||||||
"First instance (%u) must be zero.", firstInstance);
|
"First instance (%u) must be zero.", firstInstance);
|
||||||
|
|
||||||
DAWN_INVALID_IF(mDisableBaseVertex && baseVertex != 0,
|
DAWN_INVALID_IF(mDisableBaseVertex && baseVertex != 0,
|
||||||
"Base vertex (%u) must be zero.", baseVertex);
|
"Base vertex (%u) must be zero.", baseVertex);
|
||||||
|
|
||||||
DAWN_TRY(mCommandBufferState.ValidateIndexBufferInRange(indexCount, firstIndex));
|
DAWN_TRY(
|
||||||
|
mCommandBufferState.ValidateIndexBufferInRange(indexCount, firstIndex));
|
||||||
|
|
||||||
// Although we don't know actual vertex access range in CPU, we still call the
|
// Although we don't know actual vertex access range in CPU, we still call the
|
||||||
// ValidateBufferInRangeForVertexBuffer in order to deal with those vertex step mode
|
// ValidateBufferInRangeForVertexBuffer in order to deal with those vertex step
|
||||||
// vertex buffer with an array stride of zero.
|
// mode vertex buffer with an array stride of zero.
|
||||||
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForVertexBuffer(0, 0));
|
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForVertexBuffer(0, 0));
|
||||||
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForInstanceBuffer(instanceCount,
|
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForInstanceBuffer(
|
||||||
firstInstance));
|
instanceCount, firstInstance));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawIndexedCmd* draw = allocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
|
DrawIndexedCmd* draw = allocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
|
||||||
draw->indexCount = indexCount;
|
draw->indexCount = indexCount;
|
||||||
draw->instanceCount = instanceCount;
|
draw->instanceCount = instanceCount;
|
||||||
draw->firstIndex = firstIndex;
|
draw->firstIndex = firstIndex;
|
||||||
draw->baseVertex = baseVertex;
|
draw->baseVertex = baseVertex;
|
||||||
draw->firstInstance = firstInstance;
|
draw->firstInstance = firstInstance;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding DrawIndexed(%u, %u, %u, %i, %u).", indexCount, instanceCount, firstIndex,
|
||||||
|
baseVertex, firstInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APIDrawIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset) {
|
void RenderEncoderBase::APIDrawIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
|
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
||||||
|
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
|
||||||
|
|
||||||
DAWN_INVALID_IF(indirectOffset % 4 != 0,
|
DAWN_INVALID_IF(indirectOffset % 4 != 0,
|
||||||
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
|
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
indirectOffset >= indirectBuffer->GetSize() ||
|
indirectOffset >= indirectBuffer->GetSize() ||
|
||||||
kDrawIndirectSize > indirectBuffer->GetSize() - indirectOffset,
|
kDrawIndirectSize > indirectBuffer->GetSize() - indirectOffset,
|
||||||
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
|
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
|
||||||
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
|
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawIndirectCmd* cmd = allocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
|
DrawIndirectCmd* cmd = allocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
|
||||||
cmd->indirectBuffer = indirectBuffer;
|
cmd->indirectBuffer = indirectBuffer;
|
||||||
cmd->indirectOffset = indirectOffset;
|
cmd->indirectOffset = indirectOffset;
|
||||||
|
|
||||||
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding DrawIndirect(%s, %u).", indirectBuffer, indirectOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APIDrawIndexedIndirect(BufferBase* indirectBuffer,
|
void RenderEncoderBase::APIDrawIndexedIndirect(BufferBase* indirectBuffer,
|
||||||
uint64_t indirectOffset) {
|
uint64_t indirectOffset) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
||||||
|
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
||||||
|
|
||||||
DAWN_INVALID_IF(indirectOffset % 4 != 0,
|
DAWN_INVALID_IF(indirectOffset % 4 != 0,
|
||||||
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
|
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
(indirectOffset >= indirectBuffer->GetSize() ||
|
(indirectOffset >= indirectBuffer->GetSize() ||
|
||||||
kDrawIndexedIndirectSize > indirectBuffer->GetSize() - indirectOffset),
|
kDrawIndexedIndirectSize > indirectBuffer->GetSize() - indirectOffset),
|
||||||
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
|
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
|
||||||
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
|
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawIndexedIndirectCmd* cmd =
|
DrawIndexedIndirectCmd* cmd =
|
||||||
allocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect);
|
allocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect);
|
||||||
if (IsValidationEnabled()) {
|
if (IsValidationEnabled()) {
|
||||||
cmd->indirectBufferLocation = BufferLocation::New();
|
cmd->indirectBufferLocation = BufferLocation::New();
|
||||||
mIndirectDrawMetadata.AddIndexedIndirectDraw(
|
mIndirectDrawMetadata.AddIndexedIndirectDraw(
|
||||||
mCommandBufferState.GetIndexFormat(), mCommandBufferState.GetIndexBufferSize(),
|
mCommandBufferState.GetIndexFormat(),
|
||||||
indirectBuffer, indirectOffset, cmd->indirectBufferLocation.Get());
|
mCommandBufferState.GetIndexBufferSize(), indirectBuffer, indirectOffset,
|
||||||
} else {
|
cmd->indirectBufferLocation.Get());
|
||||||
cmd->indirectBufferLocation = BufferLocation::New(indirectBuffer, indirectOffset);
|
} else {
|
||||||
}
|
cmd->indirectBufferLocation =
|
||||||
|
BufferLocation::New(indirectBuffer, indirectOffset);
|
||||||
|
}
|
||||||
|
|
||||||
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding DrawIndexedIndirect(%s, %u).", indirectBuffer, indirectOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APISetPipeline(RenderPipelineBase* pipeline) {
|
void RenderEncoderBase::APISetPipeline(RenderPipelineBase* pipeline) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
||||||
|
|
||||||
// TODO(dawn:563): More detail about why the states are incompatible would be nice.
|
// TODO(dawn:563): More detail about why the states are incompatible would be
|
||||||
DAWN_INVALID_IF(
|
// nice.
|
||||||
pipeline->GetAttachmentState() != mAttachmentState.Get(),
|
DAWN_INVALID_IF(
|
||||||
"Attachment state of %s is not compatible with the attachment state of %s",
|
pipeline->GetAttachmentState() != mAttachmentState.Get(),
|
||||||
pipeline, this);
|
"Attachment state of %s is not compatible with the attachment state of %s",
|
||||||
}
|
pipeline, this);
|
||||||
|
}
|
||||||
|
|
||||||
mCommandBufferState.SetRenderPipeline(pipeline);
|
mCommandBufferState.SetRenderPipeline(pipeline);
|
||||||
|
|
||||||
SetRenderPipelineCmd* cmd =
|
SetRenderPipelineCmd* cmd =
|
||||||
allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
|
allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
|
||||||
cmd->pipeline = pipeline;
|
cmd->pipeline = pipeline;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetPipeline(%s).", pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APISetIndexBuffer(BufferBase* buffer,
|
void RenderEncoderBase::APISetIndexBuffer(BufferBase* buffer,
|
||||||
wgpu::IndexFormat format,
|
wgpu::IndexFormat format,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Index));
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Index));
|
||||||
|
|
||||||
DAWN_INVALID_IF(format == wgpu::IndexFormat::Undefined,
|
DAWN_INVALID_IF(format == wgpu::IndexFormat::Undefined,
|
||||||
"Index format must be specified");
|
"Index format must be specified");
|
||||||
|
|
||||||
DAWN_INVALID_IF(offset % uint64_t(IndexFormatSize(format)) != 0,
|
DAWN_INVALID_IF(offset % uint64_t(IndexFormatSize(format)) != 0,
|
||||||
"Index buffer offset (%u) is not a multiple of the size (%u)"
|
"Index buffer offset (%u) is not a multiple of the size (%u)"
|
||||||
"of %s.",
|
"of %s.",
|
||||||
offset, IndexFormatSize(format), format);
|
offset, IndexFormatSize(format), format);
|
||||||
|
|
||||||
uint64_t bufferSize = buffer->GetSize();
|
uint64_t bufferSize = buffer->GetSize();
|
||||||
DAWN_INVALID_IF(offset > bufferSize,
|
DAWN_INVALID_IF(offset > bufferSize,
|
||||||
"Index buffer offset (%u) is larger than the size (%u) of %s.",
|
"Index buffer offset (%u) is larger than the size (%u) of %s.",
|
||||||
offset, bufferSize, buffer);
|
offset, bufferSize, buffer);
|
||||||
|
|
||||||
uint64_t remainingSize = bufferSize - offset;
|
uint64_t remainingSize = bufferSize - offset;
|
||||||
|
|
||||||
// Temporarily treat 0 as undefined for size, and give a warning
|
// Temporarily treat 0 as undefined for size, and give a warning
|
||||||
// TODO(dawn:1058): Remove this if block
|
// TODO(dawn:1058): Remove this if block
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
size = wgpu::kWholeSize;
|
size = wgpu::kWholeSize;
|
||||||
GetDevice()->EmitDeprecationWarning(
|
GetDevice()->EmitDeprecationWarning(
|
||||||
"Using size=0 to indicate default binding size for setIndexBuffer "
|
"Using size=0 to indicate default binding size for setIndexBuffer "
|
||||||
"is deprecated. In the future it will result in a zero-size binding. "
|
"is deprecated. In the future it will result in a zero-size binding. "
|
||||||
"Use `undefined` (wgpu::kWholeSize) or just omit the parameter instead.");
|
"Use `undefined` (wgpu::kWholeSize) or just omit the parameter "
|
||||||
}
|
"instead.");
|
||||||
|
}
|
||||||
|
|
||||||
if (size == wgpu::kWholeSize) {
|
if (size == wgpu::kWholeSize) {
|
||||||
size = remainingSize;
|
size = remainingSize;
|
||||||
|
} else {
|
||||||
|
DAWN_INVALID_IF(size > remainingSize,
|
||||||
|
"Index buffer range (offset: %u, size: %u) doesn't fit in "
|
||||||
|
"the size (%u) of "
|
||||||
|
"%s.",
|
||||||
|
offset, size, bufferSize, buffer);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DAWN_INVALID_IF(
|
if (size == wgpu::kWholeSize) {
|
||||||
size > remainingSize,
|
DAWN_ASSERT(buffer->GetSize() >= offset);
|
||||||
"Index buffer range (offset: %u, size: %u) doesn't fit in the size (%u) of "
|
size = buffer->GetSize() - offset;
|
||||||
"%s.",
|
}
|
||||||
offset, size, bufferSize, buffer);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (size == wgpu::kWholeSize) {
|
|
||||||
DAWN_ASSERT(buffer->GetSize() >= offset);
|
|
||||||
size = buffer->GetSize() - offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCommandBufferState.SetIndexBuffer(format, size);
|
mCommandBufferState.SetIndexBuffer(format, size);
|
||||||
|
|
||||||
SetIndexBufferCmd* cmd =
|
SetIndexBufferCmd* cmd =
|
||||||
allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
||||||
cmd->buffer = buffer;
|
cmd->buffer = buffer;
|
||||||
cmd->format = format;
|
cmd->format = format;
|
||||||
cmd->offset = offset;
|
cmd->offset = offset;
|
||||||
cmd->size = size;
|
cmd->size = size;
|
||||||
|
|
||||||
mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Index);
|
mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Index);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetIndexBuffer(%s, %s, %u, %u).", buffer, format, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APISetVertexBuffer(uint32_t slot,
|
void RenderEncoderBase::APISetVertexBuffer(uint32_t slot,
|
||||||
BufferBase* buffer,
|
BufferBase* buffer,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Vertex));
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
||||||
|
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Vertex));
|
||||||
|
|
||||||
DAWN_INVALID_IF(slot >= kMaxVertexBuffers,
|
DAWN_INVALID_IF(slot >= kMaxVertexBuffers,
|
||||||
"Vertex buffer slot (%u) is larger the maximum (%u)", slot,
|
"Vertex buffer slot (%u) is larger the maximum (%u)", slot,
|
||||||
kMaxVertexBuffers - 1);
|
kMaxVertexBuffers - 1);
|
||||||
|
|
||||||
DAWN_INVALID_IF(offset % 4 != 0, "Vertex buffer offset (%u) is not a multiple of 4",
|
DAWN_INVALID_IF(offset % 4 != 0,
|
||||||
offset);
|
"Vertex buffer offset (%u) is not a multiple of 4", offset);
|
||||||
|
|
||||||
uint64_t bufferSize = buffer->GetSize();
|
uint64_t bufferSize = buffer->GetSize();
|
||||||
DAWN_INVALID_IF(offset > bufferSize,
|
DAWN_INVALID_IF(offset > bufferSize,
|
||||||
"Vertex buffer offset (%u) is larger than the size (%u) of %s.",
|
"Vertex buffer offset (%u) is larger than the size (%u) of %s.",
|
||||||
offset, bufferSize, buffer);
|
offset, bufferSize, buffer);
|
||||||
|
|
||||||
uint64_t remainingSize = bufferSize - offset;
|
uint64_t remainingSize = bufferSize - offset;
|
||||||
|
|
||||||
// Temporarily treat 0 as undefined for size, and give a warning
|
// Temporarily treat 0 as undefined for size, and give a warning
|
||||||
// TODO(dawn:1058): Remove this if block
|
// TODO(dawn:1058): Remove this if block
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
size = wgpu::kWholeSize;
|
size = wgpu::kWholeSize;
|
||||||
GetDevice()->EmitDeprecationWarning(
|
GetDevice()->EmitDeprecationWarning(
|
||||||
"Using size=0 to indicate default binding size for setVertexBuffer "
|
"Using size=0 to indicate default binding size for setVertexBuffer "
|
||||||
"is deprecated. In the future it will result in a zero-size binding. "
|
"is deprecated. In the future it will result in a zero-size binding. "
|
||||||
"Use `undefined` (wgpu::kWholeSize) or just omit the parameter instead.");
|
"Use `undefined` (wgpu::kWholeSize) or just omit the parameter "
|
||||||
}
|
"instead.");
|
||||||
|
}
|
||||||
|
|
||||||
if (size == wgpu::kWholeSize) {
|
if (size == wgpu::kWholeSize) {
|
||||||
size = remainingSize;
|
size = remainingSize;
|
||||||
|
} else {
|
||||||
|
DAWN_INVALID_IF(size > remainingSize,
|
||||||
|
"Vertex buffer range (offset: %u, size: %u) doesn't fit in "
|
||||||
|
"the size (%u) "
|
||||||
|
"of %s.",
|
||||||
|
offset, size, bufferSize, buffer);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DAWN_INVALID_IF(
|
if (size == wgpu::kWholeSize) {
|
||||||
size > remainingSize,
|
DAWN_ASSERT(buffer->GetSize() >= offset);
|
||||||
"Vertex buffer range (offset: %u, size: %u) doesn't fit in the size (%u) "
|
size = buffer->GetSize() - offset;
|
||||||
"of %s.",
|
}
|
||||||
offset, size, bufferSize, buffer);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (size == wgpu::kWholeSize) {
|
|
||||||
DAWN_ASSERT(buffer->GetSize() >= offset);
|
|
||||||
size = buffer->GetSize() - offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCommandBufferState.SetVertexBuffer(VertexBufferSlot(uint8_t(slot)), size);
|
mCommandBufferState.SetVertexBuffer(VertexBufferSlot(uint8_t(slot)), size);
|
||||||
|
|
||||||
SetVertexBufferCmd* cmd =
|
SetVertexBufferCmd* cmd =
|
||||||
allocator->Allocate<SetVertexBufferCmd>(Command::SetVertexBuffer);
|
allocator->Allocate<SetVertexBufferCmd>(Command::SetVertexBuffer);
|
||||||
cmd->slot = VertexBufferSlot(static_cast<uint8_t>(slot));
|
cmd->slot = VertexBufferSlot(static_cast<uint8_t>(slot));
|
||||||
cmd->buffer = buffer;
|
cmd->buffer = buffer;
|
||||||
cmd->offset = offset;
|
cmd->offset = offset;
|
||||||
cmd->size = size;
|
cmd->size = size;
|
||||||
|
|
||||||
mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Vertex);
|
mUsageTracker.BufferUsedAs(buffer, wgpu::BufferUsage::Vertex);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetVertexBuffer(%u, %s, %u, %u).", slot, buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEncoderBase::APISetBindGroup(uint32_t groupIndexIn,
|
void RenderEncoderBase::APISetBindGroup(uint32_t groupIndexIn,
|
||||||
BindGroupBase* group,
|
BindGroupBase* group,
|
||||||
uint32_t dynamicOffsetCount,
|
uint32_t dynamicOffsetCount,
|
||||||
const uint32_t* dynamicOffsets) {
|
const uint32_t* dynamicOffsets) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
BindGroupIndex groupIndex(groupIndexIn);
|
this,
|
||||||
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
BindGroupIndex groupIndex(groupIndexIn);
|
||||||
|
|
||||||
if (IsValidationEnabled()) {
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY(
|
DAWN_TRY(ValidateSetBindGroup(groupIndex, group, dynamicOffsetCount,
|
||||||
ValidateSetBindGroup(groupIndex, group, dynamicOffsetCount, dynamicOffsets));
|
dynamicOffsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordSetBindGroup(allocator, groupIndex, group, dynamicOffsetCount, dynamicOffsets);
|
RecordSetBindGroup(allocator, groupIndex, group, dynamicOffsetCount,
|
||||||
mCommandBufferState.SetBindGroup(groupIndex, group);
|
dynamicOffsets);
|
||||||
mUsageTracker.AddBindGroup(group);
|
mCommandBufferState.SetBindGroup(groupIndex, group);
|
||||||
|
mUsageTracker.AddBindGroup(group);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetBindGroup(%u, %s, %u).", groupIndexIn, group, dynamicOffsetCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
|
@ -93,43 +93,52 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APIEndPass() {
|
void RenderPassEncoder::APIEndPass() {
|
||||||
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
if (mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
mOcclusionQueryActive,
|
mOcclusionQueryActive,
|
||||||
"Render pass %s ended with incomplete occlusion query index %u of %s.",
|
"Render pass %s ended with incomplete occlusion query index %u of %s.",
|
||||||
this, mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
|
this, mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||||
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
|
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
|
||||||
mCommandEncoder.Get(),
|
mCommandEncoder.Get(),
|
||||||
std::move(mIndirectDrawMetadata)));
|
std::move(mIndirectDrawMetadata)));
|
||||||
return {};
|
return {};
|
||||||
})) {
|
},
|
||||||
|
"encoding EndPass().")) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APISetStencilReference(uint32_t reference) {
|
void RenderPassEncoder::APISetStencilReference(uint32_t reference) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
SetStencilReferenceCmd* cmd =
|
this,
|
||||||
allocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->reference = reference;
|
SetStencilReferenceCmd* cmd =
|
||||||
|
allocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
|
||||||
|
cmd->reference = reference;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetStencilReference(%u)", reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APISetBlendConstant(const Color* color) {
|
void RenderPassEncoder::APISetBlendConstant(const Color* color) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
SetBlendConstantCmd* cmd =
|
this,
|
||||||
allocator->Allocate<SetBlendConstantCmd>(Command::SetBlendConstant);
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
cmd->color = *color;
|
SetBlendConstantCmd* cmd =
|
||||||
|
allocator->Allocate<SetBlendConstantCmd>(Command::SetBlendConstant);
|
||||||
|
cmd->color = *color;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetBlendConstant(%s).", color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APISetViewport(float x,
|
void RenderPassEncoder::APISetViewport(float x,
|
||||||
|
@ -138,192 +147,214 @@ namespace dawn_native {
|
||||||
float height,
|
float height,
|
||||||
float minDepth,
|
float minDepth,
|
||||||
float maxDepth) {
|
float maxDepth) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_INVALID_IF((isnan(x) || isnan(y) || isnan(width) || isnan(height) ||
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
isnan(minDepth) || isnan(maxDepth)),
|
if (IsValidationEnabled()) {
|
||||||
"A parameter of the viewport (x: %f, y: %f, width: %f, height: %f, "
|
DAWN_INVALID_IF(
|
||||||
"minDepth: %f, maxDepth: %f) is NaN.",
|
(isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) ||
|
||||||
x, y, width, height, minDepth, maxDepth);
|
isnan(maxDepth)),
|
||||||
|
"A parameter of the viewport (x: %f, y: %f, width: %f, height: %f, "
|
||||||
|
"minDepth: %f, maxDepth: %f) is NaN.",
|
||||||
|
x, y, width, height, minDepth, maxDepth);
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
x < 0 || y < 0 || width < 0 || height < 0,
|
x < 0 || y < 0 || width < 0 || height < 0,
|
||||||
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) contains a negative "
|
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) contains a negative "
|
||||||
"value.",
|
"value.",
|
||||||
x, y, width, height);
|
x, y, width, height);
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
x + width > mRenderTargetWidth || y + height > mRenderTargetHeight,
|
x + width > mRenderTargetWidth || y + height > mRenderTargetHeight,
|
||||||
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) are not contained in "
|
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) are not contained "
|
||||||
"the render target dimensions (%u x %u).",
|
"in "
|
||||||
x, y, width, height, mRenderTargetWidth, mRenderTargetHeight);
|
"the render target dimensions (%u x %u).",
|
||||||
|
x, y, width, height, mRenderTargetWidth, mRenderTargetHeight);
|
||||||
|
|
||||||
// Check for depths being in [0, 1] and min <= max in 3 checks instead of 5.
|
// Check for depths being in [0, 1] and min <= max in 3 checks instead of 5.
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(minDepth < 0 || minDepth > maxDepth || maxDepth > 1,
|
||||||
minDepth < 0 || minDepth > maxDepth || maxDepth > 1,
|
"Viewport minDepth (%f) and maxDepth (%f) are not in [0, 1] or "
|
||||||
"Viewport minDepth (%f) and maxDepth (%f) are not in [0, 1] or minDepth was "
|
"minDepth was "
|
||||||
"greater than maxDepth.",
|
"greater than maxDepth.",
|
||||||
minDepth, maxDepth);
|
minDepth, maxDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetViewportCmd* cmd = allocator->Allocate<SetViewportCmd>(Command::SetViewport);
|
SetViewportCmd* cmd = allocator->Allocate<SetViewportCmd>(Command::SetViewport);
|
||||||
cmd->x = x;
|
cmd->x = x;
|
||||||
cmd->y = y;
|
cmd->y = y;
|
||||||
cmd->width = width;
|
cmd->width = width;
|
||||||
cmd->height = height;
|
cmd->height = height;
|
||||||
cmd->minDepth = minDepth;
|
cmd->minDepth = minDepth;
|
||||||
cmd->maxDepth = maxDepth;
|
cmd->maxDepth = maxDepth;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetViewport(%f, %f, %f, %f, %f, %f).", x, y, width, height, minDepth,
|
||||||
|
maxDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APISetScissorRect(uint32_t x,
|
void RenderPassEncoder::APISetScissorRect(uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_INVALID_IF(
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
width > mRenderTargetWidth || height > mRenderTargetHeight ||
|
if (IsValidationEnabled()) {
|
||||||
x > mRenderTargetWidth - width || y > mRenderTargetHeight - height,
|
DAWN_INVALID_IF(
|
||||||
"Scissor rect (x: %u, y: %u, width: %u, height: %u) is not contained in "
|
width > mRenderTargetWidth || height > mRenderTargetHeight ||
|
||||||
"the render target dimensions (%u x %u).",
|
x > mRenderTargetWidth - width || y > mRenderTargetHeight - height,
|
||||||
x, y, width, height, mRenderTargetWidth, mRenderTargetHeight);
|
"Scissor rect (x: %u, y: %u, width: %u, height: %u) is not contained in "
|
||||||
}
|
"the render target dimensions (%u x %u).",
|
||||||
|
x, y, width, height, mRenderTargetWidth, mRenderTargetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
SetScissorRectCmd* cmd =
|
SetScissorRectCmd* cmd =
|
||||||
allocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect);
|
allocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect);
|
||||||
cmd->x = x;
|
cmd->x = x;
|
||||||
cmd->y = y;
|
cmd->y = y;
|
||||||
cmd->width = width;
|
cmd->width = width;
|
||||||
cmd->height = height;
|
cmd->height = height;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding SetScissorRect(%u, %u, %u, %u).", x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APIExecuteBundles(uint32_t count,
|
void RenderPassEncoder::APIExecuteBundles(uint32_t count,
|
||||||
RenderBundleBase* const* renderBundles) {
|
RenderBundleBase* const* renderBundles) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
|
|
||||||
|
|
||||||
// TODO(dawn:563): Give more detail about why the states are incompatible.
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
GetAttachmentState() != renderBundles[i]->GetAttachmentState(),
|
|
||||||
"Attachment state of renderBundles[%i] (%s) is not compatible with "
|
|
||||||
"attachment state of %s.",
|
|
||||||
i, renderBundles[i], this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCommandBufferState = CommandBufferStateTracker{};
|
|
||||||
|
|
||||||
ExecuteBundlesCmd* cmd =
|
|
||||||
allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
|
|
||||||
cmd->count = count;
|
|
||||||
|
|
||||||
Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);
|
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
|
||||||
bundles[i] = renderBundles[i];
|
|
||||||
|
|
||||||
const RenderPassResourceUsage& usages = bundles[i]->GetResourceUsage();
|
|
||||||
for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
|
|
||||||
mUsageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < usages.textures.size(); ++i) {
|
|
||||||
mUsageTracker.AddRenderBundleTextureUsage(usages.textures[i],
|
|
||||||
usages.textureUsages[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsValidationEnabled()) {
|
if (IsValidationEnabled()) {
|
||||||
mIndirectDrawMetadata.AddBundle(renderBundles[i]);
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
}
|
DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
// TODO(dawn:563): Give more detail about why the states are incompatible.
|
||||||
});
|
DAWN_INVALID_IF(
|
||||||
|
GetAttachmentState() != renderBundles[i]->GetAttachmentState(),
|
||||||
|
"Attachment state of renderBundles[%i] (%s) is not compatible with "
|
||||||
|
"attachment state of %s.",
|
||||||
|
i, renderBundles[i], this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mCommandBufferState = CommandBufferStateTracker{};
|
||||||
|
|
||||||
|
ExecuteBundlesCmd* cmd =
|
||||||
|
allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
|
||||||
|
cmd->count = count;
|
||||||
|
|
||||||
|
Ref<RenderBundleBase>* bundles =
|
||||||
|
allocator->AllocateData<Ref<RenderBundleBase>>(count);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
bundles[i] = renderBundles[i];
|
||||||
|
|
||||||
|
const RenderPassResourceUsage& usages = bundles[i]->GetResourceUsage();
|
||||||
|
for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
|
||||||
|
mUsageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
|
mUsageTracker.AddRenderBundleTextureUsage(usages.textures[i],
|
||||||
|
usages.textureUsages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
mIndirectDrawMetadata.AddBundle(renderBundles[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
"encoding ExecuteBundles(%u, ...)", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APIBeginOcclusionQuery(uint32_t queryIndex) {
|
void RenderPassEncoder::APIBeginOcclusionQuery(uint32_t queryIndex) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_INVALID_IF(mOcclusionQuerySet.Get() == nullptr,
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
"The occlusionQuerySet in RenderPassDescriptor is not set.");
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_INVALID_IF(mOcclusionQuerySet.Get() == nullptr,
|
||||||
|
"The occlusionQuerySet in RenderPassDescriptor is not set.");
|
||||||
|
|
||||||
// The type of querySet has been validated by ValidateRenderPassDescriptor
|
// The type of querySet has been validated by ValidateRenderPassDescriptor
|
||||||
|
|
||||||
DAWN_INVALID_IF(queryIndex >= mOcclusionQuerySet->GetQueryCount(),
|
DAWN_INVALID_IF(queryIndex >= mOcclusionQuerySet->GetQueryCount(),
|
||||||
"Query index (%u) exceeds the number of queries (%u) in %s.",
|
"Query index (%u) exceeds the number of queries (%u) in %s.",
|
||||||
queryIndex, mOcclusionQuerySet->GetQueryCount(),
|
queryIndex, mOcclusionQuerySet->GetQueryCount(),
|
||||||
mOcclusionQuerySet.Get());
|
mOcclusionQuerySet.Get());
|
||||||
|
|
||||||
DAWN_INVALID_IF(mOcclusionQueryActive,
|
DAWN_INVALID_IF(mOcclusionQueryActive,
|
||||||
"An occlusion query (%u) in %s is already active.",
|
"An occlusion query (%u) in %s is already active.",
|
||||||
mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
|
mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
|
||||||
|
|
||||||
DAWN_TRY_CONTEXT(
|
DAWN_TRY_CONTEXT(
|
||||||
ValidateQueryIndexOverwrite(mOcclusionQuerySet.Get(), queryIndex,
|
ValidateQueryIndexOverwrite(mOcclusionQuerySet.Get(), queryIndex,
|
||||||
mUsageTracker.GetQueryAvailabilityMap()),
|
mUsageTracker.GetQueryAvailabilityMap()),
|
||||||
"validating the occlusion query index (%u) in %s", queryIndex,
|
"validating the occlusion query index (%u) in %s", queryIndex,
|
||||||
mOcclusionQuerySet.Get());
|
mOcclusionQuerySet.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the current query index for endOcclusionQuery.
|
// Record the current query index for endOcclusionQuery.
|
||||||
mCurrentOcclusionQueryIndex = queryIndex;
|
mCurrentOcclusionQueryIndex = queryIndex;
|
||||||
mOcclusionQueryActive = true;
|
mOcclusionQueryActive = true;
|
||||||
|
|
||||||
BeginOcclusionQueryCmd* cmd =
|
BeginOcclusionQueryCmd* cmd =
|
||||||
allocator->Allocate<BeginOcclusionQueryCmd>(Command::BeginOcclusionQuery);
|
allocator->Allocate<BeginOcclusionQueryCmd>(Command::BeginOcclusionQuery);
|
||||||
cmd->querySet = mOcclusionQuerySet.Get();
|
cmd->querySet = mOcclusionQuerySet.Get();
|
||||||
cmd->queryIndex = queryIndex;
|
cmd->queryIndex = queryIndex;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding BeginOcclusionQuery(%u)", queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APIEndOcclusionQuery() {
|
void RenderPassEncoder::APIEndOcclusionQuery() {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_INVALID_IF(!mOcclusionQueryActive, "No occlusion queries are active.");
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
}
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_INVALID_IF(!mOcclusionQueryActive, "No occlusion queries are active.");
|
||||||
|
}
|
||||||
|
|
||||||
TrackQueryAvailability(mOcclusionQuerySet.Get(), mCurrentOcclusionQueryIndex);
|
TrackQueryAvailability(mOcclusionQuerySet.Get(), mCurrentOcclusionQueryIndex);
|
||||||
|
|
||||||
mOcclusionQueryActive = false;
|
mOcclusionQueryActive = false;
|
||||||
|
|
||||||
EndOcclusionQueryCmd* cmd =
|
EndOcclusionQueryCmd* cmd =
|
||||||
allocator->Allocate<EndOcclusionQueryCmd>(Command::EndOcclusionQuery);
|
allocator->Allocate<EndOcclusionQueryCmd>(Command::EndOcclusionQuery);
|
||||||
cmd->querySet = mOcclusionQuerySet.Get();
|
cmd->querySet = mOcclusionQuerySet.Get();
|
||||||
cmd->queryIndex = mCurrentOcclusionQueryIndex;
|
cmd->queryIndex = mCurrentOcclusionQueryIndex;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding EndOcclusionQuery()");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
void RenderPassEncoder::APIWriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(
|
||||||
if (IsValidationEnabled()) {
|
this,
|
||||||
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
if (IsValidationEnabled()) {
|
||||||
DAWN_TRY_CONTEXT(ValidateQueryIndexOverwrite(
|
DAWN_TRY(GetDevice()->ValidateObject(querySet));
|
||||||
querySet, queryIndex, mUsageTracker.GetQueryAvailabilityMap()),
|
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
|
||||||
"validating the timestamp query index (%u) of %s", queryIndex,
|
DAWN_TRY_CONTEXT(
|
||||||
querySet);
|
ValidateQueryIndexOverwrite(querySet, queryIndex,
|
||||||
}
|
mUsageTracker.GetQueryAvailabilityMap()),
|
||||||
|
"validating the timestamp query index (%u) of %s", queryIndex, querySet);
|
||||||
|
}
|
||||||
|
|
||||||
TrackQueryAvailability(querySet, queryIndex);
|
TrackQueryAvailability(querySet, queryIndex);
|
||||||
|
|
||||||
WriteTimestampCmd* cmd =
|
WriteTimestampCmd* cmd =
|
||||||
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
|
||||||
cmd->querySet = querySet;
|
cmd->querySet = querySet;
|
||||||
cmd->queryIndex = queryIndex;
|
cmd->queryIndex = queryIndex;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
},
|
||||||
|
"encoding WriteTimestamp(%s, %u).", querySet, queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
Loading…
Reference in New Issue