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
|
} // namespace
|
||||||
|
|
||||||
|
// CommandBuffer
|
||||||
|
|
||||||
CommandBufferBase::CommandBufferBase(CommandBufferBuilder* builder)
|
CommandBufferBase::CommandBufferBase(CommandBufferBuilder* builder)
|
||||||
: mDevice(builder->mDevice),
|
: mDevice(builder->mDevice),
|
||||||
mBuffersTransitioned(std::move(builder->mState->mBuffersTransitioned)),
|
mBuffersTransitioned(std::move(builder->mState->mBuffersTransitioned)),
|
||||||
|
@ -150,6 +152,8 @@ namespace backend {
|
||||||
return mDevice;
|
return mDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommandBufferBuilder
|
||||||
|
|
||||||
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device)
|
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device)
|
||||||
: Builder(device), mState(std::make_unique<CommandBufferStateTracker>(this)) {
|
: 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() {
|
bool CommandBufferBuilder::ValidateGetResult() {
|
||||||
MoveToIterator();
|
MoveToIterator();
|
||||||
|
mIterator.Reset();
|
||||||
|
|
||||||
Command type;
|
Command type;
|
||||||
while (mIterator.NextCommandId(&type)) {
|
while (mIterator.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mIterator.NextCommand<BeginComputePassCmd>();
|
mIterator.NextCommand<BeginComputePassCmd>();
|
||||||
if (!mState->BeginComputePass()) {
|
if (!ValidateComputePass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
|
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
|
||||||
RenderPassDescriptorBase* info = cmd->info.Get();
|
if (!ValidateRenderPass(cmd->info.Get())) {
|
||||||
if (!mState->BeginRenderPass(info)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -186,7 +210,6 @@ namespace backend {
|
||||||
CopyBufferToBufferCmd* copy = mIterator.NextCommand<CopyBufferToBufferCmd>();
|
CopyBufferToBufferCmd* copy = mIterator.NextCommand<CopyBufferToBufferCmd>();
|
||||||
if (!ValidateCopySizeFitsInBuffer(this, copy->source, copy->size) ||
|
if (!ValidateCopySizeFitsInBuffer(this, copy->source, copy->size) ||
|
||||||
!ValidateCopySizeFitsInBuffer(this, copy->destination, copy->size) ||
|
!ValidateCopySizeFitsInBuffer(this, copy->destination, copy->size) ||
|
||||||
!mState->ValidateCanCopy() ||
|
|
||||||
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
||||||
nxt::BufferUsageBit::TransferSrc) ||
|
nxt::BufferUsageBit::TransferSrc) ||
|
||||||
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
||||||
|
@ -206,7 +229,6 @@ namespace backend {
|
||||||
!ValidateCopySizeFitsInBuffer(this, copy->source, bufferCopySize) ||
|
!ValidateCopySizeFitsInBuffer(this, copy->source, bufferCopySize) ||
|
||||||
!ValidateTexelBufferOffset(this, copy->destination.texture.Get(),
|
!ValidateTexelBufferOffset(this, copy->destination.texture.Get(),
|
||||||
copy->source) ||
|
copy->source) ||
|
||||||
!mState->ValidateCanCopy() ||
|
|
||||||
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
!mState->ValidateCanUseBufferAs(copy->source.buffer.Get(),
|
||||||
nxt::BufferUsageBit::TransferSrc) ||
|
nxt::BufferUsageBit::TransferSrc) ||
|
||||||
!mState->ValidateCanUseTextureAs(copy->destination.texture.Get(),
|
!mState->ValidateCanUseTextureAs(copy->destination.texture.Get(),
|
||||||
|
@ -226,7 +248,6 @@ namespace backend {
|
||||||
!ValidateCopySizeFitsInBuffer(this, copy->destination, bufferCopySize) ||
|
!ValidateCopySizeFitsInBuffer(this, copy->destination, bufferCopySize) ||
|
||||||
!ValidateTexelBufferOffset(this, copy->source.texture.Get(),
|
!ValidateTexelBufferOffset(this, copy->source.texture.Get(),
|
||||||
copy->destination) ||
|
copy->destination) ||
|
||||||
!mState->ValidateCanCopy() ||
|
|
||||||
!mState->ValidateCanUseTextureAs(copy->source.texture.Get(),
|
!mState->ValidateCanUseTextureAs(copy->source.texture.Get(),
|
||||||
nxt::TextureUsageBit::TransferSrc) ||
|
nxt::TextureUsageBit::TransferSrc) ||
|
||||||
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
!mState->ValidateCanUseBufferAs(copy->destination.buffer.Get(),
|
||||||
|
@ -235,6 +256,42 @@ namespace backend {
|
||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
case Command::Dispatch: {
|
||||||
mIterator.NextCommand<DispatchCmd>();
|
mIterator.NextCommand<DispatchCmd>();
|
||||||
if (!mState->ValidateCanDispatch()) {
|
if (!mState->ValidateCanDispatch()) {
|
||||||
|
@ -242,6 +299,58 @@ namespace backend {
|
||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
case Command::DrawArrays: {
|
||||||
mIterator.NextCommand<DrawArraysCmd>();
|
mIterator.NextCommand<DrawArraysCmd>();
|
||||||
if (!mState->ValidateCanDrawArrays()) {
|
if (!mState->ValidateCanDrawArrays()) {
|
||||||
|
@ -256,31 +365,15 @@ namespace backend {
|
||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
case Command::SetRenderPipeline: {
|
||||||
SetRenderPipelineCmd* cmd = mIterator.NextCommand<SetRenderPipelineCmd>();
|
SetRenderPipelineCmd* cmd = mIterator.NextCommand<SetRenderPipelineCmd>();
|
||||||
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
||||||
|
|
||||||
|
if (!pipeline->IsCompatibleWith(renderPass)) {
|
||||||
|
HandleError("Pipeline is incompatible with this render pass");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mState->SetRenderPipeline(pipeline)) {
|
if (!mState->SetRenderPipeline(pipeline)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -292,33 +385,25 @@ namespace backend {
|
||||||
// Validation of count and offset has already been done when the command was
|
// Validation of count and offset has already been done when the command was
|
||||||
// recorded because it impacts the size of an allocation in the
|
// recorded because it impacts the size of an allocation in the
|
||||||
// CommandAllocator.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::SetStencilReference: {
|
case Command::SetStencilReference: {
|
||||||
mIterator.NextCommand<SetStencilReferenceCmd>();
|
mIterator.NextCommand<SetStencilReferenceCmd>();
|
||||||
if (!mState->HaveRenderPass()) {
|
|
||||||
HandleError("Can't set stencil reference without an active render pass");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::SetBlendColor: {
|
case Command::SetBlendColor: {
|
||||||
mIterator.NextCommand<SetBlendColorCmd>();
|
mIterator.NextCommand<SetBlendColorCmd>();
|
||||||
if (!mState->HaveRenderPass()) {
|
|
||||||
HandleError("Can't set blend color without an active render pass");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::SetScissorRect: {
|
case Command::SetScissorRect: {
|
||||||
mIterator.NextCommand<SetScissorRectCmd>();
|
mIterator.NextCommand<SetScissorRectCmd>();
|
||||||
if (!mState->HaveRenderPass()) {
|
|
||||||
HandleError("Can't set scissor rect without an active render pass");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::SetBindGroup: {
|
case Command::SetBindGroup: {
|
||||||
|
@ -345,42 +430,17 @@ namespace backend {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::TransitionBufferUsage: {
|
default:
|
||||||
TransitionBufferUsageCmd* cmd =
|
HandleError("Command disallowed inside a render pass");
|
||||||
mIterator.NextCommand<TransitionBufferUsageCmd>();
|
|
||||||
if (!mState->TransitionBufferUsage(cmd->buffer.Get(), cmd->usage)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
}
|
||||||
|
|
||||||
case Command::TransitionTextureUsage: {
|
HandleError("Unfinished render pass");
|
||||||
TransitionTextureUsageCmd* cmd =
|
|
||||||
mIterator.NextCommand<TransitionTextureUsageCmd>();
|
|
||||||
if (!mState->TransitionTextureUsage(cmd->texture.Get(), cmd->usage)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
// Implementation of the API's command recording methods
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mState->ValidateEndCommandBuffer()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandIterator CommandBufferBuilder::AcquireCommands() {
|
|
||||||
ASSERT(!mWereCommandsAcquired);
|
|
||||||
mWereCommandsAcquired = true;
|
|
||||||
return std::move(mIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandBufferBase* CommandBufferBuilder::GetResultImpl() {
|
|
||||||
MoveToIterator();
|
|
||||||
return mDevice->CreateCommandBuffer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandBufferBuilder::BeginComputePass() {
|
void CommandBufferBuilder::BeginComputePass() {
|
||||||
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||||
|
@ -630,11 +690,4 @@ namespace backend {
|
||||||
cmd->usage = usage;
|
cmd->usage = usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferBuilder::MoveToIterator() {
|
|
||||||
if (!mWasMovedToIterator) {
|
|
||||||
mIterator = std::move(mAllocator);
|
|
||||||
mWasMovedToIterator = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace backend
|
} // namespace backend
|
||||||
|
|
|
@ -136,6 +136,9 @@ namespace backend {
|
||||||
CommandBufferBase* GetResultImpl() override;
|
CommandBufferBase* GetResultImpl() override;
|
||||||
void MoveToIterator();
|
void MoveToIterator();
|
||||||
|
|
||||||
|
bool ValidateComputePass();
|
||||||
|
bool ValidateRenderPass(RenderPassDescriptorBase* renderPass);
|
||||||
|
|
||||||
std::unique_ptr<CommandBufferStateTracker> mState;
|
std::unique_ptr<CommandBufferStateTracker> mState;
|
||||||
CommandAllocator mAllocator;
|
CommandAllocator mAllocator;
|
||||||
CommandIterator mIterator;
|
CommandIterator mIterator;
|
||||||
|
|
|
@ -32,18 +32,6 @@ namespace backend {
|
||||||
: mBuilder(mBuilder) {
|
: 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,
|
bool CommandBufferStateTracker::ValidateCanUseBufferAs(BufferBase* buffer,
|
||||||
nxt::BufferUsageBit usage) const {
|
nxt::BufferUsageBit usage) const {
|
||||||
if (!BufferHasGuaranteedUsageBit(buffer, usage)) {
|
if (!BufferHasGuaranteedUsageBit(buffer, usage)) {
|
||||||
|
@ -64,14 +52,13 @@ namespace backend {
|
||||||
|
|
||||||
bool CommandBufferStateTracker::ValidateCanDispatch() {
|
bool CommandBufferStateTracker::ValidateCanDispatch() {
|
||||||
constexpr ValidationAspects requiredAspects =
|
constexpr ValidationAspects requiredAspects =
|
||||||
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | // implicitly requires COMPUTE_PASS
|
1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS;
|
||||||
1 << VALIDATION_ASPECT_BIND_GROUPS;
|
|
||||||
if ((requiredAspects & ~mAspects).none()) {
|
if ((requiredAspects & ~mAspects).none()) {
|
||||||
// Fast return-true path if everything is good
|
// Fast return-true path if everything is good
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mAspects[VALIDATION_ASPECT_COMPUTE_PIPELINE]) {
|
if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
|
||||||
mBuilder->HandleError("No active compute pipeline");
|
mBuilder->HandleError("No active compute pipeline");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -84,10 +71,9 @@ namespace backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::ValidateCanDrawArrays() {
|
bool CommandBufferStateTracker::ValidateCanDrawArrays() {
|
||||||
// TODO(kainino@chromium.org): Check for a current render pass
|
constexpr ValidationAspects requiredAspects = 1 << VALIDATION_ASPECT_PIPELINE |
|
||||||
constexpr ValidationAspects requiredAspects =
|
1 << VALIDATION_ASPECT_BIND_GROUPS |
|
||||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_PASS
|
1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
|
||||||
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
|
|
||||||
if ((requiredAspects & ~mAspects).none()) {
|
if ((requiredAspects & ~mAspects).none()) {
|
||||||
// Fast return-true path if everything is good
|
// Fast return-true path if everything is good
|
||||||
return true;
|
return true;
|
||||||
|
@ -97,9 +83,8 @@ namespace backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::ValidateCanDrawElements() {
|
bool CommandBufferStateTracker::ValidateCanDrawElements() {
|
||||||
// TODO(kainino@chromium.org): Check for a current render pass
|
|
||||||
constexpr ValidationAspects requiredAspects =
|
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;
|
1 << VALIDATION_ASPECT_VERTEX_BUFFERS | 1 << VALIDATION_ASPECT_INDEX_BUFFER;
|
||||||
if ((requiredAspects & ~mAspects).none()) {
|
if ((requiredAspects & ~mAspects).none()) {
|
||||||
// Fast return-true path if everything is good
|
// Fast return-true path if everything is good
|
||||||
|
@ -113,72 +98,7 @@ namespace backend {
|
||||||
return RevalidateCanDraw();
|
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) {
|
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())) {
|
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||||
TextureBase* texture = info->GetColorAttachment(i).view->GetTexture();
|
TextureBase* texture = info->GetColorAttachment(i).view->GetTexture();
|
||||||
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
||||||
|
@ -200,50 +120,21 @@ namespace backend {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::EndRenderPass() {
|
void CommandBufferStateTracker::EndPass() {
|
||||||
if (mCurrentRenderPass == nullptr) {
|
|
||||||
mBuilder->HandleError("No render pass is currently active");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything in mTexturesAttached should be for the current render pass.
|
// Everything in mTexturesAttached should be for the current render pass.
|
||||||
mTexturesAttached.clear();
|
mTexturesAttached.clear();
|
||||||
|
|
||||||
mInputsSet.reset();
|
mInputsSet.reset();
|
||||||
UnsetPipeline();
|
mAspects = 0;
|
||||||
|
mBindgroups.fill(nullptr);
|
||||||
mAspects.reset(VALIDATION_ASPECT_RENDER_PASS);
|
|
||||||
mCurrentRenderPass = nullptr;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) {
|
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);
|
SetPipelineCommon(pipeline);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
|
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;
|
mLastRenderPipeline = pipeline;
|
||||||
SetPipelineCommon(pipeline);
|
SetPipelineCommon(pipeline);
|
||||||
return true;
|
return true;
|
||||||
|
@ -419,9 +310,7 @@ namespace backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::HavePipeline() const {
|
bool CommandBufferStateTracker::HavePipeline() const {
|
||||||
constexpr ValidationAspects pipelineAspects =
|
return mAspects[VALIDATION_ASPECT_PIPELINE];
|
||||||
1 << VALIDATION_ASPECT_COMPUTE_PIPELINE | 1 << VALIDATION_ASPECT_RENDER_PIPELINE;
|
|
||||||
return (mAspects & pipelineAspects).any();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::ValidateBindGroupUsages(BindGroupBase* group) const {
|
bool CommandBufferStateTracker::ValidateBindGroupUsages(BindGroupBase* group) const {
|
||||||
|
@ -472,7 +361,7 @@ namespace backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandBufferStateTracker::RevalidateCanDraw() {
|
bool CommandBufferStateTracker::RevalidateCanDraw() {
|
||||||
if (!mAspects[VALIDATION_ASPECT_RENDER_PIPELINE]) {
|
if (!mAspects[VALIDATION_ASPECT_PIPELINE]) {
|
||||||
mBuilder->HandleError("No active render pipeline");
|
mBuilder->HandleError("No active render pipeline");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -491,6 +380,8 @@ namespace backend {
|
||||||
void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
|
void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
|
||||||
PipelineLayoutBase* layout = pipeline->GetLayout();
|
PipelineLayoutBase* layout = pipeline->GetLayout();
|
||||||
|
|
||||||
|
mAspects.set(VALIDATION_ASPECT_PIPELINE);
|
||||||
|
|
||||||
mAspects.reset(VALIDATION_ASPECT_BIND_GROUPS);
|
mAspects.reset(VALIDATION_ASPECT_BIND_GROUPS);
|
||||||
mAspects.reset(VALIDATION_ASPECT_VERTEX_BUFFERS);
|
mAspects.reset(VALIDATION_ASPECT_VERTEX_BUFFERS);
|
||||||
// Reset bindgroups but mark unused bindgroups as valid
|
// Reset bindgroups but mark unused bindgroups as valid
|
||||||
|
@ -504,12 +395,4 @@ namespace backend {
|
||||||
mLastPipeline = pipeline;
|
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
|
} // namespace backend
|
||||||
|
|
|
@ -29,21 +29,16 @@ namespace backend {
|
||||||
explicit CommandBufferStateTracker(CommandBufferBuilder* builder);
|
explicit CommandBufferStateTracker(CommandBufferBuilder* builder);
|
||||||
|
|
||||||
// Non-state-modifying validation functions
|
// Non-state-modifying validation functions
|
||||||
bool HaveRenderPass() const;
|
|
||||||
bool ValidateCanCopy() const;
|
bool ValidateCanCopy() const;
|
||||||
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
|
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
|
||||||
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
|
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
|
||||||
bool ValidateCanDispatch();
|
bool ValidateCanDispatch();
|
||||||
bool ValidateCanDrawArrays();
|
bool ValidateCanDrawArrays();
|
||||||
bool ValidateCanDrawElements();
|
bool ValidateCanDrawElements();
|
||||||
bool ValidateEndCommandBuffer() const;
|
|
||||||
bool ValidateSetPushConstants(nxt::ShaderStageBit stages);
|
|
||||||
|
|
||||||
// State-modifying methods
|
// State-modifying methods
|
||||||
bool BeginComputePass();
|
void EndPass();
|
||||||
bool EndComputePass();
|
|
||||||
bool BeginRenderPass(RenderPassDescriptorBase* info);
|
bool BeginRenderPass(RenderPassDescriptorBase* info);
|
||||||
bool EndRenderPass();
|
|
||||||
bool SetComputePipeline(ComputePipelineBase* pipeline);
|
bool SetComputePipeline(ComputePipelineBase* pipeline);
|
||||||
bool SetRenderPipeline(RenderPipelineBase* pipeline);
|
bool SetRenderPipeline(RenderPipelineBase* pipeline);
|
||||||
bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
|
bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
|
||||||
|
@ -58,17 +53,13 @@ namespace backend {
|
||||||
// command buffer.
|
// command buffer.
|
||||||
std::set<BufferBase*> mBuffersTransitioned;
|
std::set<BufferBase*> mBuffersTransitioned;
|
||||||
std::set<TextureBase*> mTexturesTransitioned;
|
std::set<TextureBase*> mTexturesTransitioned;
|
||||||
std::set<TextureBase*> mTexturesAttached;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum ValidationAspect {
|
enum ValidationAspect {
|
||||||
VALIDATION_ASPECT_RENDER_PIPELINE,
|
VALIDATION_ASPECT_PIPELINE,
|
||||||
VALIDATION_ASPECT_COMPUTE_PIPELINE,
|
|
||||||
VALIDATION_ASPECT_BIND_GROUPS,
|
VALIDATION_ASPECT_BIND_GROUPS,
|
||||||
VALIDATION_ASPECT_VERTEX_BUFFERS,
|
VALIDATION_ASPECT_VERTEX_BUFFERS,
|
||||||
VALIDATION_ASPECT_INDEX_BUFFER,
|
VALIDATION_ASPECT_INDEX_BUFFER,
|
||||||
VALIDATION_ASPECT_RENDER_PASS,
|
|
||||||
VALIDATION_ASPECT_COMPUTE_PASS,
|
|
||||||
|
|
||||||
VALIDATION_ASPECT_COUNT
|
VALIDATION_ASPECT_COUNT
|
||||||
};
|
};
|
||||||
|
@ -91,7 +82,6 @@ namespace backend {
|
||||||
bool RevalidateCanDraw();
|
bool RevalidateCanDraw();
|
||||||
|
|
||||||
void SetPipelineCommon(PipelineBase* pipeline);
|
void SetPipelineCommon(PipelineBase* pipeline);
|
||||||
void UnsetPipeline();
|
|
||||||
|
|
||||||
CommandBufferBuilder* mBuilder;
|
CommandBufferBuilder* mBuilder;
|
||||||
|
|
||||||
|
@ -105,8 +95,7 @@ namespace backend {
|
||||||
|
|
||||||
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
|
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
|
||||||
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
|
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
|
||||||
|
std::set<TextureBase*> mTexturesAttached;
|
||||||
RenderPassDescriptorBase* mCurrentRenderPass = nullptr;
|
|
||||||
};
|
};
|
||||||
} // namespace backend
|
} // namespace backend
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue