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