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/CommandBufferStateTracker.h",
|
||||||
"src/dawn_native/CommandEncoder.cpp",
|
"src/dawn_native/CommandEncoder.cpp",
|
||||||
"src/dawn_native/CommandEncoder.h",
|
"src/dawn_native/CommandEncoder.h",
|
||||||
|
"src/dawn_native/CommandValidation.cpp",
|
||||||
|
"src/dawn_native/CommandValidation.h",
|
||||||
"src/dawn_native/Commands.cpp",
|
"src/dawn_native/Commands.cpp",
|
||||||
"src/dawn_native/Commands.h",
|
"src/dawn_native/Commands.h",
|
||||||
"src/dawn_native/ComputePassEncoder.cpp",
|
"src/dawn_native/ComputePassEncoder.cpp",
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "dawn_native/Buffer.h"
|
#include "dawn_native/Buffer.h"
|
||||||
#include "dawn_native/CommandBuffer.h"
|
#include "dawn_native/CommandBuffer.h"
|
||||||
#include "dawn_native/CommandBufferStateTracker.h"
|
#include "dawn_native/CommandBufferStateTracker.h"
|
||||||
|
#include "dawn_native/CommandValidation.h"
|
||||||
#include "dawn_native/Commands.h"
|
#include "dawn_native/Commands.h"
|
||||||
#include "dawn_native/ComputePassEncoder.h"
|
#include "dawn_native/ComputePassEncoder.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
|
@ -121,29 +122,6 @@ namespace dawn_native {
|
||||||
return {};
|
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) {
|
MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
|
||||||
if (texture->GetSampleCount() > 1) {
|
if (texture->GetSampleCount() > 1) {
|
||||||
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
|
||||||
|
@ -476,39 +454,6 @@ namespace dawn_native {
|
||||||
return {};
|
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
|
} // namespace
|
||||||
|
|
||||||
CommandEncoderBase::CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor*)
|
CommandEncoderBase::CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor*)
|
||||||
|
@ -749,12 +694,12 @@ namespace dawn_native {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
commands->NextCommand<BeginComputePassCmd>();
|
commands->NextCommand<BeginComputePassCmd>();
|
||||||
DAWN_TRY(ValidateComputePass(commands));
|
DAWN_TRY(ValidateComputePass(commands, &mResourceUsages.perPass));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
|
BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
|
||||||
DAWN_TRY(ValidateRenderPass(commands, cmd));
|
DAWN_TRY(ValidateRenderPass(commands, cmd, &mResourceUsages.perPass));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::CopyBufferToBuffer: {
|
case Command::CopyBufferToBuffer: {
|
||||||
|
@ -881,211 +826,4 @@ namespace dawn_native {
|
||||||
return {};
|
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
|
} // namespace dawn_native
|
||||||
|
|
|
@ -56,15 +56,11 @@ namespace dawn_native {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor);
|
MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor);
|
||||||
MaybeError ValidateComputePass(CommandIterator* commands);
|
|
||||||
MaybeError ValidateRenderPass(CommandIterator* commands, BeginRenderPassCmd* renderPass);
|
|
||||||
|
|
||||||
EncodingContext mEncodingContext;
|
EncodingContext mEncodingContext;
|
||||||
|
|
||||||
bool mWereResourceUsagesAcquired = false;
|
bool mWereResourceUsagesAcquired = false;
|
||||||
CommandBufferResourceUsage mResourceUsages;
|
CommandBufferResourceUsage mResourceUsages;
|
||||||
|
|
||||||
unsigned int mDebugGroupStackSize = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // 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();
|
return mAttachmentState->GetSampleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError RenderPipelineBase::ValidateCompatibleWith(
|
const AttachmentState* RenderPipelineBase::GetAttachmentState() const {
|
||||||
const BeginRenderPassCmd* renderPass) const {
|
|
||||||
ASSERT(!IsError());
|
ASSERT(!IsError());
|
||||||
|
|
||||||
if (renderPass->attachmentState.Get() != mAttachmentState.Get()) {
|
return mAttachmentState.Get();
|
||||||
return DAWN_VALIDATION_ERROR(
|
|
||||||
"Pipeline attachment state is not compatible with render pass");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::bitset<kMaxVertexAttributes> RenderPipelineBase::GetAttributesUsingInput(
|
std::bitset<kMaxVertexAttributes> RenderPipelineBase::GetAttributesUsingInput(
|
||||||
|
|
|
@ -78,9 +78,8 @@ namespace dawn_native {
|
||||||
dawn::TextureFormat GetDepthStencilFormat() const;
|
dawn::TextureFormat GetDepthStencilFormat() const;
|
||||||
uint32_t GetSampleCount() const;
|
uint32_t GetSampleCount() const;
|
||||||
|
|
||||||
// A pipeline can be used in a render pass if its attachment info matches the actual
|
const AttachmentState* GetAttachmentState() const;
|
||||||
// attachments in the render pass. This returns whether it is the case.
|
|
||||||
MaybeError ValidateCompatibleWith(const BeginRenderPassCmd* renderPassCmd) const;
|
|
||||||
std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const;
|
std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const;
|
||||||
std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexBuffers> attributesUsingInput;
|
std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexBuffers> attributesUsingInput;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue