Factor RenderPass command validation
Validation of GPURenderBundle will share code with RenderPass validation. Factor validation of commands for GPURenderBundle into a separate function. Bug: dawn:154 Change-Id: I79a229592ead27d462da0dd2d12fbdb95443ff19 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9980 Commit-Queue: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
9b45b5aafa
commit
3318caaa51
2
BUILD.gn
2
BUILD.gn
|
@ -124,6 +124,8 @@ source_set("libdawn_native_sources") {
|
|||
"src/dawn_native/CommandBufferStateTracker.h",
|
||||
"src/dawn_native/CommandEncoder.cpp",
|
||||
"src/dawn_native/CommandEncoder.h",
|
||||
"src/dawn_native/CommandValidation.cpp",
|
||||
"src/dawn_native/CommandValidation.h",
|
||||
"src/dawn_native/Commands.cpp",
|
||||
"src/dawn_native/Commands.h",
|
||||
"src/dawn_native/ComputePassEncoder.cpp",
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "dawn_native/Buffer.h"
|
||||
#include "dawn_native/CommandBuffer.h"
|
||||
#include "dawn_native/CommandBufferStateTracker.h"
|
||||
#include "dawn_native/CommandValidation.h"
|
||||
#include "dawn_native/Commands.h"
|
||||
#include "dawn_native/ComputePassEncoder.h"
|
||||
#include "dawn_native/Device.h"
|
||||
|
@ -121,29 +122,6 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
inline MaybeError PushDebugMarkerStack(unsigned int* counter) {
|
||||
*counter += 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline MaybeError PopDebugMarkerStack(unsigned int* counter) {
|
||||
if (*counter == 0) {
|
||||
return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push.");
|
||||
} else {
|
||||
*counter -= 1;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
inline MaybeError ValidateDebugGroups(const unsigned int counter) {
|
||||
if (counter != 0) {
|
||||
return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
|
||||
if (texture->GetSampleCount() > 1) {
|
||||
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
||||
|
@ -476,39 +454,6 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
void TrackBindGroupResourceUsage(BindGroupBase* group, PassResourceUsageTracker* tracker) {
|
||||
const auto& layoutInfo = group->GetLayout()->GetBindingInfo();
|
||||
|
||||
for (uint32_t i : IterateBitSet(layoutInfo.mask)) {
|
||||
dawn::BindingType type = layoutInfo.types[i];
|
||||
|
||||
switch (type) {
|
||||
case dawn::BindingType::UniformBuffer: {
|
||||
BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
|
||||
tracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Uniform);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::StorageBuffer: {
|
||||
BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
|
||||
tracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Storage);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::SampledTexture: {
|
||||
TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture();
|
||||
tracker->TextureUsedAs(texture, dawn::TextureUsageBit::Sampled);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::Sampler:
|
||||
break;
|
||||
|
||||
case dawn::BindingType::StorageTexture:
|
||||
case dawn::BindingType::ReadonlyStorageBuffer:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CommandEncoderBase::CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor*)
|
||||
|
@ -749,12 +694,12 @@ namespace dawn_native {
|
|||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
commands->NextCommand<BeginComputePassCmd>();
|
||||
DAWN_TRY(ValidateComputePass(commands));
|
||||
DAWN_TRY(ValidateComputePass(commands, &mResourceUsages.perPass));
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
|
||||
DAWN_TRY(ValidateRenderPass(commands, cmd));
|
||||
DAWN_TRY(ValidateRenderPass(commands, cmd, &mResourceUsages.perPass));
|
||||
} break;
|
||||
|
||||
case Command::CopyBufferToBuffer: {
|
||||
|
@ -881,211 +826,4 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateComputePass(CommandIterator* commands) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker persistentState;
|
||||
|
||||
Command type;
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndComputePass: {
|
||||
commands->NextCommand<EndComputePassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateComputePassUsages());
|
||||
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
|
||||
return {};
|
||||
} break;
|
||||
|
||||
case Command::Dispatch: {
|
||||
commands->NextCommand<DispatchCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDispatch());
|
||||
} break;
|
||||
|
||||
case Command::DispatchIndirect: {
|
||||
DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDispatch());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipelineBase* pipeline = cmd->pipeline.Get();
|
||||
persistentState.SetComputePipeline(pipeline);
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
||||
if (cmd->dynamicOffsetCount > 0) {
|
||||
commands->NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
|
||||
persistentState.SetBindGroup(cmd->index, cmd->group.Get());
|
||||
} break;
|
||||
|
||||
default:
|
||||
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return DAWN_VALIDATION_ERROR("Unfinished compute pass");
|
||||
}
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateRenderPass(CommandIterator* commands,
|
||||
BeginRenderPassCmd* renderPass) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker persistentState;
|
||||
|
||||
// Track usage of the render pass attachments
|
||||
for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
||||
RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i];
|
||||
TextureBase* texture = colorAttachment->view->GetTexture();
|
||||
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
|
||||
|
||||
TextureViewBase* resolveTarget = colorAttachment->resolveTarget.Get();
|
||||
if (resolveTarget != nullptr) {
|
||||
usageTracker.TextureUsedAs(resolveTarget->GetTexture(),
|
||||
dawn::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
}
|
||||
|
||||
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
||||
TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture();
|
||||
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
|
||||
Command type;
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndRenderPass: {
|
||||
commands->NextCommand<EndRenderPassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateRenderPassUsages());
|
||||
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
|
||||
return {};
|
||||
} break;
|
||||
|
||||
case Command::Draw: {
|
||||
commands->NextCommand<DrawCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDraw());
|
||||
} break;
|
||||
|
||||
case Command::DrawIndexed: {
|
||||
commands->NextCommand<DrawIndexedCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDrawIndexed());
|
||||
} break;
|
||||
|
||||
case Command::DrawIndirect: {
|
||||
DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDraw());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::DrawIndexedIndirect: {
|
||||
DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDrawIndexed());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::SetRenderPipeline: {
|
||||
SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>();
|
||||
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
||||
|
||||
DAWN_TRY(pipeline->ValidateCompatibleWith(renderPass));
|
||||
persistentState.SetRenderPipeline(pipeline);
|
||||
} 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::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
||||
if (cmd->dynamicOffsetCount > 0) {
|
||||
commands->NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
|
||||
persistentState.SetBindGroup(cmd->index, cmd->group.Get());
|
||||
} break;
|
||||
|
||||
case Command::SetIndexBuffer: {
|
||||
SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
|
||||
|
||||
usageTracker.BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsageBit::Index);
|
||||
persistentState.SetIndexBuffer();
|
||||
} break;
|
||||
|
||||
case Command::SetVertexBuffers: {
|
||||
SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>();
|
||||
auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count);
|
||||
commands->NextData<uint64_t>(cmd->count);
|
||||
|
||||
for (uint32_t i = 0; i < cmd->count; ++i) {
|
||||
usageTracker.BufferUsedAs(buffers[i].Get(), dawn::BufferUsageBit::Vertex);
|
||||
}
|
||||
persistentState.SetVertexBuffer(cmd->startSlot, cmd->count);
|
||||
} break;
|
||||
|
||||
default:
|
||||
return DAWN_VALIDATION_ERROR("Command disallowed inside a render pass");
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return DAWN_VALIDATION_ERROR("Unfinished render pass");
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -56,15 +56,11 @@ namespace dawn_native {
|
|||
|
||||
private:
|
||||
MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor);
|
||||
MaybeError ValidateComputePass(CommandIterator* commands);
|
||||
MaybeError ValidateRenderPass(CommandIterator* commands, BeginRenderPassCmd* renderPass);
|
||||
|
||||
EncodingContext mEncodingContext;
|
||||
|
||||
bool mWereResourceUsagesAcquired = false;
|
||||
CommandBufferResourceUsage mResourceUsages;
|
||||
|
||||
unsigned int mDebugGroupStackSize = 0;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "dawn_native/CommandValidation.h"
|
||||
|
||||
#include "common/BitSetIterator.h"
|
||||
#include "dawn_native/BindGroup.h"
|
||||
#include "dawn_native/CommandBufferStateTracker.h"
|
||||
#include "dawn_native/Commands.h"
|
||||
#include "dawn_native/PassResourceUsageTracker.h"
|
||||
#include "dawn_native/RenderPipeline.h"
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
namespace {
|
||||
|
||||
inline MaybeError PushDebugMarkerStack(unsigned int* counter) {
|
||||
*counter += 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
inline MaybeError PopDebugMarkerStack(unsigned int* counter) {
|
||||
if (*counter == 0) {
|
||||
return DAWN_VALIDATION_ERROR("Pop must be balanced by a corresponding Push.");
|
||||
} else {
|
||||
*counter -= 1;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
inline MaybeError ValidateDebugGroups(const unsigned int counter) {
|
||||
if (counter != 0) {
|
||||
return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void TrackBindGroupResourceUsage(BindGroupBase* group,
|
||||
PassResourceUsageTracker* usageTracker) {
|
||||
const auto& layoutInfo = group->GetLayout()->GetBindingInfo();
|
||||
|
||||
for (uint32_t i : IterateBitSet(layoutInfo.mask)) {
|
||||
dawn::BindingType type = layoutInfo.types[i];
|
||||
|
||||
switch (type) {
|
||||
case dawn::BindingType::UniformBuffer: {
|
||||
BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
|
||||
usageTracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Uniform);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::StorageBuffer: {
|
||||
BufferBase* buffer = group->GetBindingAsBufferBinding(i).buffer;
|
||||
usageTracker->BufferUsedAs(buffer, dawn::BufferUsageBit::Storage);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::SampledTexture: {
|
||||
TextureBase* texture = group->GetBindingAsTextureView(i)->GetTexture();
|
||||
usageTracker->TextureUsedAs(texture, dawn::TextureUsageBit::Sampled);
|
||||
} break;
|
||||
|
||||
case dawn::BindingType::Sampler:
|
||||
break;
|
||||
|
||||
case dawn::BindingType::StorageTexture:
|
||||
case dawn::BindingType::ReadonlyStorageBuffer:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline MaybeError ValidateRenderBundleCommand(CommandIterator* commands,
|
||||
Command type,
|
||||
PassResourceUsageTracker* usageTracker,
|
||||
CommandBufferStateTracker* commandBufferState,
|
||||
const AttachmentState* attachmentState,
|
||||
unsigned int* debugGroupStackSize,
|
||||
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: {
|
||||
DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>();
|
||||
DAWN_TRY(commandBufferState->ValidateCanDraw());
|
||||
usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::DrawIndexedIndirect: {
|
||||
DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>();
|
||||
DAWN_TRY(commandBufferState->ValidateCanDrawIndexed());
|
||||
usageTracker->BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(debugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(debugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::SetRenderPipeline: {
|
||||
SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>();
|
||||
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
||||
|
||||
if (DAWN_UNLIKELY(pipeline->GetAttachmentState() != attachmentState)) {
|
||||
return DAWN_VALIDATION_ERROR("Pipeline attachment state is not compatible");
|
||||
}
|
||||
commandBufferState->SetRenderPipeline(pipeline);
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
||||
if (cmd->dynamicOffsetCount > 0) {
|
||||
commands->NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), usageTracker);
|
||||
commandBufferState->SetBindGroup(cmd->index, cmd->group.Get());
|
||||
} break;
|
||||
|
||||
case Command::SetIndexBuffer: {
|
||||
SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
|
||||
|
||||
usageTracker->BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsageBit::Index);
|
||||
commandBufferState->SetIndexBuffer();
|
||||
} break;
|
||||
|
||||
case Command::SetVertexBuffers: {
|
||||
SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>();
|
||||
auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count);
|
||||
commands->NextData<uint64_t>(cmd->count);
|
||||
|
||||
for (uint32_t i = 0; i < cmd->count; ++i) {
|
||||
usageTracker->BufferUsedAs(buffers[i].Get(), dawn::BufferUsageBit::Vertex);
|
||||
}
|
||||
commandBufferState->SetVertexBuffer(cmd->startSlot, cmd->count);
|
||||
} break;
|
||||
|
||||
default:
|
||||
return DAWN_VALIDATION_ERROR(disallowedMessage);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MaybeError ValidateRenderPass(CommandIterator* commands,
|
||||
BeginRenderPassCmd* renderPass,
|
||||
std::vector<PassResourceUsage>* perPassResourceUsages) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker commandBufferState;
|
||||
unsigned int debugGroupStackSize = 0;
|
||||
|
||||
// Track usage of the render pass attachments
|
||||
for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
||||
RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i];
|
||||
TextureBase* texture = colorAttachment->view->GetTexture();
|
||||
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
|
||||
|
||||
TextureViewBase* resolveTarget = colorAttachment->resolveTarget.Get();
|
||||
if (resolveTarget != nullptr) {
|
||||
usageTracker.TextureUsedAs(resolveTarget->GetTexture(),
|
||||
dawn::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
}
|
||||
|
||||
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
||||
TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture();
|
||||
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
|
||||
Command type;
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndRenderPass: {
|
||||
commands->NextCommand<EndRenderPassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(debugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateRenderPassUsages());
|
||||
ASSERT(perPassResourceUsages != nullptr);
|
||||
perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage());
|
||||
|
||||
return {};
|
||||
} 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;
|
||||
|
||||
default:
|
||||
DAWN_TRY(ValidateRenderBundleCommand(
|
||||
commands, type, &usageTracker, &commandBufferState,
|
||||
renderPass->attachmentState.Get(), &debugGroupStackSize,
|
||||
"Command disallowed inside a render pass"));
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return DAWN_VALIDATION_ERROR("Unfinished render pass");
|
||||
}
|
||||
|
||||
MaybeError ValidateComputePass(CommandIterator* commands,
|
||||
std::vector<PassResourceUsage>* perPassResourceUsages) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker commandBufferState;
|
||||
unsigned int debugGroupStackSize = 0;
|
||||
|
||||
Command type;
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndComputePass: {
|
||||
commands->NextCommand<EndComputePassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(debugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateComputePassUsages());
|
||||
ASSERT(perPassResourceUsages != nullptr);
|
||||
perPassResourceUsages->push_back(usageTracker.AcquireResourceUsage());
|
||||
return {};
|
||||
} break;
|
||||
|
||||
case Command::Dispatch: {
|
||||
commands->NextCommand<DispatchCmd>();
|
||||
DAWN_TRY(commandBufferState.ValidateCanDispatch());
|
||||
} break;
|
||||
|
||||
case Command::DispatchIndirect: {
|
||||
DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>();
|
||||
DAWN_TRY(commandBufferState.ValidateCanDispatch());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(&debugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(&debugGroupStackSize));
|
||||
} 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<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
|
||||
commandBufferState.SetBindGroup(cmd->index, cmd->group.Get());
|
||||
} break;
|
||||
|
||||
default:
|
||||
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return DAWN_VALIDATION_ERROR("Unfinished compute pass");
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef DAWNNATIVE_COMMANDVALIDATION_H_
|
||||
#define DAWNNATIVE_COMMANDVALIDATION_H_
|
||||
|
||||
#include "dawn_native/CommandAllocator.h"
|
||||
#include "dawn_native/Error.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
struct BeginRenderPassCmd;
|
||||
struct PassResourceUsage;
|
||||
|
||||
MaybeError ValidateRenderPass(CommandIterator* commands,
|
||||
BeginRenderPassCmd* renderPass,
|
||||
std::vector<PassResourceUsage>* perPassResourceUsages);
|
||||
MaybeError ValidateComputePass(CommandIterator* commands,
|
||||
std::vector<PassResourceUsage>* perPassResourceUsages);
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // DAWNNATIVE_COMMANDVALIDATION_H_
|
|
@ -514,16 +514,10 @@ namespace dawn_native {
|
|||
return mAttachmentState->GetSampleCount();
|
||||
}
|
||||
|
||||
MaybeError RenderPipelineBase::ValidateCompatibleWith(
|
||||
const BeginRenderPassCmd* renderPass) const {
|
||||
const AttachmentState* RenderPipelineBase::GetAttachmentState() const {
|
||||
ASSERT(!IsError());
|
||||
|
||||
if (renderPass->attachmentState.Get() != mAttachmentState.Get()) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Pipeline attachment state is not compatible with render pass");
|
||||
}
|
||||
|
||||
return {};
|
||||
return mAttachmentState.Get();
|
||||
}
|
||||
|
||||
std::bitset<kMaxVertexAttributes> RenderPipelineBase::GetAttributesUsingInput(
|
||||
|
|
|
@ -78,9 +78,8 @@ namespace dawn_native {
|
|||
dawn::TextureFormat GetDepthStencilFormat() const;
|
||||
uint32_t GetSampleCount() const;
|
||||
|
||||
// A pipeline can be used in a render pass if its attachment info matches the actual
|
||||
// attachments in the render pass. This returns whether it is the case.
|
||||
MaybeError ValidateCompatibleWith(const BeginRenderPassCmd* renderPassCmd) const;
|
||||
const AttachmentState* GetAttachmentState() const;
|
||||
|
||||
std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const;
|
||||
std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexBuffers> attributesUsingInput;
|
||||
|
||||
|
|
Loading…
Reference in New Issue