Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLVkMeshCompiler.h"
24 :
25 : #include "XLCoreMesh.h"
26 : #include "XLVkAllocator.h"
27 : #include "XLVkTransferQueue.h"
28 : #include "XLCoreFrameRequest.h"
29 : #include "XLCoreFrameQueue.h"
30 : #include "XLCoreQueue.h"
31 :
32 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
33 :
34 : class MeshCompilerAttachment : public core::GenericAttachment {
35 : public:
36 : virtual ~MeshCompilerAttachment();
37 :
38 : virtual Rc<AttachmentHandle> makeFrameHandle(const FrameQueue &) override;
39 : };
40 :
41 : class MeshCompilerAttachmentHandle : public core::AttachmentHandle {
42 : public:
43 : virtual ~MeshCompilerAttachmentHandle();
44 :
45 : virtual bool setup(FrameQueue &handle, Function<void(bool)> &&) override;
46 : virtual void submitInput(FrameQueue &, Rc<core::AttachmentInputData> &&, Function<void(bool)> &&) override;
47 :
48 0 : virtual const Rc<core::MeshInputData> &getInputData() const { return _inputData; }
49 0 : virtual const Rc<core::MeshSet> &getMeshSet() const { return _originSet; }
50 :
51 : protected:
52 : Rc<core::MeshInputData> _inputData;
53 : Rc<core::MeshSet> _originSet;
54 : };
55 :
56 : class MeshCompilerPass : public QueuePass {
57 : public:
58 : virtual ~MeshCompilerPass();
59 :
60 : virtual bool init(QueuePassBuilder &, const AttachmentData *);
61 :
62 : virtual Rc<QueuePassHandle> makeFrameHandle(const FrameQueue &) override;
63 :
64 0 : const AttachmentData *getMeshAttachment() const { return _meshAttachment; }
65 :
66 : protected:
67 : using QueuePass::init;
68 :
69 : const AttachmentData *_meshAttachment = nullptr;
70 : };
71 :
72 : class MeshCompilerPassHandle : public QueuePassHandle {
73 : public:
74 : virtual ~MeshCompilerPassHandle();
75 :
76 : virtual bool prepare(FrameQueue &, Function<void(bool)> &&) override;
77 : virtual void finalize(FrameQueue &, bool successful) override;
78 :
79 : virtual QueueOperations getQueueOps() const override;
80 :
81 : protected:
82 : virtual Vector<const CommandBuffer *> doPrepareCommands(FrameHandle &) override;
83 : virtual void doSubmitted(FrameHandle &, Function<void(bool)> &&, bool, Rc<Fence> &&) override;
84 : virtual void doComplete(FrameQueue &, Function<void(bool)> &&, bool) override;
85 :
86 : bool loadPersistent(core::MeshIndex *);
87 :
88 : Rc<core::MeshSet> _outputData;
89 : MeshCompilerAttachmentHandle *_meshAttachment;
90 : };
91 :
92 0 : MeshCompiler::~MeshCompiler() { }
93 :
94 0 : bool MeshCompiler::init() {
95 : using namespace core;
96 :
97 0 : Queue::Builder builder("MeshCompiler");
98 :
99 0 : auto attachment = builder.addAttachemnt("", [] (AttachmentBuilder &attachmentBuilder) -> Rc<Attachment> {
100 0 : attachmentBuilder.defineAsInput();
101 0 : attachmentBuilder.defineAsOutput();
102 0 : return Rc<MeshCompilerAttachment>::create(attachmentBuilder);
103 0 : });
104 :
105 0 : builder.addPass("MeshPass", PassType::Transfer, RenderOrdering(0), [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
106 0 : return Rc<MeshCompilerPass>::create(passBuilder, attachment);
107 : });
108 :
109 0 : if (core::Queue::init(move(builder))) {
110 0 : _attachment = attachment;
111 0 : return true;
112 : }
113 0 : return false;
114 0 : }
115 :
116 0 : bool MeshCompiler::inProgress(const MeshAttachment *a) const {
117 0 : auto it = _inProgress.find(a);
118 0 : if (it != _inProgress.end()) {
119 0 : return true;
120 : }
121 0 : return false;
122 : }
123 :
124 0 : void MeshCompiler::setInProgress(const MeshAttachment *a) {
125 0 : _inProgress.emplace(a);
126 0 : }
127 :
128 0 : void MeshCompiler::dropInProgress(const MeshAttachment *a) {
129 0 : _inProgress.erase(a);
130 0 : }
131 :
132 0 : bool MeshCompiler::hasRequest(const MeshAttachment *a) const {
133 0 : auto it = _requests.find(a);
134 0 : if (it != _requests.end()) {
135 0 : return true;
136 : }
137 0 : return false;
138 : }
139 :
140 0 : void MeshCompiler::appendRequest(const MeshAttachment *a, Rc<MeshInputData> &&req,
141 : Vector<Rc<core::DependencyEvent>> &&deps) {
142 0 : auto it = _requests.find(a);
143 0 : if (it == _requests.end()) {
144 0 : it = _requests.emplace(a, MeshRequest()).first;
145 : }
146 :
147 0 : for (auto &rem : req->meshesToRemove) {
148 0 : auto m = it->second.toAdd.find(rem);
149 0 : if (m != it->second.toAdd.end()) {
150 0 : it->second.toAdd.erase(m);
151 : }
152 :
153 0 : it->second.toRemove.emplace(rem);
154 : }
155 :
156 0 : for (auto &m : req->meshesToAdd) {
157 0 : auto iit = it->second.toAdd.find(m);
158 0 : if (iit == it->second.toAdd.end()) {
159 0 : it->second.toAdd.emplace(m);
160 : }
161 0 : auto v = it->second.toRemove.find(m);
162 0 : if (v != it->second.toRemove.end()) {
163 0 : it->second.toRemove.erase(v);
164 : }
165 : }
166 :
167 0 : if (it->second.deps.empty()) {
168 0 : it->second.deps = move(deps);
169 : } else {
170 0 : for (auto &iit : deps) {
171 0 : it->second.deps.emplace_back(move(iit));
172 : }
173 : }
174 0 : }
175 :
176 0 : void MeshCompiler::clearRequests() {
177 0 : _requests.clear();
178 0 : }
179 :
180 0 : auto MeshCompiler::makeRequest(Rc<core::MeshInputData> &&input,
181 : Vector<Rc<core::DependencyEvent>> &&deps) -> Rc<FrameRequest> {
182 0 : auto req = Rc<FrameRequest>::create(this);
183 0 : req->addInput(_attachment, move(input));
184 0 : req->addSignalDependencies(move(deps));
185 0 : return req;
186 0 : }
187 :
188 0 : void MeshCompiler::runMeshCompilationFrame(core::Loop &loop, Rc<MeshInputData> &&req,
189 : Vector<Rc<core::DependencyEvent>> &&deps) {
190 0 : auto targetAttachment = req->attachment;
191 :
192 0 : auto h = loop.makeFrame(makeRequest(move(req), move(deps)), 0);
193 0 : h->setCompleteCallback([this, targetAttachment] (FrameHandle &handle) {
194 0 : auto reqIt = _requests.find(targetAttachment);
195 0 : if (reqIt != _requests.end()) {
196 0 : if (handle.getLoop()->isRunning()) {
197 0 : auto deps = move(reqIt->second.deps);
198 0 : Rc<MeshInputData> req = Rc<MeshInputData>::alloc();
199 0 : req->attachment = targetAttachment;
200 0 : req->meshesToAdd.reserve(reqIt->second.toAdd.size());
201 0 : for (auto &m : reqIt->second.toAdd) {
202 0 : req->meshesToAdd.emplace_back(m);
203 : }
204 0 : req->meshesToRemove.reserve(reqIt->second.toRemove.size());
205 0 : for (auto &m : reqIt->second.toRemove) {
206 0 : req->meshesToRemove.emplace_back(m);
207 : }
208 0 : _requests.erase(reqIt);
209 :
210 0 : runMeshCompilationFrame(*handle.getLoop(), move(req), move(deps));
211 0 : } else {
212 0 : clearRequests();
213 0 : dropInProgress(targetAttachment);
214 : }
215 : } else {
216 0 : dropInProgress(targetAttachment);
217 : }
218 0 : });
219 0 : h->update(true);
220 0 : }
221 :
222 0 : MeshCompilerAttachment::~MeshCompilerAttachment() { }
223 :
224 0 : auto MeshCompilerAttachment::makeFrameHandle(const FrameQueue &handle) -> Rc<AttachmentHandle> {
225 0 : return Rc<MeshCompilerAttachmentHandle>::create(this, handle);
226 : }
227 :
228 0 : MeshCompilerAttachmentHandle::~MeshCompilerAttachmentHandle() { }
229 :
230 0 : bool MeshCompilerAttachmentHandle::setup(FrameQueue &handle, Function<void(bool)> &&cb) {
231 0 : return true;
232 : }
233 :
234 0 : void MeshCompilerAttachmentHandle::submitInput(FrameQueue &q, Rc<core::AttachmentInputData> &&data, Function<void(bool)> &&cb) {
235 0 : auto d = data.cast<core::MeshInputData>();
236 0 : if (!d || q.isFinalized()) {
237 0 : cb(false);
238 : }
239 :
240 0 : q.getFrame()->waitForDependencies(data->waitDependencies, [this, d = move(d), cb = move(cb)] (FrameHandle &handle, bool success) {
241 0 : handle.performOnGlThread([this, d = move(d), cb = move(cb)] (FrameHandle &handle) {
242 0 : _inputData = d;
243 0 : _originSet = _inputData->attachment->getMeshes();
244 0 : cb(true);
245 0 : }, this, true, "MeshCompilerAttachmentHandle::submitInput");
246 0 : });
247 0 : }
248 :
249 0 : MeshCompilerPass::~MeshCompilerPass() { }
250 :
251 0 : bool MeshCompilerPass::init(QueuePassBuilder &passBuilder, const AttachmentData *attachment) {
252 0 : passBuilder.addAttachment(attachment);
253 :
254 0 : if (!QueuePass::init(passBuilder)) {
255 0 : return false;
256 : }
257 :
258 0 : _queueOps = QueueOperations::Transfer;
259 0 : _meshAttachment = attachment;
260 0 : return true;
261 : }
262 :
263 0 : auto MeshCompilerPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
264 0 : return Rc<MeshCompilerPassHandle>::create(*this, handle);
265 : }
266 :
267 0 : MeshCompilerPassHandle::~MeshCompilerPassHandle() { }
268 :
269 0 : bool MeshCompilerPassHandle::prepare(FrameQueue &frame, Function<void(bool)> &&cb) {
270 0 : if (auto a = frame.getAttachment(static_cast<MeshCompilerPass *>(_queuePass.get())->getMeshAttachment())) {
271 0 : _meshAttachment = static_cast<MeshCompilerAttachmentHandle *>(a->handle.get());
272 : }
273 :
274 0 : return QueuePassHandle::prepare(frame, move(cb));
275 : }
276 :
277 0 : void MeshCompilerPassHandle::finalize(FrameQueue &handle, bool successful) {
278 0 : QueuePassHandle::finalize(handle, successful);
279 0 : }
280 :
281 0 : QueueOperations MeshCompilerPassHandle::getQueueOps() const {
282 0 : return QueuePassHandle::getQueueOps();
283 : }
284 :
285 0 : Vector<const CommandBuffer *> MeshCompilerPassHandle::doPrepareCommands(FrameHandle &handle) {
286 0 : auto &allocator = _device->getAllocator();
287 0 : auto memPool = static_cast<DeviceFrameHandle &>(handle).getMemPool(this);
288 :
289 0 : auto input = _meshAttachment->getInputData();
290 0 : auto prev = _meshAttachment->getMeshSet();
291 :
292 0 : QueueOperations ops = QueueOperations::None;
293 0 : for (auto &it : input->attachment->getRenderPasses()) {
294 0 : ops |= static_cast<vk::QueuePass *>(it->pass.get())->getQueueOps();
295 0 : }
296 :
297 0 : auto q = _device->getQueueFamily(ops);
298 0 : if (!q) {
299 0 : return Vector<const CommandBuffer *>();
300 : }
301 :
302 0 : auto indexes = _meshAttachment->getMeshSet()->getIndexes();
303 :
304 : do {
305 0 : auto it = indexes.begin();
306 0 : while (it != indexes.end()) {
307 0 : auto iit = std::find(input->meshesToAdd.begin(), input->meshesToAdd.end(), it->index);
308 0 : if (iit != input->meshesToAdd.end()) {
309 0 : input->meshesToAdd.erase(iit);
310 : }
311 :
312 0 : iit = std::find(input->meshesToRemove.begin(), input->meshesToRemove.end(), it->index);
313 0 : if (iit != input->meshesToRemove.end()) {
314 0 : it = indexes.erase(it);
315 : } else {
316 0 : ++ it;
317 : }
318 : }
319 : } while (0);
320 :
321 0 : for (auto &it : input->meshesToAdd) {
322 0 : indexes.emplace_back(core::MeshSet::Index{maxOf<VkDeviceSize>(), maxOf<VkDeviceSize>(), it});
323 : }
324 :
325 0 : uint64_t indexBufferSize = 0;
326 0 : uint64_t vertexBufferSize = 0;
327 :
328 0 : for (auto &it : indexes) {
329 0 : indexBufferSize += it.index->getIndexBufferData()->size;
330 0 : vertexBufferSize += it.index->getVertexBufferData()->size;
331 : }
332 :
333 0 : BufferInfo vertexBufferInfo;
334 0 : BufferInfo indexBufferInfo;
335 :
336 0 : if (prev) {
337 0 : vertexBufferInfo = prev->getVertexBuffer()->getInfo();
338 0 : indexBufferInfo = prev->getIndexBuffer()->getInfo();
339 : } else {
340 0 : vertexBufferInfo = *indexes.front().index->getVertexBufferData();
341 0 : indexBufferInfo = *indexes.front().index->getIndexBufferData();
342 : }
343 :
344 0 : vertexBufferInfo.size = vertexBufferSize;
345 0 : indexBufferInfo.size = indexBufferSize;
346 :
347 0 : auto vertexBuffer = allocator->spawnPersistent(AllocationUsage::DeviceLocal, vertexBufferInfo);
348 0 : auto indexBuffer = allocator->spawnPersistent(AllocationUsage::DeviceLocal, indexBufferInfo);
349 :
350 0 : auto loadBuffer = [] (const core::BufferData *bufferData, Buffer *buf) {
351 0 : if (!bufferData->data.empty()) {
352 0 : buf->setData(bufferData->data);
353 : } else {
354 0 : buf->map([&] (uint8_t *ptr, VkDeviceSize size) {
355 0 : bufferData->writeData(ptr, size);
356 0 : });
357 : }
358 0 : return buf;
359 : };
360 :
361 0 : auto writeBufferCopy = [&memPool, &loadBuffer] (CommandBuffer &buf, const core::BufferData *bufferData, Buffer *targetBuffer,
362 0 : VkDeviceSize targetOffset, VkDeviceSize originOffset, Buffer *originBuffer) -> VkDeviceSize {
363 0 : Buffer *sourceBuffer = nullptr;
364 0 : VkDeviceSize sourceOffset = 0;
365 0 : VkDeviceSize targetSize = bufferData->size;
366 :
367 0 : if (originBuffer && originOffset != maxOf<VkDeviceSize>()) {
368 0 : sourceBuffer = originBuffer;
369 0 : sourceOffset = originOffset;
370 : } else {
371 0 : auto resourceBuffer = bufferData->buffer.get();
372 0 : if (!resourceBuffer) {
373 0 : auto tmp = memPool->spawn(AllocationUsage::HostTransitionSource, bufferData);
374 0 : resourceBuffer = loadBuffer(bufferData, tmp);
375 0 : }
376 :
377 0 : if (resourceBuffer) {
378 0 : sourceBuffer = static_cast<Buffer *>(resourceBuffer);
379 0 : sourceOffset = 0;
380 : }
381 : }
382 :
383 0 : if (sourceBuffer) {
384 0 : buf.cmdCopyBuffer(sourceBuffer, targetBuffer, sourceOffset, targetOffset, targetSize);
385 0 : return targetSize;
386 : }
387 0 : return 0;
388 0 : };
389 :
390 0 : auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
391 0 : uint64_t targetIndexOffset = 0;
392 0 : uint64_t targetVertexOffset = 0;
393 :
394 0 : Buffer *prevIndexBuffer = nullptr;
395 0 : Buffer *prevVertexBuffer = nullptr;
396 :
397 0 : if (_pool->getFamilyIdx() == q->index) {
398 0 : prevIndexBuffer = static_cast<Buffer *>(prev->getIndexBuffer().get());
399 0 : prevVertexBuffer = static_cast<Buffer *>(prev->getVertexBuffer().get());
400 : }
401 :
402 0 : for (auto &it : indexes) {
403 0 : if (_pool->getFamilyIdx() != q->index) {
404 0 : if (!loadPersistent(it.index)) {
405 0 : continue;
406 : }
407 : }
408 :
409 0 : auto indexBufferSize = writeBufferCopy(buf, it.index->getIndexBufferData(), indexBuffer,
410 : targetIndexOffset, it.indexOffset, prevIndexBuffer);
411 0 : if (indexBufferSize > 0) {
412 0 : it.indexOffset = targetIndexOffset;
413 0 : targetIndexOffset += indexBufferSize;
414 : } else {
415 0 : it.indexOffset = maxOf<VkDeviceSize>();
416 : }
417 :
418 0 : auto vertexBufferSize = writeBufferCopy(buf, it.index->getVertexBufferData(), vertexBuffer,
419 : targetVertexOffset, it.vertexOffset, prevVertexBuffer);
420 0 : if (vertexBufferSize > 0) {
421 0 : it.vertexOffset = targetIndexOffset;
422 0 : targetIndexOffset += vertexBufferSize;
423 : } else {
424 0 : it.vertexOffset = maxOf<VkDeviceSize>();
425 : }
426 : }
427 0 : return true;
428 : });
429 :
430 0 : if (buf) {
431 0 : _outputData = Rc<core::MeshSet>::create(move(indexes), indexBuffer, vertexBuffer);
432 :
433 0 : return Vector<const CommandBuffer *>{buf};
434 : }
435 0 : return Vector<const CommandBuffer *>();
436 0 : }
437 :
438 0 : void MeshCompilerPassHandle::doSubmitted(FrameHandle &frame, Function<void(bool)> &&func, bool success, Rc<Fence> &&fence) {
439 0 : if (success) {
440 0 : _meshAttachment->getInputData()->attachment->setMeshes(move(_outputData));
441 : }
442 :
443 0 : QueuePassHandle::doSubmitted(frame, move(func), success, move(fence));
444 0 : frame.signalDependencies(success);
445 0 : }
446 :
447 0 : void MeshCompilerPassHandle::doComplete(FrameQueue &queue, Function<void(bool)> &&func, bool success) {
448 0 : QueuePassHandle::doComplete(queue, move(func), success);
449 0 : }
450 :
451 0 : bool MeshCompilerPassHandle::loadPersistent(core::MeshIndex *index) {
452 0 : if (!index->isCompiled()) {
453 0 : auto res = Rc<TransferResource>::create(_device->getAllocator(), index);
454 0 : if (res->initialize(AllocationUsage::HostTransitionSource) && res->compile()) {
455 0 : return true;
456 : }
457 0 : return false;
458 0 : }
459 0 : return false;
460 : }
461 :
462 : }
|