• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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/IndirectDrawMetadata.h"
16 
17 #include "common/Constants.h"
18 #include "common/RefCounted.h"
19 #include "dawn_native/IndirectDrawValidationEncoder.h"
20 #include "dawn_native/Limits.h"
21 #include "dawn_native/RenderBundle.h"
22 
23 #include <algorithm>
24 #include <utility>
25 
26 namespace dawn_native {
27 
ComputeMaxIndirectValidationBatchOffsetRange(const CombinedLimits & limits)28     uint32_t ComputeMaxIndirectValidationBatchOffsetRange(const CombinedLimits& limits) {
29         return limits.v1.maxStorageBufferBindingSize - limits.v1.minStorageBufferOffsetAlignment -
30                kDrawIndexedIndirectSize;
31     }
32 
IndexedIndirectBufferValidationInfo(BufferBase * indirectBuffer)33     IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::IndexedIndirectBufferValidationInfo(
34         BufferBase* indirectBuffer)
35         : mIndirectBuffer(indirectBuffer) {
36     }
37 
AddIndexedIndirectDraw(uint32_t maxDrawCallsPerIndirectValidationBatch,uint32_t maxBatchOffsetRange,IndexedIndirectDraw draw)38     void IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::AddIndexedIndirectDraw(
39         uint32_t maxDrawCallsPerIndirectValidationBatch,
40         uint32_t maxBatchOffsetRange,
41         IndexedIndirectDraw draw) {
42         const uint64_t newOffset = draw.clientBufferOffset;
43         auto it = mBatches.begin();
44         while (it != mBatches.end()) {
45             IndexedIndirectValidationBatch& batch = *it;
46             if (batch.draws.size() >= maxDrawCallsPerIndirectValidationBatch) {
47                 // This batch is full. If its minOffset is to the right of the new offset, we can
48                 // just insert a new batch here.
49                 if (newOffset < batch.minOffset) {
50                     break;
51                 }
52 
53                 // Otherwise keep looking.
54                 ++it;
55                 continue;
56             }
57 
58             if (newOffset >= batch.minOffset && newOffset <= batch.maxOffset) {
59                 batch.draws.push_back(std::move(draw));
60                 return;
61             }
62 
63             if (newOffset < batch.minOffset && batch.maxOffset - newOffset <= maxBatchOffsetRange) {
64                 // We can extend this batch to the left in order to fit the new offset.
65                 batch.minOffset = newOffset;
66                 batch.draws.push_back(std::move(draw));
67                 return;
68             }
69 
70             if (newOffset > batch.maxOffset && newOffset - batch.minOffset <= maxBatchOffsetRange) {
71                 // We can extend this batch to the right in order to fit the new offset.
72                 batch.maxOffset = newOffset;
73                 batch.draws.push_back(std::move(draw));
74                 return;
75             }
76 
77             if (newOffset < batch.minOffset) {
78                 // We want to insert a new batch just before this one.
79                 break;
80             }
81 
82             ++it;
83         }
84 
85         IndexedIndirectValidationBatch newBatch;
86         newBatch.minOffset = newOffset;
87         newBatch.maxOffset = newOffset;
88         newBatch.draws.push_back(std::move(draw));
89 
90         mBatches.insert(it, std::move(newBatch));
91     }
92 
AddBatch(uint32_t maxDrawCallsPerIndirectValidationBatch,uint32_t maxBatchOffsetRange,const IndexedIndirectValidationBatch & newBatch)93     void IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::AddBatch(
94         uint32_t maxDrawCallsPerIndirectValidationBatch,
95         uint32_t maxBatchOffsetRange,
96         const IndexedIndirectValidationBatch& newBatch) {
97         auto it = mBatches.begin();
98         while (it != mBatches.end()) {
99             IndexedIndirectValidationBatch& batch = *it;
100             uint64_t min = std::min(newBatch.minOffset, batch.minOffset);
101             uint64_t max = std::max(newBatch.maxOffset, batch.maxOffset);
102             if (max - min <= maxBatchOffsetRange && batch.draws.size() + newBatch.draws.size() <=
103                                                         maxDrawCallsPerIndirectValidationBatch) {
104                 // This batch fits within the limits of an existing batch. Merge it.
105                 batch.minOffset = min;
106                 batch.maxOffset = max;
107                 batch.draws.insert(batch.draws.end(), newBatch.draws.begin(), newBatch.draws.end());
108                 return;
109             }
110 
111             if (newBatch.minOffset < batch.minOffset) {
112                 break;
113             }
114 
115             ++it;
116         }
117         mBatches.push_back(newBatch);
118     }
119 
120     const std::vector<IndirectDrawMetadata::IndexedIndirectValidationBatch>&
GetBatches() const121     IndirectDrawMetadata::IndexedIndirectBufferValidationInfo::GetBatches() const {
122         return mBatches;
123     }
124 
IndirectDrawMetadata(const CombinedLimits & limits)125     IndirectDrawMetadata::IndirectDrawMetadata(const CombinedLimits& limits)
126         : mMaxDrawCallsPerBatch(ComputeMaxDrawCallsPerIndirectValidationBatch(limits)),
127           mMaxBatchOffsetRange(ComputeMaxIndirectValidationBatchOffsetRange(limits)) {
128     }
129 
130     IndirectDrawMetadata::~IndirectDrawMetadata() = default;
131 
132     IndirectDrawMetadata::IndirectDrawMetadata(IndirectDrawMetadata&&) = default;
133 
134     IndirectDrawMetadata& IndirectDrawMetadata::operator=(IndirectDrawMetadata&&) = default;
135 
136     IndirectDrawMetadata::IndexedIndirectBufferValidationInfoMap*
GetIndexedIndirectBufferValidationInfo()137     IndirectDrawMetadata::GetIndexedIndirectBufferValidationInfo() {
138         return &mIndexedIndirectBufferValidationInfo;
139     }
140 
AddBundle(RenderBundleBase * bundle)141     void IndirectDrawMetadata::AddBundle(RenderBundleBase* bundle) {
142         auto result = mAddedBundles.insert(bundle);
143         if (!result.second) {
144             return;
145         }
146 
147         for (const auto& entry :
148              bundle->GetIndirectDrawMetadata().mIndexedIndirectBufferValidationInfo) {
149             const IndexedIndirectConfig& config = entry.first;
150             auto it = mIndexedIndirectBufferValidationInfo.lower_bound(config);
151             if (it != mIndexedIndirectBufferValidationInfo.end() && it->first == config) {
152                 // We already have batches for the same config. Merge the new ones in.
153                 for (const IndexedIndirectValidationBatch& batch : entry.second.GetBatches()) {
154                     it->second.AddBatch(mMaxDrawCallsPerBatch, mMaxBatchOffsetRange, batch);
155                 }
156             } else {
157                 mIndexedIndirectBufferValidationInfo.emplace_hint(it, config, entry.second);
158             }
159         }
160     }
161 
AddIndexedIndirectDraw(wgpu::IndexFormat indexFormat,uint64_t indexBufferSize,BufferBase * indirectBuffer,uint64_t indirectOffset,DrawIndexedIndirectCmd * cmd)162     void IndirectDrawMetadata::AddIndexedIndirectDraw(wgpu::IndexFormat indexFormat,
163                                                       uint64_t indexBufferSize,
164                                                       BufferBase* indirectBuffer,
165                                                       uint64_t indirectOffset,
166                                                       DrawIndexedIndirectCmd* cmd) {
167         uint64_t numIndexBufferElements;
168         switch (indexFormat) {
169             case wgpu::IndexFormat::Uint16:
170                 numIndexBufferElements = indexBufferSize / 2;
171                 break;
172             case wgpu::IndexFormat::Uint32:
173                 numIndexBufferElements = indexBufferSize / 4;
174                 break;
175             case wgpu::IndexFormat::Undefined:
176                 UNREACHABLE();
177         }
178 
179         const IndexedIndirectConfig config(indirectBuffer, numIndexBufferElements);
180         auto it = mIndexedIndirectBufferValidationInfo.find(config);
181         if (it == mIndexedIndirectBufferValidationInfo.end()) {
182             auto result = mIndexedIndirectBufferValidationInfo.emplace(
183                 config, IndexedIndirectBufferValidationInfo(indirectBuffer));
184             it = result.first;
185         }
186 
187         IndexedIndirectDraw draw;
188         draw.clientBufferOffset = indirectOffset;
189         draw.cmd = cmd;
190         it->second.AddIndexedIndirectDraw(mMaxDrawCallsPerBatch, mMaxBatchOffsetRange,
191                                           std::move(draw));
192     }
193 
194 }  // namespace dawn_native
195