Improve validation errors, Part 2

Updated validation messages in:
 - CommandBufferStateTracker
 - RenderBundleEncoder
 - RenderEncoderBase
 - RenderPassEncoder

Bug: dawn:563
Change-Id: I0e8f133333bf759921e5db1b1908ee2dc882c504
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64982
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Brandon Jones 2021-09-28 21:35:43 +00:00 committed by Dawn LUCI CQ
parent 7c73488b37
commit ea5d768f94
6 changed files with 204 additions and 177 deletions

View File

@ -1,6 +1,6 @@
# Dawn Errors
Dawn produces errors for several reasons. The most common is validation errors, indicatin that a
Dawn produces errors for several reasons. The most common is validation errors, indicating that a
given descriptor, configuration, state, or action is not valid according to the WebGPU spec. Errors
can also be produced during exceptional circumstances such as the system running out of GPU memory
or the device being lost.
@ -44,6 +44,10 @@ Errors returned from `DAWN_INVALID_IF()` or `DAWN_VALIDATION_ERROR()` should fol
* Example: `Command encoding has already finished.`
* Instead of: `encoder finished`
**Error messages should be in the present tense.**
* Example: `Buffer is not large enough...`
* Instead of: `Buffer was not large enough...`
**When possible any values mentioned should be immediately followed in parentheses by the given value.**
* Example: `("Array stride (%u) is not...", stride)`
* Output: `Array stride (16) is not...`
@ -59,7 +63,7 @@ Errors returned from `DAWN_INVALID_IF()` or `DAWN_VALIDATION_ERROR()` should fol
**When possible state both the given value and the expected value or limit.**
* Example: `("Offset (%u) is larger than the size (%u) of %s.", offset, buffer.size, buffer)`
* Output: `Offset (256) is larger than the size (144) of [Buffer "Label"].`
**State errors in terms of what failed, rather than how to satisfy the rule.**
* Example: `Binding size (3) is less than the minimum binding size (32).`
* Instead of: `Binding size (3) must not be less than the minimum binding size (32).`

View File

