CommandBuffer: have a state tracker per-pass
Also perform small code simplifications of the CommandBufferStateTracker
now that it only tracks aspects.
diff --git a/src/backend/CommandBuffer.cpp b/src/backend/CommandBuffer.cpp
index 9b74c3f..beb31ca 100644
--- a/src/backend/CommandBuffer.cpp
+++ b/src/backend/CommandBuffer.cpp
@@ -278,8 +278,7 @@
// CommandBufferBuilder
- CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device)
- : Builder(device), mState(std::make_unique<CommandBufferStateTracker>()) {
+ CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device) {
}
CommandBufferBuilder::~CommandBufferBuilder() {
@@ -392,6 +391,7 @@
MaybeError CommandBufferBuilder::ValidateComputePass() {
PassResourceUsageTracker usageTracker;
+ CommandBufferStateTracker persistentState;
Command type;
while (mIterator.NextCommandId(&type)) {
@@ -401,20 +401,18 @@
DAWN_TRY(usageTracker.ValidateUsages(PassType::Compute));
mPassResourceUsages.push_back(usageTracker.AcquireResourceUsage());
-
- mState->EndPass();
return {};
} break;
case Command::Dispatch: {
mIterator.NextCommand<DispatchCmd>();
- DAWN_TRY(mState->ValidateCanDispatch());
+ DAWN_TRY(persistentState.ValidateCanDispatch());
} break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get();
- mState->SetComputePipeline(pipeline);
+ persistentState.SetComputePipeline(pipeline);
} break;
case Command::SetPushConstants: {
@@ -433,7 +431,7 @@
SetBindGroupCmd* cmd = mIterator.NextCommand<SetBindGroupCmd>();
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
- mState->SetBindGroup(cmd->index, cmd->group.Get());
+ persistentState.SetBindGroup(cmd->index, cmd->group.Get());
} break;
default:
@@ -446,6 +444,7 @@
MaybeError CommandBufferBuilder::ValidateRenderPass(RenderPassDescriptorBase* renderPass) {
PassResourceUsageTracker usageTracker;
+ CommandBufferStateTracker persistentState;
// Track usage of the render pass attachments
for (uint32_t i : IterateBitSet(renderPass->GetColorAttachmentMask())) {
@@ -466,19 +465,17 @@
DAWN_TRY(usageTracker.ValidateUsages(PassType::Render));
mPassResourceUsages.push_back(usageTracker.AcquireResourceUsage());
-
- mState->EndPass();
return {};
} break;
case Command::DrawArrays: {
mIterator.NextCommand<DrawArraysCmd>();
- DAWN_TRY(mState->ValidateCanDrawArrays());
+ DAWN_TRY(persistentState.ValidateCanDrawArrays());
} break;
case Command::DrawElements: {
mIterator.NextCommand<DrawElementsCmd>();
- DAWN_TRY(mState->ValidateCanDrawElements());
+ DAWN_TRY(persistentState.ValidateCanDrawElements());
} break;
case Command::SetRenderPipeline: {
@@ -489,7 +486,7 @@
DAWN_RETURN_ERROR("Pipeline is incompatible with this render pass");
}
- mState->SetRenderPipeline(pipeline);
+ persistentState.SetRenderPipeline(pipeline);
} break;
case Command::SetPushConstants: {
@@ -522,14 +519,14 @@
SetBindGroupCmd* cmd = mIterator.NextCommand<SetBindGroupCmd>();
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
- mState->SetBindGroup(cmd->index, cmd->group.Get());
+ persistentState.SetBindGroup(cmd->index, cmd->group.Get());
} break;
case Command::SetIndexBuffer: {
SetIndexBufferCmd* cmd = mIterator.NextCommand<SetIndexBufferCmd>();
usageTracker.BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsageBit::Index);
- DAWN_TRY(mState->SetIndexBuffer());
+ persistentState.SetIndexBuffer();
} break;
case Command::SetVertexBuffers: {
@@ -539,8 +536,8 @@
for (uint32_t i = 0; i < cmd->count; ++i) {
usageTracker.BufferUsedAs(buffers[i].Get(), dawn::BufferUsageBit::Vertex);
- DAWN_TRY(mState->SetVertexBuffer(cmd->startSlot + i));
}
+ persistentState.SetVertexBuffer(cmd->startSlot, cmd->count);
} break;
default:
diff --git a/src/backend/CommandBuffer.h b/src/backend/CommandBuffer.h
index 4efd772..ce15623 100644
--- a/src/backend/CommandBuffer.h
+++ b/src/backend/CommandBuffer.h
@@ -31,7 +31,6 @@
class BindGroupBase;
class BufferBase;
- class CommandBufferStateTracker;
class FramebufferBase;
class DeviceBase;
class PipelineBase;
@@ -138,7 +137,6 @@
MaybeError ValidateComputePass();
MaybeError ValidateRenderPass(RenderPassDescriptorBase* renderPass);
- std::unique_ptr<CommandBufferStateTracker> mState;
CommandAllocator mAllocator;
CommandIterator mIterator;
bool mWasMovedToIterator = false;
diff --git a/src/backend/CommandBufferStateTracker.cpp b/src/backend/CommandBufferStateTracker.cpp
index 943cf8f..37b04c3 100644
--- a/src/backend/CommandBufferStateTracker.cpp
+++ b/src/backend/CommandBufferStateTracker.cpp
@@ -15,69 +15,124 @@
#include "backend/CommandBufferStateTracker.h"
#include "backend/BindGroup.h"
-#include "backend/BindGroupLayout.h"
-#include "backend/Buffer.h"
#include "backend/ComputePipeline.h"
#include "backend/Forward.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
-#include "backend/RenderPassDescriptor.h"
#include "backend/RenderPipeline.h"
-#include "backend/Texture.h"
#include "common/Assert.h"
#include "common/BitSetIterator.h"
namespace backend {
- MaybeError CommandBufferStateTracker::ValidateCanDispatch() {
- constexpr ValidationAspects requiredAspects =
- 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS;
- if ((requiredAspects & ~mAspects).none()) {
- // Fast return-true path if everything is good
- return {};
- }
+ enum ValidationAspect {
+ VALIDATION_ASPECT_PIPELINE,
+ VALIDATION_ASPECT_BIND_GROUPS,
+ VALIDATION_ASPECT_VERTEX_BUFFERS,
+ VALIDATION_ASPECT_INDEX_BUFFER,
- if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
- DAWN_RETURN_ERROR("No active compute pipeline");
- }
- // Compute the lazily computed mAspects
- if (!RecomputeHaveAspectBindGroups()) {
- DAWN_RETURN_ERROR("Bind group state not valid");
- }
- return {};
+ VALIDATION_ASPECT_COUNT
+ };
+ static_assert(VALIDATION_ASPECT_COUNT == CommandBufferStateTracker::kNumAspects, "");
+
+ static constexpr CommandBufferStateTracker::ValidationAspects kDispatchAspects =
+ 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS;
+
+ static constexpr CommandBufferStateTracker::ValidationAspects kDrawArraysAspects =
+ 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS |
+ 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
+
+ static constexpr CommandBufferStateTracker::ValidationAspects kDrawElementsAspects =
+ 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS |
+ 1 << VALIDATION_ASPECT_VERTEX_BUFFERS | 1 << VALIDATION_ASPECT_INDEX_BUFFER;
+
+ static constexpr CommandBufferStateTracker::ValidationAspects kLazyAspects =
+ 1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
+
+ MaybeError CommandBufferStateTracker::ValidateCanDispatch() {
+ return ValidateOperation(kDispatchAspects);
}
MaybeError CommandBufferStateTracker::ValidateCanDrawArrays() {
- 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 {};
- }
-
- return RevalidateCanDraw();
+ return ValidateOperation(kDrawArraysAspects);
}
MaybeError CommandBufferStateTracker::ValidateCanDrawElements() {
- constexpr ValidationAspects requiredAspects =
- 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
+ return ValidateOperation(kDrawElementsAspects);
+ }
+
+ MaybeError CommandBufferStateTracker::ValidateOperation(ValidationAspects requiredAspects) {
+ // Fast return-true path if everything is good
+ ValidationAspects missingAspects = requiredAspects & ~mAspects;
+ if (missingAspects.none()) {
return {};
}
- if (!mAspects[VALIDATION_ASPECT_INDEX_BUFFER]) {
- DAWN_RETURN_ERROR("Cannot DrawElements without index buffer set");
+ // Generate an error immediately if a non-lazy aspect is missing as computing lazy aspects
+ // requires the pipeline to be set.
+ if ((missingAspects & ~kLazyAspects).any()) {
+ return GenerateAspectError(missingAspects);
}
- return RevalidateCanDraw();
+
+ RecomputeLazyAspects(missingAspects);
+
+ missingAspects = requiredAspects & ~mAspects;
+ if (missingAspects.any()) {
+ return GenerateAspectError(missingAspects);
+ }
+
+ return {};
}
- void CommandBufferStateTracker::EndPass() {
- mInputsSet.reset();
- mAspects = 0;
- mBindgroups.fill(nullptr);
+ void CommandBufferStateTracker::RecomputeLazyAspects(ValidationAspects aspects) {
+ ASSERT(mAspects[VALIDATION_ASPECT_PIPELINE]);
+ ASSERT((aspects & ~kLazyAspects).none());
+
+ if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) {
+ bool matches = true;
+
+ for (uint32_t i : IterateBitSet(mLastPipelineLayout->GetBindGroupLayoutsMask())) {
+ if (mLastPipelineLayout->GetBindGroupLayout(i) != mBindgroups[i]->GetLayout()) {
+ matches = false;
+ break;
+ }
+ }
+
+ if (matches) {
+ mAspects.set(VALIDATION_ASPECT_BIND_GROUPS);
+ }
+ }
+
+ if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) {
+ ASSERT(mLastRenderPipeline != nullptr);
+
+ auto requiredInputs = mLastRenderPipeline->GetInputState()->GetInputsSetMask();
+ if ((mInputsSet & requiredInputs) == requiredInputs) {
+ mAspects.set(VALIDATION_ASPECT_VERTEX_BUFFERS);
+ }
+ }
+ }
+
+ MaybeError CommandBufferStateTracker::GenerateAspectError(ValidationAspects aspects) {
+ ASSERT(aspects.any());
+
+ if (aspects[VALIDATION_ASPECT_INDEX_BUFFER]) {
+ DAWN_RETURN_ERROR("Missing index buffer");
+ }
+
+ if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) {
+ DAWN_RETURN_ERROR("Missing vertex buffer");
+ }
+
+ if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) {
+ DAWN_RETURN_ERROR("Missing bind group");
+ }
+
+ if (aspects[VALIDATION_ASPECT_PIPELINE]) {
+ DAWN_RETURN_ERROR("Missing pipeline");
+ }
+
+ UNREACHABLE();
}
void CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) {
@@ -90,96 +145,26 @@
}
void CommandBufferStateTracker::SetBindGroup(uint32_t index, BindGroupBase* bindgroup) {
- mBindgroupsSet.set(index);
mBindgroups[index] = bindgroup;
}
- MaybeError CommandBufferStateTracker::SetIndexBuffer() {
- if (!HavePipeline()) {
- DAWN_RETURN_ERROR("Can't set the index buffer without a pipeline");
- }
-
+ void CommandBufferStateTracker::SetIndexBuffer() {
mAspects.set(VALIDATION_ASPECT_INDEX_BUFFER);
- return {};
}
- MaybeError CommandBufferStateTracker::SetVertexBuffer(uint32_t index) {
- if (!HavePipeline()) {
- DAWN_RETURN_ERROR("Can't set vertex buffers without a pipeline");
+ void CommandBufferStateTracker::SetVertexBuffer(uint32_t start, uint32_t count) {
+ for (uint32_t i = 0; i < count; ++i) {
+ mInputsSet.set(start + i);
}
-
- mInputsSet.set(index);
- return {};
- }
-
- bool CommandBufferStateTracker::RecomputeHaveAspectBindGroups() {
- if (mAspects[VALIDATION_ASPECT_BIND_GROUPS]) {
- return true;
- }
- // Assumes we have a pipeline already
- if (!mBindgroupsSet.all()) {
- return false;
- }
- for (size_t i = 0; i < mBindgroups.size(); ++i) {
- if (auto* bindgroup = mBindgroups[i]) {
- // TODO(kainino@chromium.org): bind group compatibility
- auto* pipelineBGL = mLastPipeline->GetLayout()->GetBindGroupLayout(i);
- if (pipelineBGL && bindgroup->GetLayout() != pipelineBGL) {
- return false;
- }
- }
- }
- mAspects.set(VALIDATION_ASPECT_BIND_GROUPS);
- return true;
- }
-
- bool CommandBufferStateTracker::RecomputeHaveAspectVertexBuffers() {
- if (mAspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) {
- return true;
- }
- // Assumes we have a pipeline already
- auto requiredInputs = mLastRenderPipeline->GetInputState()->GetInputsSetMask();
- if ((mInputsSet & requiredInputs) == requiredInputs) {
- mAspects.set(VALIDATION_ASPECT_VERTEX_BUFFERS);
- return true;
- }
- return false;
- }
-
- bool CommandBufferStateTracker::HavePipeline() const {
- return mAspects[VALIDATION_ASPECT_PIPELINE];
- }
-
- MaybeError CommandBufferStateTracker::RevalidateCanDraw() {
- if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
- DAWN_RETURN_ERROR("No active render pipeline");
- }
- // Compute the lazily computed mAspects
- if (!RecomputeHaveAspectBindGroups()) {
- DAWN_RETURN_ERROR("Bind group state not valid");
- }
- if (!RecomputeHaveAspectVertexBuffers()) {
- DAWN_RETURN_ERROR("Some vertex buffers are not set");
- }
- return {};
}
void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
- PipelineLayoutBase* layout = pipeline->GetLayout();
+ mLastPipelineLayout = 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
- mBindgroupsSet = ~layout->GetBindGroupLayoutsMask();
-
- // Only bindgroups that were not the same layout in the last pipeline need to be set again.
- if (mLastPipeline) {
- mBindgroupsSet |= layout->InheritedGroupsMask(mLastPipeline->GetLayout());
- }
-
- mLastPipeline = pipeline;
+ // Reset lazy aspects so they get recomputed on the next operation.
+ mAspects &= ~kLazyAspects;
}
} // namespace backend
diff --git a/src/backend/CommandBufferStateTracker.h b/src/backend/CommandBufferStateTracker.h
index 45079e2..7b4454b 100644
--- a/src/backend/CommandBufferStateTracker.h
+++ b/src/backend/CommandBufferStateTracker.h
@@ -28,45 +28,33 @@
class CommandBufferStateTracker {
public:
// Non-state-modifying validation functions
- MaybeError ValidateCanCopy() const;
MaybeError ValidateCanDispatch();
MaybeError ValidateCanDrawArrays();
MaybeError ValidateCanDrawElements();
// State-modifying methods
- void EndPass();
void SetComputePipeline(ComputePipelineBase* pipeline);
void SetRenderPipeline(RenderPipelineBase* pipeline);
void SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
- MaybeError SetIndexBuffer();
- MaybeError SetVertexBuffer(uint32_t index);
+ void SetIndexBuffer();
+ void SetVertexBuffer(uint32_t start, uint32_t count);
+
+ static constexpr size_t kNumAspects = 4;
+ using ValidationAspects = std::bitset<kNumAspects>;
private:
- enum ValidationAspect {
- VALIDATION_ASPECT_PIPELINE,
- VALIDATION_ASPECT_BIND_GROUPS,
- VALIDATION_ASPECT_VERTEX_BUFFERS,
- VALIDATION_ASPECT_INDEX_BUFFER,
-
- VALIDATION_ASPECT_COUNT
- };
- using ValidationAspects = std::bitset<VALIDATION_ASPECT_COUNT>;
-
- // Queries for lazily evaluated aspects
- bool RecomputeHaveAspectBindGroups();
- bool RecomputeHaveAspectVertexBuffers();
-
- bool HavePipeline() const;
- MaybeError RevalidateCanDraw();
+ MaybeError ValidateOperation(ValidationAspects requiredAspects);
+ void RecomputeLazyAspects(ValidationAspects aspects);
+ MaybeError GenerateAspectError(ValidationAspects aspects);
void SetPipelineCommon(PipelineBase* pipeline);
ValidationAspects mAspects;
- std::bitset<kMaxBindGroups> mBindgroupsSet;
std::array<BindGroupBase*, kMaxBindGroups> mBindgroups = {};
std::bitset<kMaxVertexInputs> mInputsSet;
- PipelineBase* mLastPipeline = nullptr;
+
+ PipelineLayoutBase* mLastPipelineLayout = nullptr;
RenderPipelineBase* mLastRenderPipeline = nullptr;
};