1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/CommandBufferStateTracker.h" 16 17 #include "common/Assert.h" 18 #include "common/BitSetIterator.h" 19 #include "dawn_native/BindGroup.h" 20 #include "dawn_native/ComputePipeline.h" 21 #include "dawn_native/Forward.h" 22 #include "dawn_native/PipelineLayout.h" 23 #include "dawn_native/RenderPipeline.h" 24 25 namespace dawn_native { 26 27 enum ValidationAspect { 28 VALIDATION_ASPECT_PIPELINE, 29 VALIDATION_ASPECT_BIND_GROUPS, 30 VALIDATION_ASPECT_VERTEX_BUFFERS, 31 VALIDATION_ASPECT_INDEX_BUFFER, 32 33 VALIDATION_ASPECT_COUNT 34 }; 35 static_assert(VALIDATION_ASPECT_COUNT == CommandBufferStateTracker::kNumAspects, ""); 36 37 static constexpr CommandBufferStateTracker::ValidationAspects kDispatchAspects = 38 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS; 39 40 static constexpr CommandBufferStateTracker::ValidationAspects kDrawAspects = 41 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS | 42 1 << VALIDATION_ASPECT_VERTEX_BUFFERS; 43 44 static constexpr CommandBufferStateTracker::ValidationAspects kDrawIndexedAspects = 45 1 << VALIDATION_ASPECT_PIPELINE | 1 << VALIDATION_ASPECT_BIND_GROUPS | 46 1 << VALIDATION_ASPECT_VERTEX_BUFFERS | 1 << VALIDATION_ASPECT_INDEX_BUFFER; 47 48 static constexpr CommandBufferStateTracker::ValidationAspects kLazyAspects = 49 1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS; 50 ValidateCanDispatch()51 MaybeError CommandBufferStateTracker::ValidateCanDispatch() { 52 return ValidateOperation(kDispatchAspects); 53 } 54 ValidateCanDraw()55 MaybeError CommandBufferStateTracker::ValidateCanDraw() { 56 return ValidateOperation(kDrawAspects); 57 } 58 ValidateCanDrawIndexed()59 MaybeError CommandBufferStateTracker::ValidateCanDrawIndexed() { 60 return ValidateOperation(kDrawIndexedAspects); 61 } 62 ValidateOperation(ValidationAspects requiredAspects)63 MaybeError CommandBufferStateTracker::ValidateOperation(ValidationAspects requiredAspects) { 64 // Fast return-true path if everything is good 65 ValidationAspects missingAspects = requiredAspects & ~mAspects; 66 if (missingAspects.none()) { 67 return {}; 68 } 69 70 // Generate an error immediately if a non-lazy aspect is missing as computing lazy aspects 71 // requires the pipeline to be set. 72 if ((missingAspects & ~kLazyAspects).any()) { 73 return GenerateAspectError(missingAspects); 74 } 75 76 RecomputeLazyAspects(missingAspects); 77 78 missingAspects = requiredAspects & ~mAspects; 79 if (missingAspects.any()) { 80 return GenerateAspectError(missingAspects); 81 } 82 83 return {}; 84 } 85 RecomputeLazyAspects(ValidationAspects aspects)86 void CommandBufferStateTracker::RecomputeLazyAspects(ValidationAspects aspects) { 87 ASSERT(mAspects[VALIDATION_ASPECT_PIPELINE]); 88 ASSERT((aspects & ~kLazyAspects).none()); 89 90 if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) { 91 bool matches = true; 92 93 for (uint32_t i : IterateBitSet(mLastPipelineLayout->GetBindGroupLayoutsMask())) { 94 if (mBindgroups[i] == nullptr || 95 mLastPipelineLayout->GetBindGroupLayout(i) != mBindgroups[i]->GetLayout()) { 96 matches = false; 97 break; 98 } 99 } 100 101 if (matches) { 102 mAspects.set(VALIDATION_ASPECT_BIND_GROUPS); 103 } 104 } 105 106 if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) { 107 ASSERT(mLastRenderPipeline != nullptr); 108 109 auto requiredInputs = mLastRenderPipeline->GetInputsSetMask(); 110 if ((mInputsSet & requiredInputs) == requiredInputs) { 111 mAspects.set(VALIDATION_ASPECT_VERTEX_BUFFERS); 112 } 113 } 114 } 115 GenerateAspectError(ValidationAspects aspects)116 MaybeError CommandBufferStateTracker::GenerateAspectError(ValidationAspects aspects) { 117 ASSERT(aspects.any()); 118 119 if (aspects[VALIDATION_ASPECT_INDEX_BUFFER]) { 120 return DAWN_VALIDATION_ERROR("Missing index buffer"); 121 } 122 123 if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) { 124 return DAWN_VALIDATION_ERROR("Missing vertex buffer"); 125 } 126 127 if (aspects[VALIDATION_ASPECT_BIND_GROUPS]) { 128 return DAWN_VALIDATION_ERROR("Missing bind group"); 129 } 130 131 if (aspects[VALIDATION_ASPECT_PIPELINE]) { 132 return DAWN_VALIDATION_ERROR("Missing pipeline"); 133 } 134 135 UNREACHABLE(); 136 } 137 SetComputePipeline(ComputePipelineBase * pipeline)138 void CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) { 139 SetPipelineCommon(pipeline); 140 } 141 SetRenderPipeline(RenderPipelineBase * pipeline)142 void CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) { 143 mLastRenderPipeline = pipeline; 144 SetPipelineCommon(pipeline); 145 } 146 SetBindGroup(uint32_t index,BindGroupBase * bindgroup)147 void CommandBufferStateTracker::SetBindGroup(uint32_t index, BindGroupBase* bindgroup) { 148 mBindgroups[index] = bindgroup; 149 } 150 SetIndexBuffer()151 void CommandBufferStateTracker::SetIndexBuffer() { 152 mAspects.set(VALIDATION_ASPECT_INDEX_BUFFER); 153 } 154 SetVertexBuffer(uint32_t start,uint32_t count)155 void CommandBufferStateTracker::SetVertexBuffer(uint32_t start, uint32_t count) { 156 for (uint32_t i = 0; i < count; ++i) { 157 mInputsSet.set(start + i); 158 } 159 } 160 SetPipelineCommon(PipelineBase * pipeline)161 void CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) { 162 mLastPipelineLayout = pipeline->GetLayout(); 163 164 mAspects.set(VALIDATION_ASPECT_PIPELINE); 165 166 // Reset lazy aspects so they get recomputed on the next operation. 167 mAspects &= ~kLazyAspects; 168 } 169 170 } // namespace dawn_native 171