LCOV - code coverage report
Current view: top level - xenolith/backend/vk - XLVkTextureSet.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 310 396 78.3 %
Date: 2024-05-12 00:16:13 Functions: 38 45 84.4 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2021-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "XLVkTextureSet.h"
      25             : #include "XLVkLoop.h"
      26             : #include <forward_list>
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      29             : 
      30          42 : bool TextureSetLayout::init(Device &dev, uint32_t imageLimit, uint32_t bufferLimit) {
      31          42 :         _imageCount = imageLimit;
      32          42 :         _bufferCount = bufferLimit;
      33             : 
      34             :         // create dummy image
      35          42 :         auto alloc = dev.getAllocator();
      36         126 :         _emptyImage = alloc->preallocate(ImageInfo(
      37          84 :                         Extent2(1, 1), core::ImageUsage::Sampled, core::ImageFormat::R8_UNORM, core::EmptyTextureName), false);
      38         126 :         _solidImage = alloc->preallocate(ImageInfo(
      39          84 :                         Extent2(1, 1), core::ImageUsage::Sampled, core::ImageFormat::R8_UNORM, core::SolidTextureName, core::ImageHints::Opaque), false);
      40          42 :         _emptyBuffer = alloc->preallocate(BufferInfo(uint64_t(8), core::BufferUsage::StorageBuffer));
      41             : 
      42             :         Rc<Image> images[] = {
      43          84 :                 _emptyImage, _solidImage
      44         126 :         };
      45             : 
      46          42 :         alloc->emplaceObjects(AllocationUsage::DeviceLocal, makeSpanView(images, 2), SpanView<Rc<Buffer>>(&_emptyBuffer, 1));
      47             : 
      48          42 :         _emptyImageView = Rc<ImageView>::create(dev, _emptyImage, ImageViewInfo());
      49          42 :         _solidImageView = Rc<ImageView>::create(dev, _solidImage, ImageViewInfo());
      50             : 
      51          84 :         return true;
      52         168 : }
      53             : 
      54          42 : void TextureSetLayout::invalidate(Device &dev) {
      55          42 :         if (_layout) {
      56          42 :                 dev.getTable()->vkDestroyDescriptorSetLayout(dev.getDevice(), _layout, nullptr);
      57          42 :                 _layout = VK_NULL_HANDLE;
      58             :         }
      59             : 
      60          42 :         _emptyImage = nullptr;
      61          42 :         _emptyImageView = nullptr;
      62          42 :         _solidImage = nullptr;
      63          42 :         _solidImageView = nullptr;
      64          42 : }
      65             : 
      66          42 : bool TextureSetLayout::compile(Device &dev, const Vector<VkSampler> &samplers) {
      67             :         VkDescriptorSetLayoutBinding b[] = {
      68             :                 VkDescriptorSetLayoutBinding{
      69             :                         uint32_t(0),
      70             :                         VK_DESCRIPTOR_TYPE_SAMPLER,
      71          42 :                         uint32_t(samplers.size()),
      72             :                         VK_SHADER_STAGE_FRAGMENT_BIT,
      73          42 :                         samplers.data()
      74             :                 },
      75             :                 VkDescriptorSetLayoutBinding{
      76             :                         uint32_t(1),
      77             :                         VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
      78          42 :                         uint32_t(_imageCount),
      79             :                         VK_SHADER_STAGE_FRAGMENT_BIT,
      80             :                         nullptr
      81             :                 },
      82             :                 VkDescriptorSetLayoutBinding{
      83             :                         uint32_t(2),
      84             :                         VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
      85          42 :                         uint32_t(_bufferCount),
      86             :                         VK_SHADER_STAGE_VERTEX_BIT,
      87             :                         nullptr
      88             :                 },
      89          42 :         };
      90             : 
      91          42 :         _samplersCount = uint32_t(samplers.size());
      92             : 
      93          42 :         VkDescriptorSetLayoutCreateInfo layoutInfo { };
      94          42 :         layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
      95          42 :         layoutInfo.pNext = nullptr;
      96          42 :         layoutInfo.bindingCount = 3;
      97          42 :         layoutInfo.pBindings = b;
      98          42 :         layoutInfo.flags = 0;
      99             : 
     100          42 :         if (dev.getInfo().features.deviceDescriptorIndexing.descriptorBindingPartiallyBound) {
     101          42 :                 Vector<VkDescriptorBindingFlags> flags;
     102          42 :                 flags.emplace_back(0);
     103          42 :                 flags.emplace_back(VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT);
     104          42 :                 flags.emplace_back(VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT);
     105             : 
     106             :                 VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlags;
     107          42 :                 bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
     108          42 :                 bindingFlags.pNext = nullptr;
     109          42 :                 bindingFlags.bindingCount = flags.size();
     110          42 :                 bindingFlags.pBindingFlags = flags.data();
     111          42 :                 layoutInfo.pNext = &bindingFlags;
     112             : 
     113          42 :                 if (dev.getTable()->vkCreateDescriptorSetLayout(dev.getDevice(), &layoutInfo, nullptr, &_layout) != VK_SUCCESS) {
     114           0 :                         return false;
     115             :                 }
     116             : 
     117          42 :                 _partiallyBound = true;
     118             : 
     119          42 :         } else {
     120           0 :                 if (dev.getTable()->vkCreateDescriptorSetLayout(dev.getDevice(), &layoutInfo, nullptr, &_layout) != VK_SUCCESS) {
     121           0 :                         return false;
     122             :                 }
     123             :         }
     124             : 
     125          42 :         return true;
     126             : }
     127             : 
     128        1214 : Rc<TextureSet> TextureSetLayout::acquireSet(Device &dev) {
     129        1214 :         std::unique_lock<Mutex> lock(_mutex);
     130        1214 :         if (_sets.empty()) {
     131        1214 :                 lock.unlock();
     132        1214 :                 return Rc<TextureSet>::create(dev, *this);
     133             :         } else {
     134           0 :                 auto v = move(_sets.back());
     135           0 :                 _sets.pop_back();
     136           0 :                 return v;
     137           0 :         }
     138        1214 : }
     139             : 
     140           0 : void TextureSetLayout::releaseSet(Rc<TextureSet> &&set) {
     141           0 :         std::unique_lock<Mutex> lock(_mutex);
     142           0 :         _sets.emplace_back(move(set));
     143           0 : }
     144             : 
     145          42 : void TextureSetLayout::initDefault(Device &dev, Loop &loop, Function<void(bool)> &&cb) {
     146             :         struct CompileTask : public Ref {
     147             :                 Function<void(bool)> callback;
     148             :                 Rc<Loop> loop;
     149             :                 Device *device;
     150             : 
     151             :                 Rc<CommandPool> pool;
     152             :                 Rc<DeviceQueue> queue;
     153             :                 Rc<Fence> fence;
     154             :         };
     155             : 
     156          84 :         auto task = new CompileTask();
     157          42 :         task->callback = move(cb);
     158          42 :         task->loop = &loop;
     159          42 :         task->device = &dev;
     160             : 
     161          42 :         dev.acquireQueue(QueueOperations::Graphics, loop, [this, task] (Loop &loop, const Rc<DeviceQueue> &queue) {
     162          42 :                 task->queue = queue;
     163          42 :                 task->fence = task->loop->acquireFence(0);
     164          42 :                 task->pool = task->device->acquireCommandPool(QueueOperations::Graphics);
     165             : 
     166          42 :                 auto refId = task->retain();
     167          42 :                 task->fence->addRelease([task, refId] (bool success) {
     168          42 :                         task->device->releaseCommandPool(*task->loop, move(task->pool));
     169          42 :                         task->callback(success);
     170          42 :                         task->release(refId);
     171          42 :                 }, this, "TextureSetLayout::initDefault releaseCommandPool");
     172             : 
     173          42 :                 loop.performInQueue(Rc<thread::Task>::create([this, task] (const thread::Task &) -> bool {
     174          42 :                         auto buf = task->pool->recordBuffer(*task->device, [&, this] (CommandBuffer &buf) {
     175          42 :                                 writeDefaults(buf);
     176          42 :                                 return true;
     177             :                         });
     178             : 
     179          42 :                         if (task->queue->submit(*task->fence, buf)) {
     180          42 :                                 return true;
     181             :                         }
     182           0 :                         return false;
     183         252 :                 }, [task] (const thread::Task &, bool success) mutable {
     184          42 :                         if (task->queue) {
     185          42 :                                 task->device->releaseQueue(move(task->queue));
     186             :                         }
     187             : 
     188          42 :                         task->fence->schedule(*task->loop);
     189          42 :                         task->fence = nullptr;
     190          42 :                         task->release(0);
     191          84 :                 }, this));
     192          42 :         }, [task] (Loop &) {
     193           0 :                 task->callback(false);
     194           0 :                 task->release(0);
     195           0 :         }, this);
     196          42 : }
     197             : 
     198          84 : Rc<Image> TextureSetLayout::getEmptyImageObject() const {
     199          84 :         return _emptyImage;
     200             : }
     201             : 
     202          84 : Rc<Image> TextureSetLayout::getSolidImageObject() const {
     203          84 :         return _solidImage;
     204             : }
     205             : 
     206          21 : void TextureSetLayout::readImage(Device &dev, Loop &loop, const Rc<Image> &image,
     207             :                 AttachmentLayout l, Function<void(const ImageInfoData &, BytesView)> &&cb) {
     208             :         struct ReadImageTask : public Ref {
     209             :                 Function<void(const ImageInfoData &, BytesView)> callback;
     210             :                 Rc<Image> image;
     211             :                 Rc<Loop> loop;
     212             :                 Device *device;
     213             :                 AttachmentLayout layout;
     214             : 
     215             :                 Rc<Buffer> transferBuffer;
     216             :                 Rc<CommandPool> pool;
     217             :                 Rc<DeviceQueue> queue;
     218             :                 Rc<Fence> fence;
     219             :                 Rc<DeviceMemoryPool> mempool;
     220             :         };
     221             : 
     222          42 :         auto task = new ReadImageTask();
     223          21 :         task->callback = move(cb);
     224          21 :         task->image = image;
     225          21 :         task->loop = &loop;
     226          21 :         task->device = &dev;
     227          21 :         task->layout = l;
     228             : 
     229          21 :         task->loop->performOnGlThread([this, task] {
     230          21 :                 task->device->acquireQueue(getQueueOperations(task->image->getInfo().type), *task->loop, [this, task] (Loop &loop, const Rc<DeviceQueue> &queue) {
     231          21 :                         task->fence = loop.acquireFence(0);
     232          21 :                         task->pool = task->device->acquireCommandPool(getQueueOperations(task->image->getInfo().type));
     233          21 :                         task->queue = move(queue);
     234          21 :                         task->mempool = Rc<DeviceMemoryPool>::create(task->device->getAllocator(), true);
     235             : 
     236          21 :                         auto &info = task->image->getInfo();
     237          21 :                         auto &extent = info.extent;
     238             : 
     239          63 :                         task->transferBuffer = task->mempool->spawn(AllocationUsage::HostTransitionDestination, BufferInfo(
     240           0 :                                 core::ForceBufferUsage(core::BufferUsage::TransferDst),
     241          21 :                                 size_t(extent.width * extent.height * extent.depth * core::getFormatBlockSize(info.format)),
     242          21 :                                 task->image->getInfo().type
     243          21 :                         ));
     244             : 
     245          21 :                         auto refId = task->retain();
     246          21 :                         task->fence->addRelease([task, refId] (bool) {
     247          21 :                                 task->device->releaseCommandPool(*task->loop, move(task->pool));
     248             : 
     249          21 :                                 task->transferBuffer->map([&] (uint8_t *buf, VkDeviceSize size) {
     250          21 :                                         task->callback(task->image->getInfo(), BytesView(buf, size));
     251          21 :                                 });
     252             : 
     253          21 :                                 task->release(refId);
     254          21 :                         }, this, "TextureSetLayout::readImage transferBuffer->dropPendingBarrier");
     255             : 
     256          21 :                         loop.performInQueue(Rc<thread::Task>::create([this, task] (const thread::Task &) -> bool {
     257          21 :                                 auto buf = task->pool->recordBuffer(*task->device, [&, this] (CommandBuffer &buf) {
     258          21 :                                         writeImageRead(*task->device, buf, task->pool->getFamilyIdx(), task->image, task->layout, task->transferBuffer);
     259          21 :                                         return true;
     260             :                                 });
     261             : 
     262          21 :                                 if (task->queue->submit(*task->fence, buf)) {
     263          21 :                                         return true;
     264             :                                 }
     265           0 :                                 return false;
     266         126 :                         }, [task] (const thread::Task &, bool success) {
     267          21 :                                 if (task->queue) {
     268          21 :                                         task->device->releaseQueue(move(task->queue));
     269             :                                 }
     270          21 :                                 if (!success) {
     271           0 :                                         task->callback(ImageInfo(), BytesView());
     272             :                                 }
     273          21 :                                 task->fence->schedule(*task->loop);
     274          21 :                                 task->fence = nullptr;
     275          21 :                                 task->release(0);
     276          21 :                         }));
     277          21 :                 }, [task] (Loop &) {
     278           0 :                         task->callback(ImageInfo(), BytesView());
     279           0 :                         task->release(0);
     280           0 :                 });
     281          21 :         }, task, true);
     282          21 : }
     283             : 
     284       25200 : void TextureSetLayout::readBuffer(Device &dev, Loop &loop, const Rc<Buffer> &buf, Function<void(const BufferInfo &, BytesView)> &&cb) {
     285       25200 :         if (!buf) {
     286           0 :                 log::error("vk::TextureSetLayout", "Buffer is null");
     287           0 :                 return;
     288             :         }
     289             : 
     290             :         struct ReadBufferTask : public Ref {
     291             :                 Function<void(const BufferInfo &, BytesView)> callback;
     292             :                 Rc<Buffer> buffer;
     293             :                 Rc<Loop> loop;
     294             :                 Device *device;
     295             : 
     296             :                 Rc<Buffer> transferBuffer;
     297             :                 Rc<CommandPool> pool;
     298             :                 Rc<DeviceQueue> queue;
     299             :                 Rc<Fence> fence;
     300             :                 Rc<DeviceMemoryPool> mempool;
     301             :         };
     302             : 
     303       50400 :         auto task = new ReadBufferTask();
     304       25200 :         task->callback = move(cb);
     305       25200 :         task->buffer = buf;
     306       25200 :         task->loop = &loop;
     307       25200 :         task->device = &dev;
     308       25200 :         task->mempool = buf->getMemory()->getPool();
     309             : 
     310       25200 :         task->loop->performOnGlThread([this, task] {
     311       25200 :                 task->device->acquireQueue(getQueueOperations(task->buffer->getInfo().type), *task->loop, [this, task] (Loop &loop, const Rc<DeviceQueue> &queue) {
     312       25200 :                         task->fence = loop.acquireFence(0);
     313       25200 :                         task->pool = task->device->acquireCommandPool(getQueueOperations(task->buffer->getInfo().type));
     314       25200 :                         task->queue = move(queue);
     315       25200 :                         if (!task->mempool) {
     316       25200 :                                 task->mempool = Rc<DeviceMemoryPool>::create(task->device->getAllocator(), true);
     317             :                         }
     318             : 
     319       25200 :                         auto &info = task->buffer->getInfo();
     320             : 
     321       75600 :                         task->transferBuffer = task->mempool->spawn(AllocationUsage::HostTransitionDestination, BufferInfo(
     322           0 :                                 core::ForceBufferUsage(core::BufferUsage::TransferDst),
     323           0 :                                 size_t(info.size),
     324       25200 :                                 info.type
     325       25200 :                         ));
     326             : 
     327       25200 :                         auto refId = task->retain();
     328       25200 :                         task->fence->addRelease([task, refId] (bool) {
     329       25200 :                                 task->device->releaseCommandPool(*task->loop, move(task->pool));
     330             : 
     331       25200 :                                 task->transferBuffer->map([&] (uint8_t *buf, VkDeviceSize size) {
     332       25200 :                                         task->callback(task->buffer->getInfo(), BytesView(buf, size));
     333       25200 :                                 });
     334             : 
     335       25200 :                                 task->release(refId);
     336       25200 :                         }, this, "TextureSetLayout::readImage transferBuffer->dropPendingBarrier");
     337             : 
     338       25200 :                         loop.performInQueue(Rc<thread::Task>::create([this, task] (const thread::Task &) -> bool {
     339       25200 :                                 auto buf = task->pool->recordBuffer(*task->device, [&, this] (CommandBuffer &buf) {
     340       25200 :                                         writeBufferRead(*task->device, buf, task->pool->getFamilyIdx(), task->buffer, task->transferBuffer);
     341       25200 :                                         return true;
     342             :                                 });
     343             : 
     344       25200 :                                 if (task->queue->submit(*task->fence, buf)) {
     345       25200 :                                         return true;
     346             :                                 }
     347           0 :                                 return false;
     348      151200 :                         }, [task] (const thread::Task &, bool success) {
     349       25200 :                                 if (task->queue) {
     350       25200 :                                         task->device->releaseQueue(move(task->queue));
     351             :                                 }
     352       25200 :                                 if (!success) {
     353           0 :                                         task->callback(BufferInfo(), BytesView());
     354             :                                 }
     355       25200 :                                 task->fence->schedule(*task->loop);
     356       25200 :                                 task->fence = nullptr;
     357       25200 :                                 task->release(0);
     358       25200 :                         }));
     359       25200 :                 }, [task] (Loop &) {
     360           0 :                         task->callback(BufferInfo(), BytesView());
     361           0 :                         task->release(0);
     362           0 :                 });
     363       25200 :         }, task, true);
     364             : }
     365             : 
     366          42 : void TextureSetLayout::writeDefaults(CommandBuffer &buf) {
     367          42 :         std::array<ImageMemoryBarrier, 2> inImageBarriers;
     368             :         // define input barrier/transition (Undefined -> TransferDst)
     369          42 :         inImageBarriers[0] = ImageMemoryBarrier(_emptyImage,
     370             :                 0, VK_ACCESS_TRANSFER_WRITE_BIT,
     371             :                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
     372          42 :         inImageBarriers[1] = ImageMemoryBarrier(_solidImage,
     373             :                 0, VK_ACCESS_TRANSFER_WRITE_BIT,
     374             :                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
     375             : 
     376          42 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, inImageBarriers);
     377             : 
     378          42 :         buf.cmdClearColorImage(_emptyImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, Color4F::ZERO);
     379          42 :         buf.cmdClearColorImage(_solidImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, Color4F::ONE);
     380          42 :         buf.cmdFillBuffer(_emptyBuffer, 0xffffffffU);
     381             : 
     382          42 :         std::array<ImageMemoryBarrier, 2> outImageBarriers;
     383          42 :         outImageBarriers[0] = ImageMemoryBarrier(_emptyImage,
     384             :                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     385             :                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
     386          42 :         outImageBarriers[1] = ImageMemoryBarrier(_solidImage,
     387             :                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     388             :                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
     389             :         BufferMemoryBarrier outBufferBarrier(_emptyBuffer,
     390          42 :                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
     391             : 
     392          84 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
     393          42 :                         makeSpanView(&outBufferBarrier, 1), outImageBarriers);
     394          42 : }
     395             : 
     396           0 : void TextureSetLayout::writeImageTransfer(Device &dev, CommandBuffer &buf, uint32_t qidx, const Rc<Buffer> &buffer, const Rc<Image> &image) {
     397           0 :         auto f = dev.getQueueFamily(image->getInfo().type);
     398           0 :         buf.writeImageTransfer(qidx, f ? f->index : VK_QUEUE_FAMILY_IGNORED, buffer, image);
     399           0 : }
     400             : 
     401          21 : void TextureSetLayout::writeImageRead(Device &dev, CommandBuffer &buf, uint32_t qidx, const Rc<Image> &image,
     402             :                 AttachmentLayout layout, const Rc<Buffer> &target) {
     403             :         auto inImageBarrier = ImageMemoryBarrier(image,
     404             :                 VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
     405          21 :                 VkImageLayout(layout), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
     406             : 
     407          21 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, makeSpanView(&inImageBarrier, 1));
     408             : 
     409          21 :         buf.cmdCopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target, 0);
     410             : 
     411          21 :         BufferMemoryBarrier bufferOutBarrier(target, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
     412             : 
     413          21 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, makeSpanView(&bufferOutBarrier, 1));
     414          21 : }
     415             : 
     416       25200 : void TextureSetLayout::writeBufferRead(Device &dev, CommandBuffer &buf, uint32_t qidx, const Rc<Buffer> &source,
     417             :                 const Rc<Buffer> &target) {
     418       25200 :         buf.cmdCopyBuffer(source, target);
     419       25200 : }
     420             : 
     421        1214 : bool TextureSet::init(Device &dev, const TextureSetLayout &layout) {
     422        1214 :         _imageCount = layout.getImageCount();
     423        1214 :         _bufferCount = layout.getBuffersCount();
     424             : 
     425             :         VkDescriptorPoolSize poolSizes[] = {
     426             :                 VkDescriptorPoolSize{
     427             :                         VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
     428        1214 :                         _imageCount
     429             :                 },
     430             :                 VkDescriptorPoolSize{
     431             :                         VK_DESCRIPTOR_TYPE_SAMPLER,
     432        2428 :                         layout.getSamplersCount()
     433             :                 },
     434             :                 VkDescriptorPoolSize{
     435             :                         VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
     436        1214 :                         _bufferCount
     437             :                 },
     438        1214 :         };
     439             : 
     440        1214 :         VkDescriptorPoolCreateInfo poolInfo{};
     441        1214 :         poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
     442        1214 :         poolInfo.pNext = nullptr;
     443        1214 :         poolInfo.flags = 0;
     444        1214 :         poolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(VkDescriptorPoolSize);
     445        1214 :         poolInfo.pPoolSizes = poolSizes;
     446        1214 :         poolInfo.maxSets = 1;
     447             : 
     448        1214 :         if (dev.getTable()->vkCreateDescriptorPool(dev.getDevice(), &poolInfo, nullptr, &_pool) != VK_SUCCESS) {
     449           0 :                 return false;
     450             :         }
     451             : 
     452        1214 :         auto descriptorSetLayout = layout.getLayout();
     453             : 
     454        1214 :         VkDescriptorSetAllocateInfo allocInfo{};
     455        1214 :         allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
     456        1214 :         allocInfo.pNext = nullptr;
     457        1214 :         allocInfo.descriptorPool = _pool;
     458        1214 :         allocInfo.descriptorSetCount = 1;
     459        1214 :         allocInfo.pSetLayouts = &descriptorSetLayout;
     460             : 
     461        1214 :         auto err = dev.getTable()->vkAllocateDescriptorSets(dev.getDevice(), &allocInfo, &_set);
     462        1214 :         if (err != VK_SUCCESS) {
     463           0 :                 dev.getTable()->vkDestroyDescriptorPool(dev.getDevice(), _pool, nullptr);
     464           0 :                 return false;
     465             :         }
     466             : 
     467        1214 :         _layout = &layout;
     468        1214 :         _partiallyBound = layout.isPartiallyBound();
     469        1214 :         return core::Object::init(dev, [] (core::Device *dev, core::ObjectType, ObjectHandle ptr, void *) {
     470        1214 :                 auto d = ((Device *)dev);
     471        1214 :                 d->getTable()->vkDestroyDescriptorPool(d->getDevice(), (VkDescriptorPool)ptr.get(), nullptr);
     472        2428 :         }, core::ObjectType::DescriptorPool, ObjectHandle(_pool));
     473             : }
     474             : 
     475        1214 : void TextureSet::write(const core::MaterialLayout &set) {
     476        1214 :         auto table = ((Device *)_object.device)->getTable();
     477        1214 :         auto dev = ((Device *)_object.device)->getDevice();
     478             : 
     479        1214 :         std::forward_list<Vector<VkDescriptorImageInfo>> imagesList;
     480        1214 :         std::forward_list<Vector<VkDescriptorBufferInfo>> buffersList;
     481        1214 :         Vector<VkWriteDescriptorSet> writes;
     482             : 
     483        1214 :         writeImages(writes, set, imagesList);
     484        1214 :         writeBuffers(writes, set, buffersList);
     485             : 
     486        1214 :         table->vkUpdateDescriptorSets(dev, writes.size(), writes.data(), 0, nullptr);
     487        1214 : }
     488             : 
     489        9517 : void TextureSet::dropPendingBarriers() {
     490        9517 :         _pendingImageBarriers.clear();
     491        9517 : }
     492             : 
     493           0 : Device *TextureSet::getDevice() const {
     494           0 :         return (Device *)_object.device;
     495             : }
     496             : 
     497        1214 : void TextureSet::writeImages(Vector<VkWriteDescriptorSet> &writes, const core::MaterialLayout &set,
     498             :                 std::forward_list<Vector<VkDescriptorImageInfo>> &imagesList) {
     499        1214 :         Vector<VkDescriptorImageInfo> *localImages = nullptr;
     500             : 
     501        1214 :         VkWriteDescriptorSet imageWriteData({
     502             :                 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
     503        1214 :                 _set, // set
     504             :                 1, // descriptor
     505             :                 0, // index
     506             :                 0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, nullptr,
     507             :                 VK_NULL_HANDLE, VK_NULL_HANDLE
     508        1214 :         });
     509             : 
     510        1214 :         if (_partiallyBound) {
     511        1214 :                 _layoutIndexes.resize(set.usedImageSlots, 0);
     512             :         } else {
     513           0 :                 _layoutIndexes.resize(set.imageSlots.size(), 0);
     514             :         }
     515             : 
     516          42 :         auto pushWritten = [&, this] {
     517          21 :                 imageWriteData.descriptorCount = localImages->size();
     518          21 :                 imageWriteData.pImageInfo = localImages->data();
     519          21 :                 writes.emplace_back(move(imageWriteData));
     520          21 :                 imageWriteData = VkWriteDescriptorSet ({
     521             :                         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
     522          21 :                         _set, // set
     523             :                         1, // descriptor
     524             :                         0, // start from next index
     525             :                         0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, nullptr,
     526             :                         VK_NULL_HANDLE, VK_NULL_HANDLE
     527             :                 });
     528          21 :                 localImages = nullptr;
     529        1235 :         };
     530             : 
     531        8499 :         for (uint32_t i = 0; i < set.usedImageSlots; ++ i) {
     532        7285 :                 if (set.imageSlots[i].image && _layoutIndexes[i] != set.imageSlots[i].image->getIndex()) {
     533        7264 :                         if (!localImages) {
     534        1214 :                                 localImages = &imagesList.emplace_front(Vector<VkDescriptorImageInfo>());
     535             :                         }
     536        7264 :                         localImages->emplace_back(VkDescriptorImageInfo({
     537        7264 :                                 VK_NULL_HANDLE, ((ImageView *)set.imageSlots[i].image.get())->getImageView(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
     538             :                         }));
     539        7264 :                         auto image = (Image *)set.imageSlots[i].image->getImage().get();
     540        7264 :                         if (auto b = image->getPendingBarrier()) {
     541        1150 :                                 _pendingImageBarriers.emplace_back(*b);
     542        1150 :                                 image->dropPendingBarrier();
     543             :                         }
     544        7264 :                         _layoutIndexes[i] = set.imageSlots[i].image->getIndex();
     545        7264 :                         ++ imageWriteData.descriptorCount;
     546          21 :                 } else if (!_partiallyBound && !set.imageSlots[i].image && _layoutIndexes[i] != _layout->getEmptyImageView()->getIndex()) {
     547           0 :                         if (!localImages) {
     548           0 :                                 localImages = &imagesList.emplace_front(Vector<VkDescriptorImageInfo>());
     549             :                         }
     550           0 :                         localImages->emplace_back(VkDescriptorImageInfo({
     551           0 :                                 VK_NULL_HANDLE, _layout->getEmptyImageView()->getImageView(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
     552             :                         }));
     553           0 :                         _layoutIndexes[i] = _layout->getEmptyImageView()->getIndex();
     554           0 :                         ++ imageWriteData.descriptorCount;
     555             :                 } else {
     556             :                         // no need to write, push written
     557          21 :                         if (imageWriteData.descriptorCount > 0) {
     558          21 :                                 pushWritten();
     559             :                         }
     560          21 :                         imageWriteData.dstArrayElement = i + 1; // start from next index
     561             :                 }
     562             :         }
     563             : 
     564        1214 :         if (!_partiallyBound) {
     565             :                 // write empty
     566           0 :                 for (uint32_t i = set.usedImageSlots; i < _imageCount; ++ i) {
     567           0 :                         if (_layoutIndexes[i] != _layout->getEmptyImageView()->getIndex()) {
     568           0 :                                 if (!localImages) {
     569           0 :                                         localImages = &imagesList.emplace_front(Vector<VkDescriptorImageInfo>());
     570             :                                 }
     571           0 :                                 localImages->emplace_back(VkDescriptorImageInfo({
     572           0 :                                         VK_NULL_HANDLE, _layout->getEmptyImageView()->getImageView(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
     573             :                                 }));
     574           0 :                                 _layoutIndexes[i] = _layout->getEmptyImageView()->getIndex();
     575           0 :                                 ++ imageWriteData.descriptorCount;
     576             :                         } else {
     577             :                                 // no need to write, push written
     578           0 :                                 if (imageWriteData.descriptorCount > 0) {
     579           0 :                                         pushWritten();
     580             :                                 }
     581           0 :                                 imageWriteData.dstArrayElement = i + 1; // start from next index
     582             :                         }
     583             :                 }
     584             :         }
     585             : 
     586        1214 :         if (imageWriteData.descriptorCount > 0) {
     587        1193 :                 imageWriteData.descriptorCount = localImages->size();
     588        1193 :                 imageWriteData.pImageInfo = localImages->data();
     589        1193 :                 writes.emplace_back(move(imageWriteData));
     590             :         }
     591        1214 : }
     592             : 
     593        1214 : void TextureSet::writeBuffers(Vector<VkWriteDescriptorSet> &writes, const core::MaterialLayout &set,
     594             :                 std::forward_list<Vector<VkDescriptorBufferInfo>> &bufferList) {
     595        1214 :         Vector<VkDescriptorBufferInfo> *localBuffers = nullptr;
     596             : 
     597        1214 :         VkWriteDescriptorSet bufferWriteData({
     598             :                 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
     599        1214 :                 _set, // set
     600             :                 2, // descriptor
     601             :                 0, // index
     602             :                 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nullptr,
     603             :                 VK_NULL_HANDLE, VK_NULL_HANDLE
     604        1214 :         });
     605             : 
     606        1214 :         if (_partiallyBound) {
     607        1214 :                 _layoutBuffers.resize(set.usedBufferSlots, nullptr);
     608             :         } else {
     609           0 :                 _layoutBuffers.resize(set.bufferSlots.size(), nullptr);
     610             :         }
     611             : 
     612           0 :         auto pushWritten = [&, this] {
     613           0 :                 bufferWriteData.descriptorCount = localBuffers->size();
     614           0 :                 bufferWriteData.pBufferInfo = localBuffers->data();
     615           0 :                 writes.emplace_back(move(bufferWriteData));
     616           0 :                 bufferWriteData = VkWriteDescriptorSet ({
     617             :                         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr,
     618           0 :                         _set, // set
     619             :                         2, // descriptor
     620             :                         0, // start from next index
     621             :                         0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, nullptr,
     622             :                         VK_NULL_HANDLE, VK_NULL_HANDLE
     623             :                 });
     624           0 :                 localBuffers = nullptr;
     625        1214 :         };
     626             : 
     627        3558 :         for (uint32_t i = 0; i < set.usedBufferSlots; ++ i) {
     628        2344 :                 if (set.bufferSlots[i].buffer && _layoutBuffers[i] != set.bufferSlots[i].buffer) {
     629             :                         // replace old buffer in descriptor
     630        2344 :                         if (!localBuffers) {
     631        1172 :                                 localBuffers = &bufferList.emplace_front(Vector<VkDescriptorBufferInfo>());
     632             :                         }
     633        2344 :                         localBuffers->emplace_back(VkDescriptorBufferInfo({
     634        2344 :                                 ((Buffer *)set.bufferSlots[i].buffer.get())->getBuffer(), 0, VK_WHOLE_SIZE
     635             :                         }));
     636        2344 :                         auto buffer = (Buffer *)set.bufferSlots[i].buffer.get();
     637             : 
     638             :                         // propagate barrier, if any
     639        2344 :                         if (auto b = buffer->getPendingBarrier()) {
     640        2132 :                                 _pendingBufferBarriers.emplace_back(*b);
     641        2132 :                                 buffer->dropPendingBarrier();
     642             :                         }
     643        2344 :                         _layoutBuffers[i] = set.bufferSlots[i].buffer;
     644        2344 :                         ++ bufferWriteData.descriptorCount;
     645           0 :                 } else if (!_partiallyBound && !set.bufferSlots[i].buffer && _layoutBuffers[i] != _layout->getEmptyBuffer()) {
     646             :                         // if partiallyBound feature is not available, drop old buffers to preallocated empty buffer
     647           0 :                         if (!localBuffers) {
     648           0 :                                 localBuffers = &bufferList.emplace_front(Vector<VkDescriptorBufferInfo>());
     649             :                         }
     650           0 :                         localBuffers->emplace_back(VkDescriptorBufferInfo({
     651           0 :                                 _layout->getEmptyBuffer()->getBuffer(), 0, VK_WHOLE_SIZE
     652             :                         }));
     653           0 :                         _layoutBuffers[i] = _layout->getEmptyBuffer();
     654           0 :                         ++ bufferWriteData.descriptorCount;
     655             :                 } else {
     656             :                         // descriptor was not changed, no need to write, push written
     657           0 :                         if (bufferWriteData.descriptorCount > 0) {
     658           0 :                                 pushWritten();
     659             :                         }
     660           0 :                         bufferWriteData.dstArrayElement = i + 1; // start from next index
     661             :                 }
     662             :         }
     663             : 
     664        1214 :         if (!_partiallyBound) {
     665             :                 // write empty buffers into empty descriptors
     666           0 :                 for (uint32_t i = set.usedBufferSlots; i < _bufferCount; ++ i) {
     667           0 :                         if (_layoutBuffers[i] != _layout->getEmptyBuffer()) {
     668           0 :                                 if (!localBuffers) {
     669           0 :                                         localBuffers = &bufferList.emplace_front(Vector<VkDescriptorBufferInfo>());
     670             :                                 }
     671           0 :                                 localBuffers->emplace_back(VkDescriptorBufferInfo({
     672           0 :                                         _layout->getEmptyBuffer()->getBuffer(), 0, VK_WHOLE_SIZE
     673             :                                 }));
     674           0 :                                 _layoutBuffers[i] = _layout->getEmptyBuffer();
     675           0 :                                 ++ bufferWriteData.descriptorCount;
     676             :                         } else {
     677             :                                 // no need to write, push written
     678           0 :                                 if (bufferWriteData.descriptorCount > 0) {
     679           0 :                                         pushWritten();
     680             :                                 }
     681           0 :                                 bufferWriteData.dstArrayElement = i + 1; // start from next index
     682             :                         }
     683             :                 }
     684             :         }
     685             : 
     686        1214 :         if (bufferWriteData.descriptorCount > 0) {
     687        1172 :                 bufferWriteData.descriptorCount = localBuffers->size();
     688        1172 :                 bufferWriteData.pBufferInfo = localBuffers->data();
     689        1172 :                 writes.emplace_back(move(bufferWriteData));
     690             :         }
     691        1214 : }
     692             : 
     693             : }

Generated by: LCOV version 1.14