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:
parent
57fcd17625
commit
05045e0ad8
|
@ -904,73 +904,6 @@ namespace dawn_native {
|
|||
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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,235 +27,6 @@
|
|||
|
||||
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
|
||||
// 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.
|
||||
|
|
|
@ -29,10 +29,6 @@ namespace dawn_native {
|
|||
struct PassResourceUsage;
|
||||
struct TexelBlockInfo;
|
||||
|
||||
MaybeError ValidateRenderBundle(CommandIterator* commands);
|
||||
MaybeError ValidateRenderPass(CommandIterator* commands, const BeginRenderPassCmd* renderPass);
|
||||
MaybeError ValidateComputePass(CommandIterator* commands);
|
||||
|
||||
MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
|
||||
|
||||
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
|
||||
|
|
|
@ -61,6 +61,10 @@ namespace dawn_native {
|
|||
|
||||
void ComputePassEncoder::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
||||
}
|
||||
|
||||
DispatchCmd* dispatch = allocator->Allocate<DispatchCmd>(Command::Dispatch);
|
||||
dispatch->x = x;
|
||||
dispatch->y = y;
|
||||
|
@ -75,6 +79,7 @@ namespace dawn_native {
|
|||
if (IsValidationEnabled()) {
|
||||
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
|
||||
// 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));
|
||||
}
|
||||
|
||||
mCommandBufferState.SetComputePipeline(pipeline);
|
||||
|
||||
SetComputePipelineCmd* cmd =
|
||||
allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
||||
cmd->pipeline = pipeline;
|
||||
|
|
|
@ -211,6 +211,8 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
mCommandBufferState.SetBindGroup(groupIndex, group);
|
||||
|
||||
SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
|
||||
cmd->index = groupIndex;
|
||||
cmd->group = group;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_
|
||||
#define DAWNNATIVE_PROGRAMMABLEPASSENCODER_H_
|
||||
|
||||
#include "dawn_native/CommandBufferStateTracker.h"
|
||||
#include "dawn_native/CommandEncoder.h"
|
||||
#include "dawn_native/Error.h"
|
||||
#include "dawn_native/ObjectBase.h"
|
||||
|
@ -57,6 +58,7 @@ namespace dawn_native {
|
|||
PassResourceUsageTracker mUsageTracker;
|
||||
|
||||
uint64_t mDebugGroupStackSize = 0;
|
||||
CommandBufferStateTracker mCommandBufferState;
|
||||
|
||||
private:
|
||||
const bool mValidationEnabled;
|
||||
|
|
|
@ -131,7 +131,6 @@ namespace dawn_native {
|
|||
TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "RenderBundleEncoder::ValidateFinish");
|
||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||
DAWN_TRY(ValidatePassResourceUsage(usages));
|
||||
DAWN_TRY(ValidateRenderBundle(commands));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace dawn_native {
|
|||
uint32_t firstInstance) {
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(mCommandBufferState.ValidateCanDraw());
|
||||
|
||||
if (mDisableBaseInstance && firstInstance != 0) {
|
||||
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
|
||||
}
|
||||
|
@ -83,6 +85,8 @@ namespace dawn_native {
|
|||
uint32_t firstInstance) {
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
||||
|
||||
if (mDisableBaseInstance && firstInstance != 0) {
|
||||
return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
|
||||
}
|
||||
|
@ -107,6 +111,7 @@ namespace dawn_native {
|
|||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||
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");
|
||||
|
@ -134,6 +139,7 @@ namespace dawn_native {
|
|||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||
DAWN_TRY(ValidateCanUseAs(indirectBuffer, wgpu::BufferUsage::Indirect));
|
||||
DAWN_TRY(mCommandBufferState.ValidateCanDrawIndexed());
|
||||
|
||||
// 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
|
||||
|
@ -178,6 +184,8 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
mCommandBufferState.SetRenderPipeline(pipeline);
|
||||
|
||||
SetRenderPipelineCmd* cmd =
|
||||
allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
|
||||
cmd->pipeline = pipeline;
|
||||
|
@ -227,6 +235,8 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
mCommandBufferState.SetIndexBuffer(format);
|
||||
|
||||
SetIndexBufferCmd* cmd =
|
||||
allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
||||
cmd->buffer = buffer;
|
||||
|
@ -272,6 +282,8 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
mCommandBufferState.SetVertexBuffer(VertexBufferSlot(uint8_t(slot)));
|
||||
|
||||
SetVertexBufferCmd* cmd =
|
||||
allocator->Allocate<SetVertexBufferCmd>(Command::SetVertexBuffer);
|
||||
cmd->slot = VertexBufferSlot(static_cast<uint8_t>(slot));
|
||||
|
|
|
@ -208,6 +208,8 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
mCommandBufferState = CommandBufferStateTracker{};
|
||||
|
||||
ExecuteBundlesCmd* cmd =
|
||||
allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
|
||||
cmd->count = count;
|
||||
|
|
Loading…
Reference in New Issue