dawn_native: Do CommandBufferStateTracker validation at encoding time

This is the last piece of validation that was done in a separate
validation pass so the validation pass is removed.

Bug: dawn:635
Change-Id: I91ce5d5a512ac188f3dd56c90db9e69aee518844
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38845
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2021-01-28 14:44:15 +00:00 committed by Commit Bot service account
parent 57fcd17625
commit 05045e0ad8
9 changed files with 25 additions and 301 deletions

View File

@ -904,73 +904,6 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop."); return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
} }
commands->Reset();
Command type;
while (commands->NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
commands->NextCommand<BeginComputePassCmd>();
DAWN_TRY(ValidateComputePass(commands));
break;
}
case Command::BeginRenderPass: {
const BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
DAWN_TRY(ValidateRenderPass(commands, cmd));
break;
}
case Command::CopyBufferToBuffer: {
commands->NextCommand<CopyBufferToBufferCmd>();
break;
}
case Command::CopyBufferToTexture: {
commands->NextCommand<CopyBufferToTextureCmd>();
break;
}
case Command::CopyTextureToBuffer: {
commands->NextCommand<CopyTextureToBufferCmd>();
break;
}
case Command::CopyTextureToTexture: {
commands->NextCommand<CopyTextureToTextureCmd>();
break;
}
case Command::InsertDebugMarker: {
const InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::PopDebugGroup: {
commands->NextCommand<PopDebugGroupCmd>();
break;
}
case Command::PushDebugGroup: {
const PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::ResolveQuerySet: {
commands->NextCommand<ResolveQuerySetCmd>();
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
return DAWN_VALIDATION_ERROR("Command disallowed outside of a pass");
}
}
return {}; return {};
} }

View File

