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:
Brandon Jones 2021-09-29 18:39:23 +00:00 committed by Dawn LUCI CQ
parent caba9139a0
commit 9b643b72f7
10 changed files with 995 additions and 731 deletions

View File

@ -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));

View File

@ -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
// //

View File

@ -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) {

View File

@ -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) {

View File

@ -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);
} }

View File

@ -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;

View File

@ -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.

View File

@ -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(

View File

@ -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

View File

@ -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