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 "XLVkQueuePass.h"
25 :
26 : #include "XLVkAllocator.h"
27 : #include "XLVkAttachment.h"
28 : #include "XLVkDevice.h"
29 : #include "XLVkDeviceQueue.h"
30 : #include "XLVkTextureSet.h"
31 : #include "XLVkRenderPass.h"
32 : #include "XLVkLoop.h"
33 : #include "XLVkPipeline.h"
34 : #include "XLCoreFrameQueue.h"
35 :
36 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
37 :
38 357 : QueuePass::~QueuePass() { }
39 :
40 357 : bool QueuePass::init(QueuePassBuilder &passBuilder) {
41 357 : if (core::QueuePass::init(passBuilder)) {
42 357 : switch (getType()) {
43 21 : case core::PassType::Graphics:
44 : case core::PassType::Generic:
45 21 : _queueOps = QueueOperations::Graphics;
46 21 : break;
47 168 : case core::PassType::Compute:
48 168 : _queueOps = QueueOperations::Compute;
49 168 : break;
50 168 : case core::PassType::Transfer:
51 168 : _queueOps = QueueOperations::Transfer;
52 168 : break;
53 : }
54 357 : return true;
55 : }
56 0 : return false;
57 : }
58 :
59 357 : void QueuePass::invalidate() { }
60 :
61 3509 : VkRect2D QueuePassHandle::rotateScissor(const core::FrameContraints &constraints, const URect &scissor) {
62 : VkRect2D scissorRect{
63 3509 : { int32_t(scissor.x), int32_t(constraints.extent.height - scissor.y - scissor.height) },
64 3509 : { scissor.width, scissor.height }
65 3509 : };
66 :
67 3509 : switch (core::getPureTransform(constraints.transform)) {
68 0 : case core::SurfaceTransformFlags::Rotate90:
69 0 : scissorRect.offset.y = scissor.x;
70 0 : scissorRect.offset.x = scissor.y;
71 0 : std::swap(scissorRect.extent.width, scissorRect.extent.height);
72 0 : break;
73 0 : case core::SurfaceTransformFlags::Rotate180:
74 0 : scissorRect.offset.y = scissor.y;
75 0 : break;
76 0 : case core::SurfaceTransformFlags::Rotate270:
77 0 : scissorRect.offset.y = constraints.extent.height - scissor.x - scissor.width;
78 0 : scissorRect.offset.x = constraints.extent.width - scissor.y - scissor.height;
79 : //scissorRect.offset.x = extent.height - scissor.y;
80 0 : std::swap(scissorRect.extent.width, scissorRect.extent.height);
81 0 : break;
82 3509 : default: break;
83 : }
84 :
85 3509 : if (scissorRect.offset.x < 0) {
86 756 : scissorRect.extent.width -= scissorRect.offset.x;
87 756 : scissorRect.offset.x = 0;
88 : }
89 :
90 3509 : if (scissorRect.offset.y < 0) {
91 0 : scissorRect.extent.height -= scissorRect.offset.y;
92 0 : scissorRect.offset.y = 0;
93 : }
94 :
95 3509 : return scissorRect;
96 : }
97 :
98 273566 : QueuePassHandle::~QueuePassHandle() {
99 172766 : invalidate();
100 273566 : }
101 :
102 345343 : void QueuePassHandle::invalidate() {
103 345343 : if (_pool) {
104 0 : _device->releaseCommandPoolUnsafe(move(_pool));
105 0 : _pool = nullptr;
106 : }
107 :
108 345343 : if (_queue) {
109 0 : _device->releaseQueue(move(_queue));
110 0 : _queue = nullptr;
111 : }
112 :
113 345343 : _sync = nullptr;
114 345343 : }
115 :
116 172535 : bool QueuePassHandle::prepare(FrameQueue &q, Function<void(bool)> &&cb) {
117 172535 : _onPrepared = move(cb);
118 172535 : _loop = static_cast<Loop *>(q.getLoop());
119 172535 : _device = static_cast<Device *>(q.getFrame()->getDevice());
120 172535 : _pool = _device->acquireCommandPool(getQueueOps());
121 :
122 172535 : _constraints = q.getFrame()->getFrameConstraints();
123 :
124 172535 : if (!_pool) {
125 0 : invalidate();
126 0 : return false;
127 : }
128 :
129 172535 : prepareSubpasses(q);
130 :
131 : // If updateAfterBind feature supported for all renderpass bindings
132 : // - we can use separate thread to update them
133 : // (ordering of bind|update is not defined in this case)
134 :
135 172535 : if (_data->hasUpdateAfterBind) {
136 170255 : q.getFrame()->performInQueue([this] (FrameHandle &frame) {
137 416110 : for (uint32_t i = 0; i < _data->pipelineLayouts.size(); ++ i) {
138 245855 : if (!static_cast<RenderPass *>(_data->impl.get())->writeDescriptors(*this, i, true)) {
139 0 : return false;
140 : }
141 : }
142 170255 : return true;
143 340591 : }, [this] (FrameHandle &frame, bool success) {
144 170255 : if (!success) {
145 0 : _valid = false;
146 0 : log::error("VK-Error", "Fail to doPrepareDescriptors");
147 : }
148 :
149 170255 : _descriptorsReady = true;
150 170255 : if (_commandsReady && _descriptorsReady) {
151 27 : _onPrepared(_valid);
152 27 : _onPrepared = nullptr;
153 : }
154 170255 : }, this, "RenderPass::doPrepareDescriptors");
155 : } else {
156 2280 : _descriptorsReady = true;
157 : }
158 :
159 172535 : q.getFrame()->performInQueue([this] (FrameHandle &frame) {
160 418390 : for (uint32_t i = 0; i < _data->pipelineLayouts.size(); ++ i) {
161 245855 : if (!static_cast<RenderPass *>(_data->impl.get())->writeDescriptors(*this, i, false)) {
162 0 : return false;
163 : }
164 : }
165 :
166 172535 : auto ret = doPrepareCommands(frame);
167 172532 : if (!ret.empty()) {
168 172532 : _buffers = move(ret);
169 172526 : return true;
170 : }
171 0 : return false;
172 172526 : }, [this, cb] (FrameHandle &frame, bool success) {
173 172535 : if (!success) {
174 0 : log::error("VK-Error", "Fail to doPrepareCommands");
175 0 : _valid = false;
176 : }
177 :
178 172535 : _commandsReady = true;
179 172535 : if (_commandsReady && _descriptorsReady) {
180 172508 : _onPrepared(_valid);
181 172508 : _onPrepared = nullptr;
182 : }
183 172535 : }, this, "RenderPass::doPrepareCommands");
184 172535 : return false;
185 : }
186 :
187 172577 : void QueuePassHandle::submit(FrameQueue &q, Rc<FrameSync> &&sync, Function<void(bool)> &&onSubmited, Function<void(bool)> &&onComplete) {
188 172577 : if (!_pool) {
189 0 : onSubmited(true);
190 0 : q.getFrame()->performInQueue([onComplete = move(onComplete)] (FrameHandle &frame) mutable {
191 0 : onComplete(true);
192 0 : return true;
193 : }, this, "RenderPass::complete");
194 0 : return;
195 : }
196 :
197 172577 : Rc<FrameHandle> f = q.getFrame(); // capture frame ref
198 :
199 172577 : _fence = _loop->acquireFence(f->getOrder());
200 :
201 172577 : _fence->setTag(getName());
202 :
203 172577 : _fence->addRelease([dev = _device, pool = _pool, loop = q.getLoop()] (bool success) {
204 172577 : dev->releaseCommandPool(*loop, Rc<CommandPool>(pool));
205 172577 : }, nullptr, "RenderPassHandle::submit dev->releaseCommandPool");
206 172577 : _fence->addRelease([this, func = move(onComplete), q = &q] (bool success) mutable {
207 172577 : doComplete(*q, move(func), success);
208 172577 : }, this, "RenderPassHandle::submit onComplete");
209 :
210 172577 : _sync = move(sync);
211 :
212 172577 : auto ops = getQueueOps();
213 :
214 172577 : _device->acquireQueue(ops, *f.get(), [this, onSubmited = move(onSubmited)] (FrameHandle &frame, const Rc<DeviceQueue> &queue) mutable {
215 172577 : _queue = queue;
216 :
217 172577 : frame.performInQueue([this, onSubmited = move(onSubmited)] (FrameHandle &frame) mutable {
218 172569 : if (!doSubmit(frame, move(onSubmited))) {
219 0 : return false;
220 : }
221 172577 : return true;
222 : }, this, "RenderPass::submit");
223 172577 : }, [this] (FrameHandle &frame) {
224 0 : _sync = nullptr;
225 0 : invalidate();
226 0 : }, this);
227 172577 : }
228 :
229 172766 : void QueuePassHandle::finalize(FrameQueue &, bool success) {
230 :
231 172766 : }
232 :
233 342980 : QueueOperations QueuePassHandle::getQueueOps() const {
234 342980 : return (static_cast<vk::QueuePass *>(_queuePass.get()))->getQueueOps();
235 : }
236 :
237 100800 : Vector<const CommandBuffer *> QueuePassHandle::doPrepareCommands(FrameHandle &handle) {
238 100800 : auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
239 100800 : auto pass = _data->impl.cast<vk::RenderPass>().get();
240 100800 : auto queue = handle.getFrameQueue(_data->queue->queue);
241 100800 : pass->perform(*this, buf, [&, this] {
242 100800 : size_t i = 0;
243 277200 : for (auto &it : _data->subpasses) {
244 176400 : if (it->commandsCallback != nullptr) {
245 176400 : it->commandsCallback(*it, *queue, buf);
246 : }
247 176400 : if (i + 2 < _data->subpasses.size()) {
248 50400 : buf.cmdNextSubpass();
249 : }
250 176400 : ++ i;
251 : }
252 100800 : });
253 100800 : return true;
254 : });
255 100800 : return Vector<const CommandBuffer *>{buf};
256 : }
257 :
258 172568 : bool QueuePassHandle::doSubmit(FrameHandle &frame, Function<void(bool)> &&onSubmited) {
259 172568 : auto success = _queue->submit(*_sync, *_fence, *_pool, _buffers, _queueIdleMode);
260 172570 : _pool = nullptr;
261 172570 : frame.performOnGlThread([this, success, onSubmited = move(onSubmited), queue = move(_queue), armedTime = _fence->getArmedTime()] (FrameHandle &frame) mutable {
262 172577 : _queueData->submitTime = armedTime;
263 :
264 172577 : if (queue) {
265 172577 : _device->releaseQueue(move(queue));
266 172577 : queue = nullptr;
267 : }
268 :
269 172577 : doSubmitted(frame, move(onSubmited), success, move(_fence));
270 172577 : _fence = nullptr;
271 172577 : invalidate();
272 :
273 172577 : if (!success) {
274 0 : log::error("VK-Error", "Fail to vkQueueSubmit");
275 : }
276 172577 : _sync = nullptr;
277 172577 : }, nullptr, false, "RenderPassHandle::doSubmit");
278 172577 : return success;
279 : }
280 :
281 172577 : void QueuePassHandle::doSubmitted(FrameHandle &handle, Function<void(bool)> &&func, bool success, Rc<Fence> &&fence) {
282 172577 : auto queue = handle.getFrameQueue(_data->queue->queue);
283 348977 : for (auto &it : _data->submittedCallbacks) {
284 176400 : it(*_data, *queue, success);
285 : }
286 :
287 172577 : func(success);
288 :
289 172577 : fence->schedule(*_loop);
290 172577 : }
291 :
292 172577 : void QueuePassHandle::doComplete(FrameQueue &queue, Function<void(bool)> &&func, bool success) {
293 172577 : for (auto &it : _data->completeCallbacks) {
294 0 : it(*_data, queue, success);
295 : }
296 :
297 172577 : func(success);
298 172577 : }
299 :
300 9517 : void QueuePassHandle::doFinalizeTransfer(core::MaterialSet * materials,
301 : Vector<ImageMemoryBarrier> &outputImageBarriers, Vector<BufferMemoryBarrier> &outputBufferBarriers) {
302 9517 : if (!materials) {
303 0 : return;
304 : }
305 :
306 9517 : auto b = static_cast<Buffer *>(materials->getBuffer().get());
307 9517 : if (!b) {
308 0 : return;
309 : }
310 :
311 9517 : if (auto barrier = b->getPendingBarrier()) {
312 1130 : outputBufferBarriers.emplace_back(*barrier);
313 1130 : b->dropPendingBarrier();
314 : }
315 :
316 19034 : for (auto &it : materials->getLayouts()) {
317 9517 : if (it.set) {
318 9517 : auto &pendingImageBarriers = (static_cast<TextureSet *>(it.set.get()))->getPendingImageBarriers();
319 10604 : for (auto &barrier : pendingImageBarriers) {
320 1087 : outputImageBarriers.emplace_back(barrier);
321 : }
322 9517 : auto &pendingBufferBarriers = (static_cast<TextureSet *>(it.set.get()))->getPendingBufferBarriers();
323 25013 : for (auto &barrier : pendingBufferBarriers) {
324 15496 : outputBufferBarriers.emplace_back(barrier);
325 : }
326 9517 : static_cast<TextureSet *>(it.set.get())->dropPendingBarriers();
327 : } else {
328 0 : log::error("MaterialRenderPassHandle", "No set for material layout");
329 : }
330 : }
331 : }
332 :
333 1214 : auto QueuePassHandle::updateMaterials(FrameHandle &frame, const Rc<core::MaterialSet> &data, const Vector<Rc<core::Material>> &materials,
334 : SpanView<core::MaterialId> dynamicMaterials, SpanView<core::MaterialId> materialsToRemove) -> MaterialBuffers {
335 1214 : MaterialBuffers ret;
336 1214 : auto &layout = _device->getTextureSetLayout();
337 :
338 : // update list of materials in set
339 2468 : auto updated = data->updateMaterials(materials, dynamicMaterials, materialsToRemove, [&, this] (const core::MaterialImage &image) -> Rc<core::ImageView> {
340 2468 : return Rc<ImageView>::create(*_device, static_cast<Image *>(image.image->image.get()), image.info);
341 1214 : });
342 1214 : if (updated.empty()) {
343 0 : return MaterialBuffers();
344 : }
345 :
346 2428 : for (auto &it : data->getLayouts()) {
347 1214 : frame.performRequiredTask([layout, data, target = &it] (FrameHandle &handle) {
348 1214 : auto dev = static_cast<Device *>(handle.getDevice());
349 :
350 1214 : target->set = Rc<TextureSet>(layout->acquireSet(*dev));
351 1214 : target->set->write(*target);
352 1214 : return true;
353 : }, this, "RenderPassHandle::updateMaterials");
354 : }
355 :
356 1214 : auto &bufferInfo = data->getInfo();
357 :
358 1214 : auto &pool = static_cast<DeviceFrameHandle &>(frame).getMemPool(&frame);
359 :
360 3642 : ret.stagingBuffer = pool->spawn(AllocationUsage::HostTransitionSource,
361 3642 : BufferInfo(core::ForceBufferUsage(core::BufferUsage::TransferSrc), bufferInfo.size));
362 1214 : ret.targetBuffer = pool->spawnPersistent(AllocationUsage::DeviceLocal, bufferInfo);
363 :
364 1214 : ret.stagingBuffer->map([&] (uint8_t *mapped, VkDeviceSize) {
365 1214 : uint32_t idx = 0;
366 1214 : ret.ordering.reserve(data->getMaterials().size());
367 :
368 1214 : uint8_t *target = mapped;
369 10768 : for (auto &it : data->getMaterials()) {
370 9554 : data->encode(target, it.second.get());
371 9554 : target += data->getObjectSize();
372 9554 : ret.ordering.emplace(it.first, idx);
373 9554 : ++ idx;
374 : }
375 1214 : });
376 1214 : return ret;
377 1214 : }
378 :
379 0 : vk::ComputePipeline *QueuePassHandle::getComputePipelineByName(uint32_t subpass, StringView name) const {
380 0 : if (_data->subpasses.size() > subpass) {
381 0 : auto pipelineIt = _data->subpasses[subpass]->computePipelines.find(name);
382 0 : if (pipelineIt != _data->subpasses[subpass]->computePipelines.end()) {
383 0 : return static_cast<vk::ComputePipeline *>((*pipelineIt)->pipeline.get());
384 : }
385 : }
386 0 : return nullptr;
387 : }
388 :
389 0 : vk::ComputePipeline *QueuePassHandle::getComputePipelineBySubName(uint32_t subpass, StringView subname) const {
390 0 : if (_data->subpasses.size() > subpass) {
391 0 : auto pipelineIt = _data->subpasses[subpass]->computePipelines.find(toString(_data->key, "_", subname));
392 0 : if (pipelineIt != _data->subpasses[subpass]->computePipelines.end()) {
393 0 : return static_cast<vk::ComputePipeline *>((*pipelineIt)->pipeline.get());
394 : }
395 : }
396 0 : return nullptr;
397 : }
398 :
399 0 : vk::GraphicPipeline *QueuePassHandle::getGraphicPipelineByName(uint32_t subpass, StringView name) const {
400 0 : if (_data->subpasses.size() > subpass) {
401 0 : auto pipelineIt = _data->subpasses[subpass]->graphicPipelines.find(name);
402 0 : if (pipelineIt != _data->subpasses[subpass]->graphicPipelines.end()) {
403 0 : return static_cast<vk::GraphicPipeline *>((*pipelineIt)->pipeline.get());
404 : }
405 : }
406 0 : return nullptr;
407 : }
408 :
409 0 : vk::GraphicPipeline *QueuePassHandle::getGraphicPipelineBySubName(uint32_t subpass, StringView subname) const {
410 0 : if (_data->subpasses.size() > subpass) {
411 0 : auto pipelineIt = _data->subpasses[subpass]->graphicPipelines.find(toString(_data->key, "_", subname));
412 0 : if (pipelineIt != _data->subpasses[subpass]->graphicPipelines.end()) {
413 0 : return static_cast<vk::GraphicPipeline *>((*pipelineIt)->pipeline.get());
414 : }
415 : }
416 0 : return nullptr;
417 : }
418 :
419 21 : QueuePassHandle::ImageInputOutputBarrier QueuePassHandle::getImageInputOutputBarrier(Device *dev, Image *image, ImageAttachmentHandle &handle) const {
420 21 : ImageInputOutputBarrier ret;
421 :
422 21 : auto attachmentData = handle.getAttachment()->getData();
423 21 : auto passData = _queuePass->getData();
424 :
425 21 : size_t passIdx = 0;
426 21 : core::AttachmentPassData *prev = nullptr;
427 21 : core::AttachmentPassData *current = nullptr;
428 21 : core::AttachmentPassData *next = nullptr;
429 :
430 21 : for (auto &it : attachmentData->passes) {
431 21 : if (it->pass == passData) {
432 21 : current = it;
433 21 : break;
434 : }
435 0 : ++ passIdx;
436 : }
437 :
438 21 : if (passIdx > 0) {
439 0 : prev = attachmentData->passes[passIdx - 1];
440 : }
441 21 : if (passIdx + 1 < attachmentData->passes.size()) {
442 0 : next = attachmentData->passes[passIdx + 1];
443 : }
444 :
445 21 : if (prev) {
446 0 : bool hasLayoutTransition = current->initialLayout != prev->finalLayout && current->initialLayout != core::AttachmentLayout::Ignored;
447 0 : bool hasReadWriteTransition = false;
448 0 : if (core::hasReadAccess(current->dependency.initialAccessMask) && core::hasWriteAccess(prev->dependency.finalAccessMask)) {
449 0 : hasReadWriteTransition = true;
450 : }
451 :
452 0 : bool hasOwnershipTransfer = false;
453 0 : if (current->pass->type != prev->pass->type) {
454 0 : auto prevQueue = dev->getQueueFamily(prev->pass->type);
455 0 : auto currentQueue = dev->getQueueFamily(current->pass->type);
456 0 : if (prevQueue != currentQueue) {
457 0 : hasOwnershipTransfer = true;
458 0 : ret.input.familyTransfer = QueueFamilyTransfer{prevQueue->index, currentQueue->index};
459 : }
460 : }
461 :
462 0 : if (hasOwnershipTransfer || hasLayoutTransition || hasReadWriteTransition) {
463 0 : ret.input.image = image;
464 0 : ret.input.oldLayout = VkImageLayout(prev->finalLayout);
465 0 : ret.input.newLayout = VkImageLayout(current->initialLayout);
466 0 : ret.input.srcAccessMask = VkAccessFlags(prev->dependency.finalAccessMask);
467 0 : ret.input.dstAccessMask = VkAccessFlags(current->dependency.initialAccessMask);
468 0 : ret.input.subresourceRange = VkImageSubresourceRange{
469 0 : image->getAspectMask(), 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS
470 : };
471 0 : ret.inputFrom = prev->dependency.finalUsageStage;
472 0 : ret.inputTo = current->dependency.initialUsageStage;
473 : }
474 : } else {
475 : // initial image transition
476 21 : if (current->initialLayout != core::AttachmentLayout::Undefined) {
477 21 : ret.input.image = image;
478 21 : ret.input.oldLayout = VkImageLayout(core::AttachmentLayout::Undefined);
479 21 : ret.input.newLayout = VkImageLayout(current->initialLayout);
480 21 : ret.input.srcAccessMask = 0;
481 21 : ret.input.dstAccessMask = VkAccessFlags(current->dependency.initialAccessMask);
482 21 : ret.input.subresourceRange = VkImageSubresourceRange{
483 21 : image->getAspectMask(), 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS
484 : };
485 21 : ret.inputFrom = core::PipelineStage::AllCommands;
486 21 : ret.inputTo = current->dependency.initialUsageStage;
487 : }
488 : }
489 :
490 21 : if (next) {
491 0 : if (current->pass->type != next->pass->type) {
492 0 : auto nextQueue = dev->getQueueFamily(next->pass->type);
493 0 : auto currentQueue = dev->getQueueFamily(current->pass->type);
494 0 : if (nextQueue != currentQueue) {
495 0 : ret.output.familyTransfer = QueueFamilyTransfer{currentQueue->index, nextQueue->index};
496 0 : ret.output.image = image;
497 0 : ret.output.oldLayout = VkImageLayout(current->finalLayout);
498 0 : ret.output.newLayout = VkImageLayout(next->initialLayout);
499 0 : ret.output.srcAccessMask = VkAccessFlags(current->dependency.finalAccessMask);
500 0 : ret.output.dstAccessMask = VkAccessFlags(next->dependency.initialAccessMask);
501 0 : ret.output.subresourceRange = VkImageSubresourceRange{
502 0 : image->getAspectMask(), 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS
503 : };
504 0 : ret.outputFrom = current->dependency.finalUsageStage;
505 0 : ret.outputTo = next->dependency.initialUsageStage;
506 : }
507 : }
508 : }
509 :
510 21 : return ret;
511 : }
512 :
513 201549 : QueuePassHandle::BufferInputOutputBarrier QueuePassHandle::getBufferInputOutputBarrier(Device *dev, Buffer *buffer, BufferAttachmentHandle &handle,
514 : VkDeviceSize offset, VkDeviceSize size) const {
515 201549 : BufferInputOutputBarrier ret;
516 :
517 201548 : auto attachmentData = handle.getAttachment()->getData();
518 201550 : auto passData = _queuePass->getData();
519 :
520 201546 : size_t passIdx = 0;
521 201546 : core::AttachmentPassData *prev = nullptr;
522 201546 : core::AttachmentPassData *current = nullptr;
523 201546 : core::AttachmentPassData *next = nullptr;
524 :
525 201546 : for (auto &it : attachmentData->passes) {
526 201540 : if (it->pass == passData) {
527 201540 : current = it;
528 201540 : break;
529 : }
530 0 : ++ passIdx;
531 : }
532 :
533 201540 : if (passIdx > 0) {
534 0 : prev = attachmentData->passes[passIdx - 1];
535 : }
536 201540 : if (passIdx + 1 < attachmentData->passes.size()) {
537 50397 : next = attachmentData->passes[passIdx + 1];
538 : }
539 :
540 201544 : if (prev) {
541 0 : bool hasReadWriteTransition = false;
542 0 : if (core::hasReadAccess(current->dependency.initialAccessMask) && core::hasWriteAccess(prev->dependency.finalAccessMask)) {
543 0 : hasReadWriteTransition = true;
544 : }
545 :
546 0 : bool hasOwnershipTransfer = false;
547 0 : if (current->pass->type != prev->pass->type) {
548 0 : auto prevQueue = dev->getQueueFamily(prev->pass->type);
549 0 : auto currentQueue = dev->getQueueFamily(current->pass->type);
550 0 : if (prevQueue != currentQueue) {
551 0 : hasOwnershipTransfer = true;
552 0 : ret.input.familyTransfer = QueueFamilyTransfer{prevQueue->index, currentQueue->index};
553 : }
554 : }
555 :
556 0 : if (hasOwnershipTransfer || hasReadWriteTransition) {
557 0 : ret.input.buffer = buffer;
558 0 : ret.input.srcAccessMask = VkAccessFlags(prev->dependency.finalAccessMask);
559 0 : ret.input.dstAccessMask = VkAccessFlags(current->dependency.initialAccessMask);
560 0 : ret.input.offset = offset;
561 0 : ret.input.size = size;
562 0 : ret.inputFrom = prev->dependency.finalUsageStage;
563 0 : ret.inputTo = current->dependency.initialUsageStage;
564 : }
565 : }
566 :
567 201544 : if (next) {
568 50397 : if (current->pass->type != next->pass->type) {
569 0 : auto nextQueue = dev->getQueueFamily(next->pass->type);
570 0 : auto currentQueue = dev->getQueueFamily(current->pass->type);
571 9 : if (nextQueue != currentQueue) {
572 0 : ret.output.familyTransfer = QueueFamilyTransfer{currentQueue->index, nextQueue->index};
573 0 : ret.output.buffer = buffer;
574 0 : ret.output.srcAccessMask = VkAccessFlags(current->dependency.finalAccessMask);
575 0 : ret.output.dstAccessMask = VkAccessFlags(next->dependency.initialAccessMask);
576 0 : ret.output.offset = offset;
577 0 : ret.output.size = size;
578 0 : ret.outputFrom = current->dependency.finalUsageStage;
579 0 : ret.outputTo = next->dependency.initialUsageStage;
580 : }
581 : }
582 : }
583 :
584 201553 : return ret;
585 : }
586 :
587 0 : void QueuePassHandle::setQueueIdleMode(DeviceQueue::IdleMode mode) {
588 0 : _queueIdleMode = mode;
589 0 : }
590 :
591 : }
|