LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkMeshCompiler.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 240 0.0 %
Date: 2024-05-12 00:16:13 Functions: 0 43 0.0 %

          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             : }

Generated by: LCOV version 1.14