@ -22,6 +22,10 @@
#include "dawn_native/PipelineLayout.h"
#include "dawn_native/RenderPipeline.h"
// TODO(dawn:563): None of the error messages in this file include the buffer objects they are
// validating against. It would be nice to improve that, but difficult to do without incurring
// additional tracking costs.
namespace dawn_native {
namespace {
@ -88,17 +92,25 @@ namespace dawn_native {
mLastRenderPipeline->GetVertexBuffer(usedSlotVertex);
uint64_t arrayStride = vertexBuffer.arrayStride;
uint64_t bufferSize = mVertexBufferSizes[usedSlotVertex];
if (arrayStride == 0) {
if (vertexBuffer.usedBytesInStride > bufferSize) {
return DAWN_VALIDATION_ERROR("Vertex buffer out of bound");
}
DAWN_INVALID_IF(vertexBuffer.usedBytesInStride > bufferSize,
"Bound vertex buffer size (%u) at slot %u with an arrayStride of 0 "
"is smaller than the required size for all attributes (%u)",
bufferSize, static_cast<uint8_t>(usedSlotVertex),
vertexBuffer.usedBytesInStride);
} else {
uint64_t requiredSize =
(static_cast<uint64_t>(firstVertex) + vertexCount) * arrayStride;
// firstVertex and vertexCount are in uint32_t, and arrayStride must not
// be larger than kMaxVertexBufferArrayStride, which is currently 2048. So by
// doing checks in uint64_t we avoid overflows.
if ((static_cast<uint64_t>(firstVertex) + vertexCount) * arrayStride > bufferSize) {
return DAWN_VALIDATION_ERROR("Vertex buffer out of bound");
}
DAWN_INVALID_IF(
requiredSize > bufferSize,
"Vertex range (first: %u, count: %u) requires a larger buffer (%u) than the "
"bound buffer size (%u) of the vertex buffer at slot %u with stride (%u).",
firstVertex, vertexCount, requiredSize, bufferSize,
static_cast<uint8_t>(usedSlotVertex), arrayStride);
}
}
@ -118,17 +130,23 @@ namespace dawn_native {
uint64_t arrayStride = vertexBuffer.arrayStride;
uint64_t bufferSize = mVertexBufferSizes[usedSlotInstance];
if (arrayStride == 0) {
if (vertexBuffer.usedBytesInStride > bufferSize) {
return DAWN_VALIDATION_ERROR("Vertex buffer out of bound");
}
DAWN_INVALID_IF(vertexBuffer.usedBytesInStride > bufferSize,
"Bound vertex buffer size (%u) at slot %u with an arrayStride of 0 "
"is smaller than the required size for all attributes (%u)",
bufferSize, static_cast<uint8_t>(usedSlotInstance),
vertexBuffer.usedBytesInStride);
} else {
uint64_t requiredSize =
(static_cast<uint64_t>(firstInstance) + instanceCount) * arrayStride;
// firstInstance and instanceCount are in uint32_t, and arrayStride must
// not be larger than kMaxVertexBufferArrayStride, which is currently 2048.
// So by doing checks in uint64_t we avoid overflows.
if ((static_cast<uint64_t>(firstInstance) + instanceCount) * arrayStride >
bufferSize) {
return DAWN_VALIDATION_ERROR("Vertex buffer out of bound");
}
DAWN_INVALID_IF(
requiredSize > bufferSize,
"Instance range (first: %u, count: %u) requires a larger buffer (%u) than the "
"bound buffer size (%u) of the vertex buffer at slot %u with stride (%u).",
firstInstance, instanceCount, requiredSize, bufferSize,
static_cast<uint8_t>(usedSlotInstance), arrayStride);
}
}
@ -141,11 +159,12 @@ namespace dawn_native {
// firstIndex and indexCount are in uint32_t, while IndexFormatSize is 2 (for
// wgpu::IndexFormat::Uint16) or 4 (for wgpu::IndexFormat::Uint32), so by doing checks in
// uint64_t we avoid overflows.
if ((static_cast<uint64_t>(firstIndex) + indexCount) * IndexFormatSize(mIndexFormat) >
mIndexBufferSize) {
// Index range is out of bounds
return DAWN_VALIDATION_ERROR("Index buffer out of bound");
}
DAWN_INVALID_IF(
(static_cast<uint64_t>(firstIndex) + indexCount) * IndexFormatSize(mIndexFormat) >
mIndexBufferSize,
"Index range (first: %u, count: %u, format: %s) does not fit in index buffer size "
"(%u).",
firstIndex, indexCount, mIndexFormat, mIndexBufferSize);
return {};
}
@ -212,15 +231,15 @@ namespace dawn_native {
return {};
}
if (aspects[VALIDATION_ASPECT_INDEX_BUFFER]) {
if (DAWN_UNLIKELY(aspects[VALIDATION_ASPECT_INDEX_BUFFER])) {
DAWN_INVALID_IF(!mIndexBufferSet, "Index buffer was not set.");
wgpu::IndexFormat pipelineIndexFormat = mLastRenderPipeline->GetStripIndexFormat();
if (!mIndexBufferSet) {
return DAWN_VALIDATION_ERROR("Missing index buffer");
} else if (IsStripPrimitiveTopology(mLastRenderPipeline->GetPrimitiveTopology()) &&
mIndexFormat != pipelineIndexFormat) {
return DAWN_VALIDATION_ERROR(
"Pipeline strip index format does not match index buffer format");
}
DAWN_INVALID_IF(
IsStripPrimitiveTopology(mLastRenderPipeline->GetPrimitiveTopology()) &&
mIndexFormat != pipelineIndexFormat,
"Strip index format (%s) of %s does not match index buffer format (%s).",
pipelineIndexFormat, mLastRenderPipeline, mIndexFormat);
// The chunk of code above should be similar to the one in |RecomputeLazyAspects|.
// It returns the first invalid state found. We shouldn't be able to reach this line
@ -230,25 +249,27 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Index buffer invalid");
}
if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) {
return DAWN_VALIDATION_ERROR("Missing vertex buffer");
}
// TODO(dawn:563): Indicate which slots were not set.
DAWN_INVALID_IF(aspects[VALIDATION_ASPECT_VERTEX_BUFFERS],
"Vertex buffer slots required by %s were not set.", mLastRenderPipeline);
if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) {
if (DAWN_UNLIKELY(aspects[VALIDATION_ASPECT_BIND_GROUPS])) {
for (BindGroupIndex i : IterateBitSet(mLastPipelineLayout->GetBindGroupLayoutsMask())) {
if (mBindgroups[i] == nullptr) {
return DAWN_VALIDATION_ERROR("Missing bind group " +
std::to_string(static_cast<uint32_t>(i)));
} else if (mLastPipelineLayout->GetBindGroupLayout(i) !=
mBindgroups[i]->GetLayout()) {
return DAWN_VALIDATION_ERROR(
"Pipeline and bind group layout doesn't match for bind group " +
std::to_string(static_cast<uint32_t>(i)));
} else if (!BufferSizesAtLeastAsBig(mBindgroups[i]->GetUnverifiedBufferSizes(),
(*mMinBufferSizes)[i])) {
return DAWN_VALIDATION_ERROR("Binding sizes too small for bind group " +
std::to_string(static_cast<uint32_t>(i)));
}
DAWN_INVALID_IF(mBindgroups[i] == nullptr, "No bind group set at index %u.",
static_cast<uint32_t>(i));
DAWN_INVALID_IF(
mLastPipelineLayout->GetBindGroupLayout(i) != mBindgroups[i]->GetLayout(),
"Bind group layout %s of pipeline layout %s does not match layout %s of bind "
"group %s at index %u.",
mLastPipelineLayout->GetBindGroupLayout(i), mLastPipelineLayout,
mBindgroups[i]->GetLayout(), mBindgroups[i], static_cast<uint32_t>(i));
// TODO(dawn:563): Report the binding sizes and which ones are failing.
DAWN_INVALID_IF(!BufferSizesAtLeastAsBig(mBindgroups[i]->GetUnverifiedBufferSizes(),
(*mMinBufferSizes)[i]),
"Binding sizes are too small for bind group %s at index %u",
mBindgroups[i], static_cast<uint32_t>(i));
}
// The chunk of code above should be similar to the one in |RecomputeLazyAspects|.
@ -259,9 +280,7 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Bind groups invalid");
}
if (aspects[VALIDATION_ASPECT_PIPELINE]) {
return DAWN_VALIDATION_ERROR("Missing pipeline");
}
DAWN_INVALID_IF(aspects[VALIDATION_ASPECT_PIPELINE], "No pipeline set.");
UNREACHABLE();
}

View File

@ -405,6 +405,7 @@ namespace dawn_native {
std::ostringstream ss;
ss << error->GetMessage();
// TODO(dawn:563): Print debug groups when avaialble.
const std::vector<std::string>& contexts = error->GetContexts();
if (!contexts.empty()) {
for (auto context : contexts) {

View File

@ -31,10 +31,8 @@ namespace dawn_native {
DAWN_TRY(ValidateTextureFormat(textureFormat));
const Format* format = nullptr;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat));
if (!format->IsColor() || !format->isRenderable) {
return DAWN_VALIDATION_ERROR(
"The color attachment texture format is not color renderable");
}
DAWN_INVALID_IF(!format->IsColor() || !format->isRenderable,
"Texture format %s is not color renderable.", textureFormat);
return {};
}
@ -43,36 +41,35 @@ namespace dawn_native {
DAWN_TRY(ValidateTextureFormat(textureFormat));
const Format* format = nullptr;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(textureFormat));
if (!format->HasDepthOrStencil() || !format->isRenderable) {
return DAWN_VALIDATION_ERROR(
"The depth stencil attachment texture format is not a renderable depth/stencil "
"format");
}
DAWN_INVALID_IF(!format->HasDepthOrStencil() || !format->isRenderable,
"Texture format %s is not depth/stencil renderable.", textureFormat);
return {};
}
MaybeError ValidateRenderBundleEncoderDescriptor(
const DeviceBase* device,
const RenderBundleEncoderDescriptor* descriptor) {
if (!IsValidSampleCount(descriptor->sampleCount)) {
return DAWN_VALIDATION_ERROR("Sample count is not supported");
}
DAWN_INVALID_IF(!IsValidSampleCount(descriptor->sampleCount),
"Sample count (%u) is not supported.", descriptor->sampleCount);
if (descriptor->colorFormatsCount > kMaxColorAttachments) {
return DAWN_VALIDATION_ERROR("Color formats count exceeds maximum");
}
DAWN_INVALID_IF(
descriptor->colorFormatsCount > kMaxColorAttachments,
"Color formats count (%u) exceeds maximum number of color attachements (%u).",
descriptor->colorFormatsCount, kMaxColorAttachments);
if (descriptor->colorFormatsCount == 0 &&
descriptor->depthStencilFormat == wgpu::TextureFormat::Undefined) {
return DAWN_VALIDATION_ERROR("Should have at least one attachment format");
}
DAWN_INVALID_IF(descriptor->colorFormatsCount == 0 &&
descriptor->depthStencilFormat == wgpu::TextureFormat::Undefined,
"No color or depth/stencil attachment formats specified.");
for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) {
DAWN_TRY(ValidateColorAttachmentFormat(device, descriptor->colorFormats[i]));
DAWN_TRY_CONTEXT(ValidateColorAttachmentFormat(device, descriptor->colorFormats[i]),
"validating colorFormats[%u]", i);
}
if (descriptor->depthStencilFormat != wgpu::TextureFormat::Undefined) {
DAWN_TRY(ValidateDepthStencilAttachmentFormat(device, descriptor->depthStencilFormat));
DAWN_TRY_CONTEXT(
ValidateDepthStencilAttachmentFormat(device, descriptor->depthStencilFormat),
"validating depthStencilFormat");
}
return {};

View File

@ -65,9 +65,8 @@ namespace dawn_native {
if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
if (mDisableBaseInstance && firstInstance != 0) {
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
}
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
"First instance (%u) must be zero.", firstInstance);
DAWN_TRY(mCommandBufferState.ValidateBufferInRangeForVertexBuffer(vertexCount,
firstVertex));
@ -94,12 +93,11 @@ namespace dawn_native {
if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
if (mDisableBaseInstance && firstInstance != 0) {
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
}
if (mDisableBaseVertex && baseVertex != 0) {
return DAWN_VALIDATION_ERROR("Non-zero base vertex not supported");
}
DAWN_INVALID_IF(mDisableBaseInstance && firstInstance != 0,
"First instance (%u) must be zero.", firstInstance);
DAWN_INVALID_IF(mDisableBaseVertex && baseVertex != 0,
"Base vertex (%u) must be zero.", baseVertex);
DAWN_TRY(mCommandBufferState.ValidateIndexBufferInRange(indexCount, firstIndex));
@ -129,14 +127,14 @@ namespace dawn_native {
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
if (indirectOffset % 4 != 0) {
return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4");
}
DAWN_INVALID_IF(indirectOffset % 4 != 0,
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
if (indirectOffset >= indirectBuffer->GetSize() ||
kDrawIndirectSize > indirectBuffer->GetSize() - indirectOffset) {
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
}
DAWN_INVALID_IF(
indirectOffset >= indirectBuffer->GetSize() ||
kDrawIndirectSize > indirectBuffer->GetSize() - indirectOffset,
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
}
DrawIndirectCmd* cmd = allocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
@ -157,14 +155,14 @@ namespace dawn_native {
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
if (indirectOffset % 4 != 0) {
return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4");
}
DAWN_INVALID_IF(indirectOffset % 4 != 0,
"Indirect offset (%u) is not a multiple of 4.", indirectOffset);
if ((indirectOffset >= indirectBuffer->GetSize() ||
kDrawIndexedIndirectSize > indirectBuffer->GetSize() - indirectOffset)) {
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
}
DAWN_INVALID_IF(
(indirectOffset >= indirectBuffer->GetSize() ||
kDrawIndexedIndirectSize > indirectBuffer->GetSize() - indirectOffset),
"Indirect offset (%u) is out of bounds of indirect buffer %s size (%u).",
indirectOffset, indirectBuffer, indirectBuffer->GetSize());
}
DrawIndexedIndirectCmd* cmd =
@ -189,11 +187,11 @@ namespace dawn_native {
if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
if (pipeline->GetAttachmentState() != mAttachmentState.Get()) {
return DAWN_VALIDATION_ERROR(
"Pipeline attachment state is not compatible with render encoder "
"attachment state");
}
// TODO(dawn:563): More detail about why the states are incompatible would be nice.
DAWN_INVALID_IF(
pipeline->GetAttachmentState() != mAttachmentState.Get(),
"Attachment state of %s is not compatible with the attachment state of %s",
pipeline, this);
}
mCommandBufferState.SetRenderPipeline(pipeline);
@ -215,20 +213,19 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateObject(buffer));
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Index));
DAWN_TRY(ValidateIndexFormat(format));
if (format == wgpu::IndexFormat::Undefined) {
return DAWN_VALIDATION_ERROR("Index format must be specified");
}
DAWN_INVALID_IF(format == wgpu::IndexFormat::Undefined,
"Index format must be specified");
if (offset % uint64_t(IndexFormatSize(format)) != 0) {
return DAWN_VALIDATION_ERROR(
"Offset must be a multiple of the index format size");
}
DAWN_INVALID_IF(offset % uint64_t(IndexFormatSize(format)) != 0,
"Index buffer offset (%u) is not a multiple of the size (%u)"
"of %s.",
offset, IndexFormatSize(format), format);
uint64_t bufferSize = buffer->GetSize();
if (offset > bufferSize) {
return DAWN_VALIDATION_ERROR("Offset larger than the buffer size");
}
DAWN_INVALID_IF(offset > bufferSize,
"Index buffer offset (%u) is larger than the size (%u) of %s.",
offset, bufferSize, buffer);
uint64_t remainingSize = bufferSize - offset;
// Temporarily treat 0 as undefined for size, and give a warning
@ -244,9 +241,11 @@ namespace dawn_native {
if (size == wgpu::kWholeSize) {
size = remainingSize;
} else {
if (size > remainingSize) {
return DAWN_VALIDATION_ERROR("Size + offset larger than the buffer size");
}
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 {
if (size == wgpu::kWholeSize) {
@ -279,18 +278,18 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateObject(buffer));
DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Vertex));
if (slot >= kMaxVertexBuffers) {
return DAWN_VALIDATION_ERROR("Vertex buffer slot out of bounds");
}
DAWN_INVALID_IF(slot >= kMaxVertexBuffers,
"Vertex buffer slot (%u) is larger the maximum (%u)", slot,
kMaxVertexBuffers - 1);
if (offset % 4 != 0) {
return DAWN_VALIDATION_ERROR("Offset must be a multiple of 4");
}
DAWN_INVALID_IF(offset % 4 != 0, "Vertex buffer offset (%u) is not a multiple of 4",
offset);
uint64_t bufferSize = buffer->GetSize();
if (offset > bufferSize) {
return DAWN_VALIDATION_ERROR("Offset larger than the buffer size");
}
DAWN_INVALID_IF(offset > bufferSize,
"Vertex buffer offset (%u) is larger than the size (%u) of %s.",
offset, bufferSize, buffer);
uint64_t remainingSize = bufferSize - offset;
// Temporarily treat 0 as undefined for size, and give a warning
@ -306,9 +305,11 @@ namespace dawn_native {
if (size == wgpu::kWholeSize) {
size = remainingSize;
} else {
if (size > remainingSize) {
return DAWN_VALIDATION_ERROR("Size + offset larger than the buffer size");
}
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 {
if (size == wgpu::kWholeSize) {

View File

@ -36,10 +36,9 @@ namespace dawn_native {
uint32_t queryIndex,
const QueryAvailabilityMap& queryAvailabilityMap) {
auto it = queryAvailabilityMap.find(querySet);
if (it != queryAvailabilityMap.end() && it->second[queryIndex]) {
return DAWN_VALIDATION_ERROR(
"The same query cannot be written twice in same render pass.");
}
DAWN_INVALID_IF(it != queryAvailabilityMap.end() && it->second[queryIndex],
"Query index %u of %s is written to twice in a render pass.",
queryIndex, querySet);
return {};
}
@ -97,10 +96,11 @@ namespace dawn_native {
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_TRY(ValidateProgrammableEncoderEnd());
if (mOcclusionQueryActive) {
return DAWN_VALIDATION_ERROR(
"The occlusion query must be ended before endPass.");
}
DAWN_INVALID_IF(
mOcclusionQueryActive,
"Render pass %s ended with incomplete occlusion query index %u of %s.",
this, mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
}
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
@ -140,25 +140,30 @@ namespace dawn_native {
float maxDepth) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
if ((isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) ||
isnan(maxDepth))) {
return DAWN_VALIDATION_ERROR("NaN is not allowed.");
}
DAWN_INVALID_IF((isnan(x) || isnan(y) || isnan(width) || isnan(height) ||
isnan(minDepth) || 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);
if (x < 0 || y < 0 || width < 0 || height < 0) {
return DAWN_VALIDATION_ERROR("X, Y, width and height must be non-negative.");
}
DAWN_INVALID_IF(
x < 0 || y < 0 || width < 0 || height < 0,
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) contains a negative "
"value.",
x, y, width, height);
if (x + width > mRenderTargetWidth || y + height > mRenderTargetHeight) {
return DAWN_VALIDATION_ERROR(
"The viewport must be contained in the render targets");
}
DAWN_INVALID_IF(
x + width > mRenderTargetWidth || y + height > mRenderTargetHeight,
"Viewport bounds (x: %f, y: %f, width: %f, height: %f) are not contained in "
"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.
if (minDepth < 0 || minDepth > maxDepth || maxDepth > 1) {
return DAWN_VALIDATION_ERROR(
"minDepth and maxDepth must be in [0, 1] and minDepth <= maxDepth.");
}
DAWN_INVALID_IF(
minDepth < 0 || minDepth > maxDepth || maxDepth > 1,
"Viewport minDepth (%f) and maxDepth (%f) are not in [0, 1] or minDepth was "
"greater than maxDepth.",
minDepth, maxDepth);
}
SetViewportCmd* cmd = allocator->Allocate<SetViewportCmd>(Command::SetViewport);
@ -179,11 +184,12 @@ namespace dawn_native {
uint32_t height) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
if (width > mRenderTargetWidth || height > mRenderTargetHeight ||
x > mRenderTargetWidth - width || y > mRenderTargetHeight - height) {
return DAWN_VALIDATION_ERROR(
"The scissor rect must be contained in the render targets");
}
DAWN_INVALID_IF(
width > mRenderTargetWidth || height > mRenderTargetHeight ||
x > mRenderTargetWidth - width || y > mRenderTargetHeight - height,
"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 =
@ -204,11 +210,12 @@ namespace dawn_native {
for (uint32_t i = 0; i < count; ++i) {
DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
if (GetAttachmentState() != renderBundles[i]->GetAttachmentState()) {
return DAWN_VALIDATION_ERROR(
"Render bundle attachment state is not compatible with render pass "
"attachment state");
}
// 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);
}
}
@ -244,25 +251,25 @@ namespace dawn_native {
void RenderPassEncoder::APIBeginOcclusionQuery(uint32_t queryIndex) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
if (mOcclusionQuerySet.Get() == nullptr) {
return DAWN_VALIDATION_ERROR(
"The occlusionQuerySet in RenderPassDescriptor must be set.");
}
DAWN_INVALID_IF(mOcclusionQuerySet.Get() == nullptr,
"The occlusionQuerySet in RenderPassDescriptor is not set.");
// The type of querySet has been validated by ValidateRenderPassDescriptor
if (queryIndex >= mOcclusionQuerySet->GetQueryCount()) {
return DAWN_VALIDATION_ERROR(
"Query index exceeds the number of queries in query set.");
}
DAWN_INVALID_IF(queryIndex >= mOcclusionQuerySet->GetQueryCount(),
"Query index (%u) exceeds the number of queries (%u) in %s.",
queryIndex, mOcclusionQuerySet->GetQueryCount(),
mOcclusionQuerySet.Get());
if (mOcclusionQueryActive) {
return DAWN_VALIDATION_ERROR(
"Only a single occlusion query can be begun at a time.");
}
DAWN_INVALID_IF(mOcclusionQueryActive,
"An occlusion query (%u) in %s is already active.",
mCurrentOcclusionQueryIndex, mOcclusionQuerySet.Get());
DAWN_TRY(ValidateQueryIndexOverwrite(mOcclusionQuerySet.Get(), queryIndex,
mUsageTracker.GetQueryAvailabilityMap()));
DAWN_TRY_CONTEXT(
ValidateQueryIndexOverwrite(mOcclusionQuerySet.Get(), queryIndex,
mUsageTracker.GetQueryAvailabilityMap()),
"validating the occlusion query index (%u) in %s", queryIndex,
mOcclusionQuerySet.Get());
}
// Record the current query index for endOcclusionQuery.
@ -281,11 +288,7 @@ namespace dawn_native {
void RenderPassEncoder::APIEndOcclusionQuery() {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
if (!mOcclusionQueryActive) {
return DAWN_VALIDATION_ERROR(
"EndOcclusionQuery cannot be called without corresponding "
"BeginOcclusionQuery.");
}
DAWN_INVALID_IF(!mOcclusionQueryActive, "No occlusion queries are active.");
}
TrackQueryAvailability(mOcclusionQuerySet.Get(), mCurrentOcclusionQueryIndex);
@ -306,8 +309,10 @@ namespace dawn_native {
if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
DAWN_TRY(ValidateQueryIndexOverwrite(querySet, queryIndex,
mUsageTracker.GetQueryAvailabilityMap()));
DAWN_TRY_CONTEXT(ValidateQueryIndexOverwrite(
querySet, queryIndex, mUsageTracker.GetQueryAvailabilityMap()),
"validating the timestamp query index (%u) of %s", queryIndex,
querySet);
}
TrackQueryAvailability(querySet, queryIndex);