CommandBufferBuilder::Validate: Iterate per pass
This changes the validation to have one iteration loop for the main buffer that calls to pass-specific iteration loops for compute passes and render passes. This is done to simplify code a bit and will help implement implicit transitions that are "precomputed" per pass in the command buffer validation and re-used in the backends. A number of code simplifications were made to CommandBufferStateTracker since it doesn't need to know if we are in a pass anymore. Further simplifications will happen when implicit barriers are implemented.
This commit is contained in:
parent
a884cb2479
commit
b3bd35ed88
|
@ -124,6 +124,8 @@ namespace backend {
|
|||
|
||||
} // namespace
|
||||
|
||||
// CommandBuffer
|
||||
|
||||
CommandBufferBase::CommandBufferBase(CommandBufferBuilder* builder)
|
||||
: mDevice(builder->mDevice),
|
||||
mBuffersTransitioned(std::move(builder->mState->mBuffersTransitioned)),
|
||||
|
@ -150,6 +152,8 @@ namespace backend {
|
|||
return mDevice;
|
||||
}
|
||||
|
||||
// CommandBufferBuilder
|
||||
|
||||
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device)
|
||||
: Builder(device), mState(std::make_unique<CommandBufferStateTracker>(this)) {
|
||||
}
|
||||
|
@ -161,23 +165,43 @@ namespace backend {
|
|||
}
|
||||
}
|
||||
|
||||
CommandIterator CommandBufferBuilder::AcquireCommands() {
|
||||
ASSERT(!mWereCommandsAcquired);
|
||||
mWereCommandsAcquired = true;
|
||||
return std::move(mIterator);
|
||||
}
|
||||
|
||||
CommandBufferBase* CommandBufferBuilder::GetResultImpl() {
|
||||
MoveToIterator();
|
||||
return mDevice->CreateCommandBuffer(this);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::MoveToIterator() {
|
||||
if (!mWasMovedToIterator) {
|
||||
mIterator = std::move(mAllocator);
|
||||
mWasMovedToIterator = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of the command buffer validation that can be precomputed before submit
|
||||
|
||||
bool CommandBufferBuilder::ValidateGetResult() {
|
||||
MoveToIterator();
|
||||
mIterator.Reset();
|
||||
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
mIterator.NextCommand<BeginComputePassCmd>();
|
||||
if (!mState->BeginComputePass()) {
|
||||
if (!ValidateComputePass()) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
|
||||
RenderPassDescriptorBase* info = cmd->info.Get();
|
||||
if (!mState->BeginRenderPass(info)) {
|
||||
if (!ValidateRenderPass(cmd->info.Get())) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
@ -186,7 +210,6 @@ namespace backend {
|
|||
CopyBufferToBufferCmd* copy = mIterator.NextCommand<CopyBufferToBufferCmd>();
|
||||
if (!ValidateCopySizeFitsInBuffer(this, copy->source, copy->size) ||
|
||||
!ValidateCopySizeFitsInBuffer(this, copy->destination, copy->size) ||
|
||||
!mState->ValidateCanCopy() ||
|
||||
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
||||
nxt::BufferUsageBit::TransferSrc) ||
|
||||
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
||||
|
@ -206,7 +229,6 @@ namespace backend {
|
|||
!ValidateCopySizeFitsInBuffer(this, copy->source, bufferCopySize) ||
|
||||
!ValidateTexelBufferOffset(this, copy->destination.texture.Get(),
|
||||
copy->source) ||
|
||||
!mState->ValidateCanCopy() ||
|
||||
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
||||
nxt::BufferUsageBit::TransferSrc) ||
|
||||
!mState->ValidateCanUseTextureAs(copy->destination.texture.Get(),
|
||||
|
@ -226,7 +248,6 @@ namespace backend {
|
|||
!ValidateCopySizeFitsInBuffer(this, copy->destination, bufferCopySize) ||
|
||||
!ValidateTexelBufferOffset(this, copy->source.texture.Get(),
|
||||
copy->destination) ||
|
||||
!mState->ValidateCanCopy() ||
|
||||
!mState->ValidateCanUseTextureAs(copy->source.texture.Get(),
|
||||
nxt::TextureUsageBit::TransferSrc) ||
|
||||
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
||||
|
@ -235,6 +256,42 @@ namespace backend {
|
|||
}
|
||||
} break;
|
||||
|
||||
case Command::TransitionBufferUsage: {
|
||||
TransitionBufferUsageCmd* cmd =
|
||||
mIterator.NextCommand<TransitionBufferUsageCmd>();
|
||||
if (!mState->TransitionBufferUsage(cmd->buffer.Get(), cmd->usage)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::TransitionTextureUsage: {
|
||||
TransitionTextureUsageCmd* cmd =
|
||||
mIterator.NextCommand<TransitionTextureUsageCmd>();
|
||||
if (!mState->TransitionTextureUsage(cmd->texture.Get(), cmd->usage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
default:
|
||||
HandleError("Command disallowed outside of a pass");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferBuilder::ValidateComputePass() {
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndComputePass: {
|
||||
mIterator.NextCommand<EndComputePassCmd>();
|
||||
mState->EndPass();
|
||||
return true;
|
||||
} break;
|
||||
|
||||
case Command::Dispatch: {
|
||||
mIterator.NextCommand<DispatchCmd>();
|
||||
if (!mState->ValidateCanDispatch()) {
|
||||
|
@ -242,6 +299,58 @@ namespace backend {
|
|||
}
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipelineBase* pipeline = cmd->pipeline.Get();
|
||||
if (!mState->SetComputePipeline(pipeline)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetPushConstants: {
|
||||
SetPushConstantsCmd* cmd = mIterator.NextCommand<SetPushConstantsCmd>();
|
||||
mIterator.NextData<uint32_t>(cmd->count);
|
||||
// Validation of count and offset has already been done when the command was
|
||||
// recorded because it impacts the size of an allocation in the
|
||||
// CommandAllocator.
|
||||
if (cmd->stages & ~nxt::ShaderStageBit::Compute) {
|
||||
HandleError(
|
||||
"SetPushConstants stage must be compute or 0 in compute passes");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = mIterator.NextCommand<SetBindGroupCmd>();
|
||||
if (!mState->SetBindGroup(cmd->index, cmd->group.Get())) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
HandleError("Command disallowed inside a compute pass");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HandleError("Unfinished compute pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommandBufferBuilder::ValidateRenderPass(RenderPassDescriptorBase* renderPass) {
|
||||
if (!mState->BeginRenderPass(renderPass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndRenderPass: {
|
||||
mIterator.NextCommand<EndRenderPassCmd>();
|
||||
mState->EndPass();
|
||||
return true;
|
||||
} break;
|
||||
|
||||
case Command::DrawArrays: {
|
||||
mIterator.NextCommand<DrawArraysCmd>();
|
||||
if (!mState->ValidateCanDrawArrays()) {
|
||||
|
@ -256,31 +365,15 @@ namespace backend {
|
|||
}
|
||||
} break;
|
||||
|
||||
case Command::EndComputePass: {
|
||||
mIterator.NextCommand<EndComputePassCmd>();
|
||||
if (!mState->EndComputePass()) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::EndRenderPass: {
|
||||
mIterator.NextCommand<EndRenderPassCmd>();
|
||||
if (!mState->EndRenderPass()) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipelineBase* pipeline = cmd->pipeline.Get();
|
||||
if (!mState->SetComputePipeline(pipeline)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetRenderPipeline: {
|
||||
SetRenderPipelineCmd* cmd = mIterator.NextCommand<SetRenderPipelineCmd>();
|
||||
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
||||
|
||||
if (!pipeline->IsCompatibleWith(renderPass)) {
|
||||
HandleError("Pipeline is incompatible with this render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mState->SetRenderPipeline(pipeline)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -292,33 +385,25 @@ namespace backend {
|
|||
// Validation of count and offset has already been done when the command was
|
||||
// recorded because it impacts the size of an allocation in the
|
||||
// CommandAllocator.
|
||||
if (!mState->ValidateSetPushConstants(cmd->stages)) {
|
||||
if (cmd->stages &
|
||||
~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
|
||||
HandleError(
|
||||
"SetPushConstants stage must be a subset of (vertex|fragment) in "
|
||||
"render passes");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetStencilReference: {
|
||||
mIterator.NextCommand<SetStencilReferenceCmd>();
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set stencil reference without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetBlendColor: {
|
||||
mIterator.NextCommand<SetBlendColorCmd>();
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set blend color without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetScissorRect: {
|
||||
mIterator.NextCommand<SetScissorRectCmd>();
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set scissor rect without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
|
@ -345,42 +430,17 @@ namespace backend {
|
|||
}
|
||||
} break;
|
||||
|
||||
case Command::TransitionBufferUsage: {
|
||||
TransitionBufferUsageCmd* cmd =
|
||||
mIterator.NextCommand<TransitionBufferUsageCmd>();
|
||||
if (!mState->TransitionBufferUsage(cmd->buffer.Get(), cmd->usage)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::TransitionTextureUsage: {
|
||||
TransitionTextureUsageCmd* cmd =
|
||||
mIterator.NextCommand<TransitionTextureUsageCmd>();
|
||||
if (!mState->TransitionTextureUsage(cmd->texture.Get(), cmd->usage)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} break;
|
||||
default:
|
||||
HandleError("Command disallowed inside a render pass");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mState->ValidateEndCommandBuffer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
HandleError("Unfinished render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandIterator CommandBufferBuilder::AcquireCommands() {
|
||||
ASSERT(!mWereCommandsAcquired);
|
||||
mWereCommandsAcquired = true;
|
||||
return std::move(mIterator);
|
||||
}
|
||||
|
||||
CommandBufferBase* CommandBufferBuilder::GetResultImpl() {
|
||||
MoveToIterator();
|
||||
return mDevice->CreateCommandBuffer(this);
|
||||
}
|
||||
// Implementation of the API's command recording methods
|
||||
|
||||
void CommandBufferBuilder::BeginComputePass() {
|
||||
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||
|
@ -630,11 +690,4 @@ namespace backend {
|
|||
cmd->usage = usage;
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::MoveToIterator() {
|
||||
if (!mWasMovedToIterator) {
|
||||
mIterator = std::move(mAllocator);
|
||||
mWasMovedToIterator = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
|
|
|
@ -136,6 +136,9 @@ namespace backend {
|
|||
CommandBufferBase* GetResultImpl() override;
|
||||
void MoveToIterator();
|
||||
|
||||
bool ValidateComputePass();
|
||||
bool ValidateRenderPass(RenderPassDescriptorBase* renderPass);
|
||||
|
||||
std::unique_ptr<CommandBufferStateTracker> mState;
|
||||
CommandAllocator mAllocator;
|
||||
CommandIterator mIterator;
|
||||
|
|
|
@ -32,18 +32,6 @@ namespace backend {
|
|||
: mBuilder(mBuilder) {
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::HaveRenderPass() const {
|
||||
return mCurrentRenderPass != nullptr;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateCanCopy() const {
|
||||
if (mCurrentRenderPass) {
|
||||
mBuilder->HandleError("Copy cannot occur during a render pass");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateCanUseBufferAs(BufferBase* buffer,
|
||||
nxt::BufferUsageBit usage) const {
|
||||
if (!BufferHasGuaranteedUsageBit(buffer, usage)) {
|
||||
|
@ -64,14 +52,13 @@ namespace backend {
|
|||
|
||||
bool CommandBufferStateTracker::ValidateCanDispatch() {
|
||||
constexpr ValidationAspects requiredAspects =
|
||||
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | // implicitly requires COMPUTE_PASS
|
||||
1 << VALIDATION_ASPECT_BIND_GROUPS;
|
||||
1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS;
|
||||
if ((requiredAspects & ~mAspects).none()) {
|
||||
// Fast return-true path if everything is good
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mAspects[VALIDATION_ASPECT_COMPUTE_PIPELINE]) {
|
||||
if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
|
||||
mBuilder->HandleError("No active compute pipeline");
|
||||
return false;
|
||||
}
|
||||
|
@ -84,10 +71,9 @@ namespace backend {
|
|||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateCanDrawArrays() {
|
||||
// TODO(kainino@chromium.org): Check for a current render pass
|
||||
constexpr ValidationAspects requiredAspects =
|
||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_PASS
|
||||
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
|
||||
constexpr ValidationAspects requiredAspects = 1 << VALIDATION_ASPECT_PIPELINE |
|
||||
1 << VALIDATION_ASPECT_BIND_GROUPS |
|
||||
1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
|
||||
if ((requiredAspects & ~mAspects).none()) {
|
||||
// Fast return-true path if everything is good
|
||||
return true;
|
||||
|
@ -97,9 +83,8 @@ namespace backend {
|
|||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateCanDrawElements() {
|
||||
// TODO(kainino@chromium.org): Check for a current render pass
|
||||
constexpr ValidationAspects requiredAspects =
|
||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS |
|
||||
1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS |
|
||||
1 << VALIDATION_ASPECT_VERTEX_BUFFERS | 1 << VALIDATION_ASPECT_INDEX_BUFFER;
|
||||
if ((requiredAspects & ~mAspects).none()) {
|
||||
// Fast return-true path if everything is good
|
||||
|
@ -113,72 +98,7 @@ namespace backend {
|
|||
return RevalidateCanDraw();
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateEndCommandBuffer() const {
|
||||
if (mCurrentRenderPass != nullptr) {
|
||||
mBuilder->HandleError("Can't end command buffer with an active render pass");
|
||||
return false;
|
||||
}
|
||||
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
mBuilder->HandleError("Can't end command buffer with an active compute pass");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateSetPushConstants(nxt::ShaderStageBit stages) {
|
||||
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
if (stages & ~nxt::ShaderStageBit::Compute) {
|
||||
mBuilder->HandleError(
|
||||
"SetPushConstants stage must be compute or 0 in compute passes");
|
||||
return false;
|
||||
}
|
||||
} else if (mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
|
||||
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
|
||||
mBuilder->HandleError(
|
||||
"SetPushConstants stage must be a subset if (vertex|fragment) in render "
|
||||
"passes");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mBuilder->HandleError(
|
||||
"PushConstants must be set in either compute passes or render passes");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::BeginComputePass() {
|
||||
if (mCurrentRenderPass != nullptr) {
|
||||
mBuilder->HandleError("Cannot begin a compute pass while a render pass is active");
|
||||
return false;
|
||||
}
|
||||
mAspects.set(VALIDATION_ASPECT_COMPUTE_PASS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::EndComputePass() {
|
||||
if (!mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
mBuilder->HandleError("Can't end a compute pass without beginning one");
|
||||
return false;
|
||||
}
|
||||
mAspects.reset(VALIDATION_ASPECT_COMPUTE_PASS);
|
||||
UnsetPipeline();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::BeginRenderPass(RenderPassDescriptorBase* info) {
|
||||
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
mBuilder->HandleError("Cannot begin a render pass while a compute pass is active");
|
||||
return false;
|
||||
}
|
||||
if (mCurrentRenderPass != nullptr) {
|
||||
mBuilder->HandleError("A render pass is already active");
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentRenderPass = info;
|
||||
mAspects.set(VALIDATION_ASPECT_RENDER_PASS);
|
||||
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
TextureBase* texture = info->GetColorAttachment(i).view->GetTexture();
|
||||
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
||||
|
@ -200,50 +120,21 @@ namespace backend {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::EndRenderPass() {
|
||||
if (mCurrentRenderPass == nullptr) {
|
||||
mBuilder->HandleError("No render pass is currently active");
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandBufferStateTracker::EndPass() {
|
||||
// Everything in mTexturesAttached should be for the current render pass.
|
||||
mTexturesAttached.clear();
|
||||
|
||||
mInputsSet.reset();
|
||||
UnsetPipeline();
|
||||
|
||||
mAspects.reset(VALIDATION_ASPECT_RENDER_PASS);
|
||||
mCurrentRenderPass = nullptr;
|
||||
|
||||
return true;
|
||||
mAspects = 0;
|
||||
mBindgroups.fill(nullptr);
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) {
|
||||
if (!mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
mBuilder->HandleError("A compute pass must be active when a compute pipeline is set");
|
||||
return false;
|
||||
}
|
||||
if (mCurrentRenderPass) {
|
||||
mBuilder->HandleError("Can't use a compute pipeline while a render pass is active");
|
||||
return false;
|
||||
}
|
||||
|
||||
mAspects.set(VALIDATION_ASPECT_COMPUTE_PIPELINE);
|
||||
SetPipelineCommon(pipeline);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
|
||||
if (!mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
|
||||
mBuilder->HandleError("A render pass must be active when a render pipeline is set");
|
||||
return false;
|
||||
}
|
||||
if (!pipeline->IsCompatibleWith(mCurrentRenderPass)) {
|
||||
mBuilder->HandleError("Pipeline is incompatible with this render pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
mAspects.set(VALIDATION_ASPECT_RENDER_PIPELINE);
|
||||
mLastRenderPipeline = pipeline;
|
||||
SetPipelineCommon(pipeline);
|
||||
return true;
|
||||
|
@ -419,9 +310,7 @@ namespace backend {
|
|||
}
|
||||
|
||||
bool CommandBufferStateTracker::HavePipeline() const {
|
||||
constexpr ValidationAspects pipelineAspects =
|
||||
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | 1 << VALIDATION_ASPECT_RENDER_PIPELINE;
|
||||
return (mAspects & pipelineAspects).any();
|
||||
return mAspects[VALIDATION_ASPECT_PIPELINE];
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateBindGroupUsages(BindGroupBase* group) const {
|
||||
|
@ -472,7 +361,7 @@ namespace backend {
|
|||
}
|
||||
|
||||
bool CommandBufferStateTracker::RevalidateCanDraw() {
|
||||
if (!mAspects[VALIDATION_ASPECT_RENDER_PIPELINE]) {
|
||||
if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
|
||||
mBuilder->HandleError("No active render pipeline");
|
||||
return false;
|
||||
}
|
||||
|
@ -491,6 +380,8 @@ namespace backend {
|
|||
void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
|
||||
PipelineLayoutBase* layout = pipeline->GetLayout();
|
||||
|
||||
mAspects.set(VALIDATION_ASPECT_PIPELINE);
|
||||
|
||||
mAspects.reset(VALIDATION_ASPECT_BIND_GROUPS);
|
||||
mAspects.reset(VALIDATION_ASPECT_VERTEX_BUFFERS);
|
||||
// Reset bindgroups but mark unused bindgroups as valid
|
||||
|
@ -504,12 +395,4 @@ namespace backend {
|
|||
mLastPipeline = pipeline;
|
||||
}
|
||||
|
||||
void CommandBufferStateTracker::UnsetPipeline() {
|
||||
constexpr ValidationAspects pipelineDependentAspects =
|
||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | 1 << VALIDATION_ASPECT_COMPUTE_PIPELINE |
|
||||
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS |
|
||||
1 << VALIDATION_ASPECT_INDEX_BUFFER;
|
||||
mAspects &= ~pipelineDependentAspects;
|
||||
mBindgroups.fill(nullptr);
|
||||
}
|
||||
} // namespace backend
|
||||
|
|
|
@ -29,21 +29,16 @@ namespace backend {
|
|||
explicit CommandBufferStateTracker(CommandBufferBuilder* builder);
|
||||
|
||||
// Non-state-modifying validation functions
|
||||
bool HaveRenderPass() const;
|
||||
bool ValidateCanCopy() const;
|
||||
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
|
||||
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
|
||||
bool ValidateCanDispatch();
|
||||
bool ValidateCanDrawArrays();
|
||||
bool ValidateCanDrawElements();
|
||||
bool ValidateEndCommandBuffer() const;
|
||||
bool ValidateSetPushConstants(nxt::ShaderStageBit stages);
|
||||
|
||||
// State-modifying methods
|
||||
bool BeginComputePass();
|
||||
bool EndComputePass();
|
||||
void EndPass();
|
||||
bool BeginRenderPass(RenderPassDescriptorBase* info);
|
||||
bool EndRenderPass();
|
||||
bool SetComputePipeline(ComputePipelineBase* pipeline);
|
||||
bool SetRenderPipeline(RenderPipelineBase* pipeline);
|
||||
bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
|
||||
|
@ -58,17 +53,13 @@ namespace backend {
|
|||
// command buffer.
|
||||
std::set<BufferBase*> mBuffersTransitioned;
|
||||
std::set<TextureBase*> mTexturesTransitioned;
|
||||
std::set<TextureBase*> mTexturesAttached;
|
||||
|
||||
private:
|
||||
enum ValidationAspect {
|
||||
VALIDATION_ASPECT_RENDER_PIPELINE,
|
||||
VALIDATION_ASPECT_COMPUTE_PIPELINE,
|
||||
VALIDATION_ASPECT_PIPELINE,
|
||||
VALIDATION_ASPECT_BIND_GROUPS,
|
||||
VALIDATION_ASPECT_VERTEX_BUFFERS,
|
||||
VALIDATION_ASPECT_INDEX_BUFFER,
|
||||
VALIDATION_ASPECT_RENDER_PASS,
|
||||
VALIDATION_ASPECT_COMPUTE_PASS,
|
||||
|
||||
VALIDATION_ASPECT_COUNT
|
||||
};
|
||||
|
@ -91,7 +82,6 @@ namespace backend {
|
|||
bool RevalidateCanDraw();
|
||||
|
||||
void SetPipelineCommon(PipelineBase* pipeline);
|
||||
void UnsetPipeline();
|
||||
|
||||
CommandBufferBuilder* mBuilder;
|
||||
|
||||
|
@ -105,8 +95,7 @@ namespace backend {
|
|||
|
||||
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
|
||||
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
|
||||
|
||||
RenderPassDescriptorBase* mCurrentRenderPass = nullptr;
|
||||
std::set<TextureBase*> mTexturesAttached;
|
||||
};
|
||||
} // namespace backend
|
||||
|
||||
|
|
Loading…
Reference in New Issue