@ -27,235 +27,6 @@
namespace dawn_native { namespace dawn_native {
namespace {
inline MaybeError ValidateRenderBundleCommand(CommandIterator* commands,
Command type,
CommandBufferStateTracker* commandBufferState,
const char* disallowedMessage) {
switch (type) {
case Command::Draw: {
commands->NextCommand<DrawCmd>();
DAWN_TRY(commandBufferState->ValidateCanDraw());
break;
}
case Command::DrawIndexed: {
commands->NextCommand<DrawIndexedCmd>();
DAWN_TRY(commandBufferState->ValidateCanDrawIndexed());
break;
}
case Command::DrawIndirect: {
commands->NextCommand<DrawIndirectCmd>();
DAWN_TRY(commandBufferState->ValidateCanDraw());
break;
}
case Command::DrawIndexedIndirect: {
commands->NextCommand<DrawIndexedIndirectCmd>();
DAWN_TRY(commandBufferState->ValidateCanDrawIndexed());
break;
}
case Command::InsertDebugMarker: {
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::PopDebugGroup: {
commands->NextCommand<PopDebugGroupCmd>();
break;
}
case Command::PushDebugGroup: {
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::SetRenderPipeline: {
SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>();
RenderPipelineBase* pipeline = cmd->pipeline.Get();
commandBufferState->SetRenderPipeline(pipeline);
break;
}
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
if (cmd->dynamicOffsetCount > 0) {
commands->NextData<uint32_t>(cmd->dynamicOffsetCount);
}
commandBufferState->SetBindGroup(cmd->index, cmd->group.Get());
break;
}
case Command::SetIndexBuffer: {
SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
commandBufferState->SetIndexBuffer(cmd->format);
break;
}
case Command::SetVertexBuffer: {
SetVertexBufferCmd* cmd = commands->NextCommand<SetVertexBufferCmd>();
commandBufferState->SetVertexBuffer(cmd->slot);
break;
}
default:
return DAWN_VALIDATION_ERROR(disallowedMessage);
}
return {};
}
} // namespace
MaybeError ValidateRenderBundle(CommandIterator* commands) {
CommandBufferStateTracker commandBufferState;
Command type;
while (commands->NextCommandId(&type)) {
DAWN_TRY(ValidateRenderBundleCommand(commands, type, &commandBufferState,
"Command disallowed inside a render bundle"));
}
return {};
}
MaybeError ValidateRenderPass(CommandIterator* commands, const BeginRenderPassCmd* renderPass) {
CommandBufferStateTracker commandBufferState;
Command type;
while (commands->NextCommandId(&type)) {
switch (type) {
case Command::BeginOcclusionQuery: {
commands->NextCommand<BeginOcclusionQueryCmd>();
break;
}
case Command::EndOcclusionQuery: {
commands->NextCommand<EndOcclusionQueryCmd>();
break;
}
case Command::EndRenderPass: {
commands->NextCommand<EndRenderPassCmd>();
return {};
}
case Command::ExecuteBundles: {
ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>();
commands->NextData<Ref<RenderBundleBase>>(cmd->count);
commandBufferState = CommandBufferStateTracker{};
break;
}
case Command::SetStencilReference: {
commands->NextCommand<SetStencilReferenceCmd>();
break;
}
case Command::SetBlendColor: {
commands->NextCommand<SetBlendColorCmd>();
break;
}
case Command::SetViewport: {
commands->NextCommand<SetViewportCmd>();
break;
}
case Command::SetScissorRect: {
commands->NextCommand<SetScissorRectCmd>();
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
DAWN_TRY(
ValidateRenderBundleCommand(commands, type, &commandBufferState,
"Command disallowed inside a render pass"));
}
}
UNREACHABLE();
return DAWN_VALIDATION_ERROR("Unfinished render pass");
}
MaybeError ValidateComputePass(CommandIterator* commands) {
CommandBufferStateTracker commandBufferState;
Command type;
while (commands->NextCommandId(&type)) {
switch (type) {
case Command::EndComputePass: {
commands->NextCommand<EndComputePassCmd>();
return {};
}
case Command::Dispatch: {
commands->NextCommand<DispatchCmd>();
DAWN_TRY(commandBufferState.ValidateCanDispatch());
break;
}
case Command::DispatchIndirect: {
commands->NextCommand<DispatchIndirectCmd>();
DAWN_TRY(commandBufferState.ValidateCanDispatch());
break;
}
case Command::InsertDebugMarker: {
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::PopDebugGroup: {
commands->NextCommand<PopDebugGroupCmd>();
break;
}
case Command::PushDebugGroup: {
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
commands->NextData<char>(cmd->length + 1);
break;
}
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get();
commandBufferState.SetComputePipeline(pipeline);
break;
}
case Command::SetBindGroup: {
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
if (cmd->dynamicOffsetCount > 0) {
commands->NextData<uint32_t>(cmd->dynamicOffsetCount);
}
commandBufferState.SetBindGroup(cmd->index, cmd->group.Get());
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
}
}
UNREACHABLE();
return DAWN_VALIDATION_ERROR("Unfinished compute pass");
}
// Performs the per-pass usage validation checks // Performs the per-pass usage validation checks
// This will eventually need to differentiate between render and compute passes. // This will eventually need to differentiate between render and compute passes.
// It will be valid to use a buffer both as uniform and storage in the same compute pass. // It will be valid to use a buffer both as uniform and storage in the same compute pass.

View File

@ -29,10 +29,6 @@ namespace dawn_native {
struct PassResourceUsage; struct PassResourceUsage;
struct TexelBlockInfo; struct TexelBlockInfo;
MaybeError ValidateRenderBundle(CommandIterator* commands);
MaybeError ValidateRenderPass(CommandIterator* commands, const BeginRenderPassCmd* renderPass);
MaybeError ValidateComputePass(CommandIterator* commands);
MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage); MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex); MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);

View File

@ -61,6 +61,10 @@ namespace dawn_native {
void ComputePassEncoder::Dispatch(uint32_t x, uint32_t y, uint32_t z) { void ComputePassEncoder::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
}
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;
@ -75,6 +79,7 @@ namespace dawn_native {
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer)); DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect)); 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 is
@ -113,6 +118,8 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateObject(pipeline)); DAWN_TRY(GetDevice()->ValidateObject(pipeline));
} }
mCommandBufferState.SetComputePipeline(pipeline);
SetComputePipelineCmd* cmd = SetComputePipelineCmd* cmd =
allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline); allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
cmd->pipeline = pipeline; cmd->pipeline = pipeline;

View File

@ -211,6 +211,8 @@ namespace dawn_native {
} }
} }
mCommandBufferState.SetBindGroup(groupIndex, group);
SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup); SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
cmd->index = groupIndex; cmd->index = groupIndex;
cmd->group = group; cmd->group = group;

View File

@ -15,6 +15,7 @@
#ifndef DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_ #ifndef DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_
#define DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_ #define DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_
#include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/CommandEncoder.h" #include "dawn_native/CommandEncoder.h"
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
#include "dawn_native/ObjectBase.h" #include "dawn_native/ObjectBase.h"
@ -57,6 +58,7 @@ namespace dawn_native {
PassResourceUsageTracker mUsageTracker; PassResourceUsageTracker mUsageTracker;
uint64_t mDebugGroupStackSize = 0; uint64_t mDebugGroupStackSize = 0;
CommandBufferStateTracker mCommandBufferState;
private: private:
const bool mValidationEnabled; const bool mValidationEnabled;

View File

@ -131,7 +131,6 @@ namespace dawn_native {
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "RenderBundleEncoder::ValidateFinish"); TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "RenderBundleEncoder::ValidateFinish");
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_TRY(ValidatePassResourceUsage(usages)); DAWN_TRY(ValidatePassResourceUsage(usages));
DAWN_TRY(ValidateRenderBundle(commands));
return {}; return {};
} }

View File

@ -61,6 +61,8 @@ namespace dawn_native {
uint32_t firstInstance) { uint32_t firstInstance) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
if (mDisableBaseInstance && firstInstance != 0) { if (mDisableBaseInstance && firstInstance != 0) {
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported"); return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
} }
@ -83,6 +85,8 @@ namespace dawn_native {
uint32_t firstInstance) { uint32_t firstInstance) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError { mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
if (mDisableBaseInstance && firstInstance != 0) { if (mDisableBaseInstance && firstInstance != 0) {
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported"); return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
} }
@ -107,6 +111,7 @@ namespace dawn_native {
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer)); DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect)); DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
if (indirectOffset % 4 != 0) { if (indirectOffset % 4 != 0) {
return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4"); return DAWN_VALIDATION_ERROR("Indirect offset must be a multiple of 4");
@ -134,6 +139,7 @@ namespace dawn_native {
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer)); DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect)); DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
// Indexed indirect draws need a compute-shader based validation check that the // Indexed indirect draws need a compute-shader based validation check that the
// range of indices is contained inside the index buffer on Metal. Disallow them as // range of indices is contained inside the index buffer on Metal. Disallow them as
@ -178,6 +184,8 @@ namespace dawn_native {
} }
} }
mCommandBufferState.SetRenderPipeline(pipeline);
SetRenderPipelineCmd* cmd = SetRenderPipelineCmd* cmd =
allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline); allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
cmd->pipeline = pipeline; cmd->pipeline = pipeline;
@ -227,6 +235,8 @@ namespace dawn_native {
} }
} }
mCommandBufferState.SetIndexBuffer(format);
SetIndexBufferCmd* cmd = SetIndexBufferCmd* cmd =
allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer); allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
cmd->buffer = buffer; cmd->buffer = buffer;
@ -272,6 +282,8 @@ namespace dawn_native {
} }
} }
mCommandBufferState.SetVertexBuffer(VertexBufferSlot(uint8_t(slot)));
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));

View File

@ -208,6 +208,8 @@ namespace dawn_native {
} }
} }
mCommandBufferState = CommandBufferStateTracker{};
ExecuteBundlesCmd* cmd = ExecuteBundlesCmd* cmd =
allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles); allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
cmd->count = count; cmd->count = count;