LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkMaterialCompiler.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 124 197 62.9 %
Date: 2024-05-12 00:16:13 Functions: 36 40 90.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2021-2022 Roman Katuntsev <sbkarr@stappler.org>
       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 "XLVkMaterialCompiler.h"
      24             : #include "XLVkObject.h"
      25             : #include "XLVkQueuePass.h"
      26             : #include "XLVkDeviceQueue.h"
      27             : #include "XLCoreFrameRequest.h"
      28             : #include "XLCoreFrameQueue.h"
      29             : 
      30             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      31             : 
      32             : class MaterialCompilationAttachment : public core::GenericAttachment {
      33             : public:
      34             :         virtual ~MaterialCompilationAttachment();
      35             : 
      36             :         virtual Rc<AttachmentHandle> makeFrameHandle(const FrameQueue &) override;
      37             : };
      38             : 
      39             : class MaterialCompilationAttachmentHandle : public core::AttachmentHandle {
      40             : public:
      41             :         virtual ~MaterialCompilationAttachmentHandle();
      42             : 
      43             :         virtual bool setup(FrameQueue &handle, Function<void(bool)> &&) override;
      44             :         virtual void submitInput(FrameQueue &, Rc<core::AttachmentInputData> &&, Function<void(bool)> &&) override;
      45             : 
      46        4772 :         virtual const Rc<core::MaterialInputData> &getInputData() const { return _inputData; }
      47        1193 :         virtual const Rc<core::MaterialSet> &getOriginalSet() const { return _originalSet; }
      48             : 
      49             : protected:
      50             :         Rc<core::MaterialInputData> _inputData;
      51             :         Rc<core::MaterialSet> _originalSet;
      52             : };
      53             : 
      54             : class MaterialCompilationRenderPass : public QueuePass {
      55             : public:
      56             :         virtual ~MaterialCompilationRenderPass();
      57             : 
      58             :         virtual bool init(QueuePassBuilder &, const AttachmentData *);
      59             : 
      60             :         virtual Rc<QueuePassHandle> makeFrameHandle(const FrameQueue &) override;
      61             : 
      62        1193 :         const AttachmentData *getMaterialAttachment() const { return _materialAttachment; }
      63             : 
      64             : protected:
      65             :         using QueuePass::init;
      66             : 
      67             :         const AttachmentData *_materialAttachment = nullptr;
      68             : };
      69             : 
      70             : class MaterialCompilationPassHandle : public QueuePassHandle {
      71             : public:
      72             :         virtual ~MaterialCompilationPassHandle();
      73             : 
      74             :         virtual bool prepare(FrameQueue &, Function<void(bool)> &&) override;
      75             :         virtual void finalize(FrameQueue &, bool successful) override;
      76             : 
      77             : protected:
      78             :         virtual Vector<const CommandBuffer *> doPrepareCommands(FrameHandle &) override;
      79             :         virtual void doSubmitted(FrameHandle &, Function<void(bool)> &&, bool, Rc<Fence> &&) override;
      80             :         virtual void doComplete(FrameQueue &, Function<void(bool)> &&, bool) override;
      81             : 
      82             :         Rc<core::MaterialSet> _outputData;
      83             :         MaterialCompilationAttachmentHandle *_materialAttachment;
      84             : };
      85             : 
      86          84 : MaterialCompiler::~MaterialCompiler() { }
      87             : 
      88          42 : bool MaterialCompiler::init() {
      89             :         using namespace core;
      90             : 
      91          42 :         Queue::Builder builder("MaterialCompiler");
      92             : 
      93          84 :         auto attachment = builder.addAttachemnt("MaterialAttachment", [&] (AttachmentBuilder &attachmentBuilder) -> Rc<Attachment> {
      94          42 :                 attachmentBuilder.defineAsInput();
      95          42 :                 attachmentBuilder.defineAsOutput();
      96          84 :                 return Rc<MaterialCompilationAttachment>::create(attachmentBuilder);
      97          42 :         });
      98             : 
      99          42 :         builder.addPass("MaterialRenderPass", PassType::Transfer, RenderOrdering(0), [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
     100          84 :                 return Rc<MaterialCompilationRenderPass>::create(passBuilder, attachment);
     101             :         });
     102             : 
     103          42 :         if (core::Queue::init(move(builder))) {
     104          42 :                 _attachment = attachment;
     105          42 :                 return true;
     106             :         }
     107           0 :         return false;
     108          42 : }
     109             : 
     110        1193 : bool MaterialCompiler::inProgress(const MaterialAttachment *a) const {
     111        1193 :         auto it = _inProgress.find(a);
     112        1193 :         if (it != _inProgress.end()) {
     113           0 :                 return true;
     114             :         }
     115        1193 :         return false;
     116             : }
     117             : 
     118        1193 : void MaterialCompiler::setInProgress(const MaterialAttachment *a) {
     119        1193 :         _inProgress.emplace(a);
     120        1193 : }
     121             : 
     122        1193 : void MaterialCompiler::dropInProgress(const MaterialAttachment *a) {
     123        1193 :         _inProgress.erase(a);
     124        1193 : }
     125             : 
     126           0 : bool MaterialCompiler::hasRequest(const MaterialAttachment *a) const {
     127           0 :         auto it = _requests.find(a);
     128           0 :         if (it != _requests.end()) {
     129           0 :                 return true;
     130             :         }
     131           0 :         return false;
     132             : }
     133             : 
     134           0 : void MaterialCompiler::appendRequest(const MaterialAttachment *a, Rc<MaterialInputData> &&req,
     135             :                 Vector<Rc<core::DependencyEvent>> &&deps) {
     136           0 :         auto it = _requests.find(a);
     137           0 :         if (it == _requests.end()) {
     138           0 :                 it = _requests.emplace(a, MaterialRequest()).first;
     139             :         }
     140             : 
     141           0 :         for (auto &rem : req->materialsToRemove) {
     142           0 :                 auto m = it->second.materials.find(rem);
     143           0 :                 if (m != it->second.materials.end()) {
     144           0 :                         it->second.materials.erase(m);
     145             :                 }
     146             : 
     147           0 :                 auto d = it->second.dynamic.find(rem);
     148           0 :                 if (d != it->second.dynamic.end()) {
     149           0 :                         it->second.dynamic.erase(d);
     150             :                 }
     151             : 
     152           0 :                 it->second.remove.emplace(rem);
     153             :         }
     154             : 
     155           0 :         for (auto &rem : req->dynamicMaterialsToUpdate) {
     156           0 :                 it->second.dynamic.emplace(rem);
     157             :         }
     158             : 
     159           0 :         for (auto &m : req->materialsToAddOrUpdate) {
     160           0 :                 auto materialId = m->getId();
     161           0 :                 auto iit = it->second.materials.find(materialId);
     162           0 :                 if (iit == it->second.materials.end()) {
     163           0 :                         it->second.materials.emplace(materialId, move(m));
     164             :                 } else {
     165           0 :                         iit->second = move(m);
     166             :                 }
     167           0 :                 auto v = it->second.remove.find(materialId);
     168           0 :                 if (v != it->second.remove.end()) {
     169           0 :                         it->second.remove.erase(v);
     170             :                 }
     171             :         }
     172             : 
     173           0 :         if (it->second.deps.empty()) {
     174           0 :                 it->second.deps = move(deps);
     175             :         } else {
     176           0 :                 for (auto &iit : deps) {
     177           0 :                         it->second.deps.emplace_back(move(iit));
     178             :                 }
     179             :         }
     180             : 
     181           0 :         if (it->second.callback) {
     182           0 :                 it->second.callback = [cb = move(it->second.callback), cb2 = move(req->callback)] {
     183           0 :                         cb();
     184           0 :                         cb2();
     185           0 :                 };
     186             :         } else {
     187           0 :                 it->second.callback = move(req->callback);
     188             :         }
     189           0 : }
     190             : 
     191           0 : void MaterialCompiler::clearRequests() {
     192           0 :         _requests.clear();
     193           0 : }
     194             : 
     195        1193 : auto MaterialCompiler::makeRequest(Rc<MaterialInputData> &&input, Vector<Rc<core::DependencyEvent>> &&deps) -> Rc<FrameRequest> {
     196        1193 :         auto req = Rc<FrameRequest>::create(this);
     197        1193 :         req->addInput(_attachment, move(input));
     198        1193 :         req->addSignalDependencies(move(deps));
     199        1193 :         return req;
     200           0 : }
     201             : 
     202        1193 : void MaterialCompiler::runMaterialCompilationFrame(core::Loop &loop, Rc<MaterialInputData> &&req,
     203             :                 Vector<Rc<core::DependencyEvent>> &&deps) {
     204        1193 :         auto targetAttachment = req->attachment;
     205             : 
     206        1193 :         auto h = loop.makeFrame(makeRequest(move(req), move(deps)), 0);
     207        1193 :         h->setCompleteCallback([this, targetAttachment] (FrameHandle &handle) {
     208        1193 :                 auto reqIt = _requests.find(targetAttachment);
     209        1193 :                 if (reqIt != _requests.end()) {
     210           0 :                         if (handle.getLoop()->isRunning()) {
     211           0 :                                 auto deps = move(reqIt->second.deps);
     212           0 :                                 Rc<MaterialInputData> req = Rc<MaterialInputData>::alloc();
     213           0 :                                 req->attachment = targetAttachment;
     214           0 :                                 req->materialsToAddOrUpdate.reserve(reqIt->second.materials.size());
     215           0 :                                 for (auto &m : reqIt->second.materials) {
     216           0 :                                         req->materialsToAddOrUpdate.emplace_back(m.second);
     217             :                                 }
     218           0 :                                 req->materialsToRemove.reserve(reqIt->second.remove.size());
     219           0 :                                 for (auto &m : reqIt->second.remove) {
     220           0 :                                         req->materialsToRemove.emplace_back(m);
     221             :                                 }
     222           0 :                                 req->dynamicMaterialsToUpdate.reserve(reqIt->second.dynamic.size());
     223           0 :                                 for (auto &m : reqIt->second.dynamic) {
     224           0 :                                         req->dynamicMaterialsToUpdate.emplace_back(m);
     225             :                                 }
     226           0 :                                 req->callback = move(reqIt->second.callback);
     227           0 :                                 _requests.erase(reqIt);
     228             : 
     229           0 :                                 runMaterialCompilationFrame(*handle.getLoop(), move(req), Vector<Rc<core::DependencyEvent>>(deps));
     230           0 :                         } else {
     231           0 :                                 clearRequests();
     232           0 :                                 dropInProgress(targetAttachment);
     233             :                         }
     234             :                 } else {
     235        1193 :                         dropInProgress(targetAttachment);
     236             :                 }
     237        1193 :         });
     238        1193 :         h->update(true);
     239        1193 : }
     240             : 
     241          84 : MaterialCompilationAttachment::~MaterialCompilationAttachment() { }
     242             : 
     243        1193 : auto MaterialCompilationAttachment::makeFrameHandle(const FrameQueue &handle) -> Rc<AttachmentHandle> {
     244        2386 :         return Rc<MaterialCompilationAttachmentHandle>::create(this, handle);
     245             : }
     246             : 
     247        2386 : MaterialCompilationAttachmentHandle::~MaterialCompilationAttachmentHandle() { }
     248             : 
     249        1193 : bool MaterialCompilationAttachmentHandle::setup(FrameQueue &handle, Function<void(bool)> &&cb) {
     250        1193 :         return true;
     251             : }
     252             : 
     253        1193 : void MaterialCompilationAttachmentHandle::submitInput(FrameQueue &q, Rc<core::AttachmentInputData> &&data, Function<void(bool)> &&cb) {
     254        1193 :         auto d = data.cast<core::MaterialInputData>();
     255        1193 :         if (!d || q.isFinalized()) {
     256           0 :                 cb(false);
     257             :         }
     258             : 
     259        1193 :         q.getFrame()->waitForDependencies(data->waitDependencies, [this, d = move(d), cb = move(cb)] (FrameHandle &handle, bool success) {
     260        1193 :                 handle.performOnGlThread([this, d = move(d), cb = move(cb)] (FrameHandle &handle) {
     261        1193 :                         _inputData = d;
     262        1193 :                         _originalSet = _inputData->attachment->getMaterials();
     263        1193 :                         cb(true);
     264        1193 :                 }, this, true, "MaterialCompilationAttachmentHandle::submitInput");
     265        1193 :         });
     266        1193 : }
     267             : 
     268          84 : MaterialCompilationRenderPass::~MaterialCompilationRenderPass() { }
     269             : 
     270          42 : bool MaterialCompilationRenderPass::init(QueuePassBuilder &passBuilder, const AttachmentData *attachment) {
     271          42 :         passBuilder.addAttachment(attachment);
     272             : 
     273          42 :         if (!QueuePass::init(passBuilder)) {
     274           0 :                 return false;
     275             :         }
     276             : 
     277          42 :         _queueOps = QueueOperations::Transfer;
     278          42 :         _materialAttachment = attachment;
     279          42 :         return true;
     280             : }
     281             : 
     282        1193 : auto MaterialCompilationRenderPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
     283        2386 :         return Rc<MaterialCompilationPassHandle>::create(*this, handle);
     284             : }
     285             : 
     286        2386 : MaterialCompilationPassHandle::~MaterialCompilationPassHandle() { }
     287             : 
     288        1193 : bool MaterialCompilationPassHandle::prepare(FrameQueue &frame, Function<void(bool)> &&cb) {
     289        1193 :         if (auto a = frame.getAttachment(static_cast<MaterialCompilationRenderPass *>(_queuePass.get())->getMaterialAttachment())) {
     290        1193 :                 _materialAttachment = static_cast<MaterialCompilationAttachmentHandle *>(a->handle.get());
     291             :         }
     292             : 
     293        1193 :         auto &originalData = _materialAttachment->getOriginalSet();
     294        1193 :         auto &inputData = _materialAttachment->getInputData();
     295        1193 :         _outputData = inputData->attachment->cloneSet(originalData);
     296             : 
     297        1193 :         return QueuePassHandle::prepare(frame, move(cb));
     298             : }
     299             : 
     300        1193 : void MaterialCompilationPassHandle::finalize(FrameQueue &handle, bool successful) {
     301        1193 :         QueuePassHandle::finalize(handle, successful);
     302        1193 : }
     303             : 
     304        1193 : Vector<const CommandBuffer *> MaterialCompilationPassHandle::doPrepareCommands(FrameHandle &handle) {
     305        1193 :         auto layout = _device->getTextureSetLayout();
     306             : 
     307        1193 :         auto &inputData = _materialAttachment->getInputData();
     308        1193 :         auto buffers = updateMaterials(handle, _outputData, inputData->materialsToAddOrUpdate,
     309        2386 :                         inputData->dynamicMaterialsToUpdate, inputData->materialsToRemove);
     310        1193 :         if (!buffers.targetBuffer) {
     311           0 :                 return Vector<const CommandBuffer *>();
     312             :         }
     313             : 
     314        1193 :         QueueOperations ops = QueueOperations::None;
     315        2386 :         for (auto &it : inputData->attachment->getRenderPasses()) {
     316        1193 :                 ops |= static_cast<vk::QueuePass *>(it->pass.get())->getQueueOps();
     317        1193 :         }
     318             : 
     319        1193 :         auto q = _device->getQueueFamily(ops);
     320        1193 :         if (!q) {
     321           0 :                 return Vector<const CommandBuffer *>();
     322             :         }
     323             : 
     324        1193 :         VkPipelineStageFlags targetStages = 0;
     325        1193 :         if ((_pool->getClass() & QueueOperations::Graphics) != QueueOperations::None) {
     326           0 :                 targetStages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
     327             :         }
     328        1193 :         if ((_pool->getClass() & QueueOperations::Compute) != QueueOperations::None) {
     329           0 :                 targetStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
     330             :         }
     331        1193 :         if (!targetStages) {
     332        1193 :                 targetStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
     333             :         }
     334             : 
     335        1193 :         auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
     336        1193 :                 buf.cmdCopyBuffer(buffers.stagingBuffer, buffers.targetBuffer);
     337             : 
     338        1193 :                 if (q->index == _pool->getFamilyIdx()) {
     339           0 :                         BufferMemoryBarrier bufferBarrier(buffers.targetBuffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
     340           0 :                         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetStages, 0, makeSpanView(&bufferBarrier, 1));
     341             :                 } else {
     342             :                         BufferMemoryBarrier bufferBarrier(buffers.targetBuffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     343        1193 :                                         QueueFamilyTransfer{_pool->getFamilyIdx(), q->index}, 0, VK_WHOLE_SIZE);
     344        1193 :                         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetStages, 0, makeSpanView(&bufferBarrier, 1));
     345        1193 :                         buffers.targetBuffer->setPendingBarrier(bufferBarrier);
     346             :                 }
     347        1193 :                 return true;
     348             :         });
     349             : 
     350        1193 :         if (buf) {
     351        1193 :                 auto tmpBuffer = new Rc<Buffer>(move(buffers.targetBuffer));
     352        1193 :                 auto tmpOrder = new HashMap<core::MaterialId, uint32_t>(move(buffers.ordering));
     353        1193 :                 handle.performOnGlThread([data = _outputData, tmpBuffer, tmpOrder] (FrameHandle &) {
     354        1193 :                         data->setBuffer(move(*tmpBuffer), move(*tmpOrder));
     355        1193 :                         delete tmpBuffer;
     356        1193 :                         delete tmpOrder;
     357        1193 :                 }, nullptr, true, "MaterialCompilationRenderPassHandle::doPrepareCommands");
     358        1193 :                 return Vector<const CommandBuffer *>{buf};
     359             :         }
     360           0 :         return Vector<const CommandBuffer *>();
     361        1193 : }
     362             : 
     363        1193 : void MaterialCompilationPassHandle::doSubmitted(FrameHandle &frame, Function<void(bool)> &&func, bool success, Rc<Fence> &&fence) {
     364        1193 :         if (success) {
     365        1193 :                 _materialAttachment->getInputData()->attachment->setMaterials(_outputData);
     366             :         }
     367             : 
     368        1193 :         QueuePassHandle::doSubmitted(frame, move(func), success, move(fence));
     369        1193 :         frame.signalDependencies(success);
     370        1193 : }
     371             : 
     372        1193 : void MaterialCompilationPassHandle::doComplete(FrameQueue &queue, Function<void(bool)> &&func, bool success) {
     373        1193 :         if (auto &cb = _materialAttachment->getInputData()->callback) {
     374         127 :                 cb();
     375             :         }
     376             : 
     377        1193 :         QueuePassHandle::doComplete(queue, move(func), success);
     378        1193 : }
     379             : 
     380             : }

Generated by: LCOV version 1.14