dawn-cmake/src/dawn_native/CommandBufferStateTracker.cpp
Corentin Wallez 6fee61ca9c Make Dawn error macro more explicit and have an "error type"
The error type will help distinguish between validation errors, context
losts and others which should be handled differently.

Take advantage of advantage of this to change DAWN_RETURN_ERROR to
"return DAWN_FOO_ERROR" to have the return be more explicit. Also
removes usage of DAWN_TRY_ASSERT for more explicit checks.

Change-Id: Icbce16b0c8d8eb084b0af2fc132acee776909a36
2018-09-11 07:55:27 -04:00

171 lines
5.9 KiB
C++

// Copyright 2017 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/CommandBufferStateTracker.h"
#include "common/Assert.h"
#include "common/BitSetIterator.h"
#include "dawn_native/BindGroup.h"
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/Forward.h"
#include "dawn_native/InputState.h"
#include "dawn_native/PipelineLayout.h"
#include "dawn_native/RenderPipeline.h"
namespace dawn_native {
enum ValidationAspect {
VALIDATION_ASPECT_PIPELINE,
VALIDATION_ASPECT_BIND_GROUPS,
VALIDATION_ASPECT_VERTEX_BUFFERS,
VALIDATION_ASPECT_INDEX_BUFFER,
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() {
return ValidateOperation(kDrawArraysAspects);
}
MaybeError CommandBufferStateTracker::ValidateCanDrawElements() {
return ValidateOperation(kDrawElementsAspects);
}
MaybeError CommandBufferStateTracker::ValidateOperation(ValidationAspects requiredAspects) {
// Fast return-true path if everything is good
ValidationAspects missingAspects = requiredAspects & ~mAspects;
if (missingAspects.none()) {
return {};
}
// 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);
}
RecomputeLazyAspects(missingAspects);
missingAspects = requiredAspects & ~mAspects;
if (missingAspects.any()) {
return GenerateAspectError(missingAspects);
}
return {};
}
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]) {
return DAWN_VALIDATION_ERROR("Missing index buffer");
}
if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) {
return DAWN_VALIDATION_ERROR("Missing vertex buffer");
}
if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) {
return DAWN_VALIDATION_ERROR("Missing bind group");
}
if (aspects[VALIDATION_ASPECT_PIPELINE]) {
return DAWN_VALIDATION_ERROR("Missing pipeline");
}
UNREACHABLE();
}
void CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) {
SetPipelineCommon(pipeline);
}
void CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
mLastRenderPipeline = pipeline;
SetPipelineCommon(pipeline);
}
void CommandBufferStateTracker::SetBindGroup(uint32_t index, BindGroupBase* bindgroup) {
mBindgroups[index] = bindgroup;
}
void CommandBufferStateTracker::SetIndexBuffer() {
mAspects.set(VALIDATION_ASPECT_INDEX_BUFFER);
}
void CommandBufferStateTracker::SetVertexBuffer(uint32_t start, uint32_t count) {
for (uint32_t i = 0; i < count; ++i) {
mInputsSet.set(start + i);
}
}
void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
mLastPipelineLayout = pipeline->GetLayout();
mAspects.set(VALIDATION_ASPECT_PIPELINE);
// Reset lazy aspects so they get recomputed on the next operation.
mAspects &= ~kLazyAspects;
}
} // namespace dawn_native