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 "XLCoreQueue.h"
25 : #include "XLCoreAttachment.h"
26 : #include "XLCoreResource.h"
27 : #include "XLCoreDevice.h"
28 : #include "XLCoreQueuePass.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::xenolith::core {
31 :
32 : template <typename T>
33 : static T * Resource_conditionalInsert(HashTable<T *> &vec, StringView key, const Callback<T *()> &cb, memory::pool_t *pool);
34 :
35 176 : static void Queue_buildLoadStore(QueueData *data) {
36 752 : for (auto &attachment : data->attachments) {
37 576 : if (attachment->type != AttachmentType::Image) {
38 496 : continue;
39 : }
40 :
41 80 : auto img = (ImageAttachment *)attachment->attachment.get();
42 :
43 80 : bool hasColor = false;
44 80 : bool hasStencil = false;
45 80 : switch (img->getImageInfo().format) {
46 0 : case ImageFormat::S8_UINT:
47 0 : hasStencil = true;
48 0 : break;
49 0 : case ImageFormat::D16_UNORM_S8_UINT:
50 : case ImageFormat::D24_UNORM_S8_UINT:
51 : case ImageFormat::D32_SFLOAT_S8_UINT:
52 0 : hasColor = true;
53 0 : hasStencil = true;
54 0 : break;
55 80 : default:
56 80 : hasColor = true;
57 80 : break;
58 : }
59 :
60 176 : for (auto &descriptor : attachment->passes) {
61 96 : if (descriptor->ops != AttachmentOps::Undefined) {
62 : // operations was hinted, no heuristics required
63 0 : continue;
64 : }
65 :
66 96 : AttachmentOps ops = AttachmentOps::Undefined;
67 176 : for (auto &it : descriptor->subpasses) {
68 80 : if (it->ops != AttachmentOps::Undefined) {
69 0 : ops |= it->ops;
70 0 : continue;
71 : }
72 :
73 80 : AttachmentOps refOps = AttachmentOps::Undefined;
74 80 : bool hasWriters = false;
75 80 : bool hasReaders = false;
76 80 : bool colorReadOnly = true;
77 80 : bool stencilReadOnly = true;
78 :
79 80 : if ((it->usage & AttachmentUsage::Output) != AttachmentUsage::None
80 32 : || (it->usage & AttachmentUsage::Resolve) != AttachmentUsage::None
81 112 : || (it->usage & AttachmentUsage::DepthStencil) != AttachmentUsage::None) {
82 64 : hasWriters = true;
83 : }
84 80 : if ((it->usage & AttachmentUsage::Input) != AttachmentUsage::None
85 80 : || (it->usage & AttachmentUsage::DepthStencil) != AttachmentUsage::None) {
86 32 : hasReaders = true;
87 : }
88 80 : if ((it->usage & AttachmentUsage::DepthStencil) != AttachmentUsage::None) {
89 16 : switch (it->layout) {
90 16 : case AttachmentLayout::DepthStencilAttachmentOptimal:
91 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
92 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
93 : case AttachmentLayout::DepthAttachmentOptimal:
94 : case AttachmentLayout::StencilAttachmentOptimal:
95 : case AttachmentLayout::General:
96 16 : hasWriters = true;
97 16 : break;
98 0 : default:
99 0 : break;
100 : }
101 : }
102 :
103 80 : switch (it->layout) {
104 16 : case AttachmentLayout::General:
105 : case AttachmentLayout::DepthStencilAttachmentOptimal:
106 16 : stencilReadOnly = false;
107 16 : colorReadOnly = false;
108 16 : break;
109 48 : case AttachmentLayout::ColorAttachmentOptimal:
110 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
111 : case AttachmentLayout::DepthAttachmentOptimal:
112 48 : colorReadOnly = false;
113 48 : break;
114 0 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
115 : case AttachmentLayout::StencilAttachmentOptimal:
116 0 : stencilReadOnly = false;
117 0 : break;
118 16 : default:
119 16 : break;
120 : }
121 :
122 80 : if (hasWriters) {
123 64 : if (hasColor && !colorReadOnly) {
124 64 : refOps |= AttachmentOps::WritesColor;
125 : }
126 64 : if (hasStencil && !stencilReadOnly) {
127 0 : refOps |= AttachmentOps::WritesStencil;
128 : }
129 : }
130 :
131 80 : if (hasReaders) {
132 32 : if (hasColor) {
133 32 : refOps |= AttachmentOps::ReadColor;
134 : }
135 32 : if (hasStencil) {
136 0 : refOps |= AttachmentOps::ReadStencil;
137 : }
138 : }
139 :
140 80 : it->ops = refOps;
141 80 : ops |= refOps;
142 : }
143 96 : descriptor->ops = ops;
144 : }
145 : };
146 :
147 64 : auto dataWasWritten = [] (AttachmentData *data, uint32_t idx) -> Pair<bool, bool> {
148 64 : if ((data->usage & AttachmentUsage::Input) != AttachmentUsage::None) {
149 32 : if ((data->ops & (AttachmentOps::WritesColor | AttachmentOps::WritesStencil)) != AttachmentOps::Undefined) {
150 32 : return pair(true, true);
151 : }
152 : }
153 :
154 32 : bool colorWasWritten = (data->ops & AttachmentOps::WritesColor) != AttachmentOps::Undefined;
155 32 : bool stencilWasWritten = (data->ops & AttachmentOps::WritesStencil) != AttachmentOps::Undefined;
156 :
157 32 : auto &descriptors = data->passes;
158 32 : for (size_t i = 0; i < idx; ++ i) {
159 0 : auto desc = descriptors[i];
160 0 : if ((desc->ops & AttachmentOps::WritesColor) != AttachmentOps::Undefined) {
161 0 : colorWasWritten = true;
162 : }
163 0 : if ((desc->ops & AttachmentOps::WritesStencil) != AttachmentOps::Undefined) {
164 0 : stencilWasWritten = true;
165 : }
166 : }
167 :
168 32 : return pair(colorWasWritten, stencilWasWritten);
169 : };
170 :
171 64 : auto dataWillBeRead = [] (AttachmentData *data, uint32_t idx) -> Pair<bool, bool> {
172 64 : if ((data->usage & AttachmentUsage::Output) != AttachmentUsage::None) {
173 32 : if ((data->ops & (AttachmentOps::ReadColor | AttachmentOps::ReadStencil)) != AttachmentOps::Undefined) {
174 32 : return pair(true, true);
175 : }
176 : }
177 :
178 32 : bool colorWillBeRead = (data->ops & AttachmentOps::ReadColor) != AttachmentOps::Undefined;
179 32 : bool stencilWillBeRead = (data->ops & AttachmentOps::ReadStencil) != AttachmentOps::Undefined;
180 :
181 32 : auto &descriptors = data->passes;
182 64 : for (size_t i = idx + 1; i < descriptors.size(); ++ i) {
183 32 : auto desc = descriptors[i];
184 32 : if ((desc->ops & AttachmentOps::ReadColor) != AttachmentOps::Undefined) {
185 0 : colorWillBeRead = true;
186 : }
187 32 : if ((desc->ops & AttachmentOps::ReadStencil) != AttachmentOps::Undefined) {
188 0 : stencilWillBeRead = true;
189 : }
190 : }
191 :
192 32 : return pair(colorWillBeRead, stencilWillBeRead);
193 : };
194 :
195 : // fill layout chain
196 752 : for (auto &attachment : data->attachments) {
197 576 : if (attachment->passes.empty()) {
198 0 : continue;
199 : }
200 :
201 576 : if (attachment->passes.size() == 1 && attachment->usage == AttachmentUsage::None) {
202 192 : attachment->transient = true;
203 :
204 192 : if (attachment->type != AttachmentType::Image) {
205 160 : continue;
206 : }
207 :
208 32 : auto img = (ImageAttachment *)attachment->attachment.get();
209 64 : for (auto &desc : attachment->passes) {
210 32 : auto fmt = getImagePixelFormat(img->getImageInfo().format);
211 32 : switch (fmt) {
212 0 : case PixelFormat::DS:
213 : case PixelFormat::S:
214 0 : desc->loadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
215 0 : desc->stencilLoadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
216 0 : desc->storeOp = AttachmentStoreOp::DontCare;
217 0 : desc->stencilStoreOp = AttachmentStoreOp::DontCare;
218 0 : break;
219 32 : default:
220 32 : desc->loadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
221 32 : desc->stencilLoadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
222 32 : desc->storeOp = AttachmentStoreOp::DontCare;
223 32 : desc->stencilStoreOp = AttachmentStoreOp::DontCare;
224 32 : break;
225 : }
226 : }
227 : } else {
228 384 : if (attachment->type != AttachmentType::Image) {
229 336 : continue;
230 : }
231 :
232 48 : size_t descIndex = 0;
233 112 : for (auto &desc : attachment->passes) {
234 64 : auto wasWritten = dataWasWritten(attachment, descIndex); // Color, Stencil
235 64 : auto willBeRead = dataWillBeRead(attachment, descIndex);
236 :
237 64 : if (wasWritten.first) {
238 32 : if ((desc->ops & AttachmentOps::ReadColor) != AttachmentOps::Undefined) {
239 0 : desc->loadOp = AttachmentLoadOp::Load;
240 : } else {
241 32 : desc->loadOp = AttachmentLoadOp::DontCare;
242 : }
243 : } else {
244 32 : bool isRead = ((desc->ops & AttachmentOps::ReadColor) != AttachmentOps::Undefined);
245 32 : bool isWrite = ((desc->ops & AttachmentOps::WritesColor) != AttachmentOps::Undefined);
246 32 : if (isRead && !isWrite) {
247 0 : log::error("Gl-Error", "Attachment's color component '", attachment->key, "' is read in renderpass ",
248 0 : desc->pass->key, " before written");
249 : }
250 :
251 32 : auto img = (ImageAttachment *)attachment->attachment.get();
252 32 : desc->loadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
253 : }
254 :
255 64 : if (wasWritten.second) {
256 32 : if ((desc->ops & AttachmentOps::ReadStencil) != AttachmentOps::Undefined) {
257 0 : desc->stencilLoadOp = AttachmentLoadOp::Load;
258 : } else {
259 32 : desc->stencilLoadOp = AttachmentLoadOp::DontCare;
260 : }
261 : } else {
262 32 : bool isRead = ((desc->ops & AttachmentOps::ReadStencil) != AttachmentOps::Undefined);
263 32 : bool isWrite = ((desc->ops & AttachmentOps::WritesStencil) != AttachmentOps::Undefined);
264 32 : if (isRead && !isWrite) {
265 0 : log::error("Gl-Error", "Attachment's stencil component '", attachment->key, "' is read in renderpass ",
266 0 : desc->pass->key, " before written");
267 : }
268 32 : auto img = (ImageAttachment *)attachment->attachment.get();
269 32 : desc->stencilLoadOp = img->shouldClearOnLoad() ? AttachmentLoadOp::Clear : AttachmentLoadOp::DontCare;
270 : }
271 :
272 64 : if (willBeRead.first) {
273 32 : if ((desc->ops & AttachmentOps::WritesColor) != AttachmentOps::Undefined) {
274 16 : desc->storeOp = AttachmentStoreOp::Store;
275 : } else {
276 16 : desc->storeOp = AttachmentStoreOp::DontCare;
277 : }
278 : } else {
279 32 : bool isRead = ((desc->ops & AttachmentOps::ReadColor) != AttachmentOps::Undefined);
280 32 : bool isWrite = ((desc->ops & AttachmentOps::WritesColor) != AttachmentOps::Undefined);
281 32 : if (!isRead && isWrite) {
282 0 : log::error("Gl-Error", "Attachment's color component '", attachment->key, "' is written in renderpass ",
283 0 : desc->pass->key, " but never read");
284 : }
285 32 : desc->storeOp = AttachmentStoreOp::DontCare;
286 : }
287 :
288 64 : if (willBeRead.second) {
289 32 : if ((desc->ops & AttachmentOps::WritesStencil) != AttachmentOps::Undefined) {
290 0 : desc->stencilStoreOp = AttachmentStoreOp::Store;
291 : } else {
292 32 : desc->stencilStoreOp = AttachmentStoreOp::DontCare;
293 : }
294 : } else {
295 32 : bool isRead = ((desc->ops & AttachmentOps::ReadStencil) != AttachmentOps::Undefined);
296 32 : bool isWrite = ((desc->ops & AttachmentOps::WritesStencil) != AttachmentOps::Undefined);
297 32 : if (!isRead && isWrite) {
298 0 : log::error("Gl-Error", "Attachment's stencil component '", attachment->key, "' is writen in renderpass ",
299 0 : desc->pass->key, " but never read");
300 : }
301 32 : desc->stencilStoreOp = AttachmentStoreOp::DontCare;
302 : }
303 : }
304 48 : ++ descIndex;
305 : }
306 :
307 80 : if (attachment->type != AttachmentType::Image) {
308 0 : continue;
309 : }
310 :
311 80 : auto img = (ImageAttachment *)attachment->attachment.get();
312 80 : AttachmentLayout layout = img->getInitialLayout();
313 176 : for (auto &desc : attachment->passes) {
314 96 : if (desc->initialLayout == AttachmentLayout::Ignored) {
315 96 : if (layout == AttachmentLayout::Ignored && !desc->subpasses.empty()) {
316 0 : desc->initialLayout = desc->subpasses.front()->layout;
317 : } else {
318 96 : desc->initialLayout = layout;
319 : }
320 : }
321 96 : if (desc->finalLayout == AttachmentLayout::Ignored) {
322 96 : if (!desc->subpasses.empty()) {
323 48 : layout = desc->subpasses.back()->layout;
324 48 : desc->finalLayout = layout;
325 : } else {
326 48 : desc->finalLayout = desc->initialLayout;
327 : }
328 : }
329 : }
330 80 : if (img->getFinalLayout() != AttachmentLayout::Ignored) {
331 80 : attachment->passes.back()->finalLayout = img->getFinalLayout();
332 : }
333 : }
334 176 : }
335 :
336 176 : static void Queue_buildDescriptors(QueueData *data, Device &dev) {
337 448 : for (auto &pass : data->passes) {
338 272 : if (pass->pass->getType() == PassType::Graphics) {
339 48 : for (auto &subpass : pass->subpasses) {
340 80 : for (auto a : subpass->outputImages) {
341 48 : if (a->pass->attachment->type == AttachmentType::Image) {
342 48 : auto desc = (ImageAttachment *)a->pass->attachment->attachment.get();
343 48 : desc->addImageUsage(ImageUsage::ColorAttachment);
344 : }
345 : }
346 32 : for (auto a : subpass->resolveImages) {
347 0 : if (a->pass->attachment->type == AttachmentType::Image) {
348 0 : auto desc = (ImageAttachment *)a->pass->attachment->attachment.get();
349 0 : desc->addImageUsage(ImageUsage::ColorAttachment);
350 : }
351 : }
352 48 : for (auto a : subpass->inputImages) {
353 16 : if (a->pass->attachment->type == AttachmentType::Image) {
354 16 : auto desc = (ImageAttachment *)a->pass->attachment->attachment.get();
355 16 : desc->addImageUsage(ImageUsage::InputAttachment);
356 : }
357 : }
358 32 : if (subpass->depthStencil) {
359 16 : if (subpass->depthStencil->pass->attachment->type == AttachmentType::Image) {
360 16 : auto desc = (ImageAttachment *)subpass->depthStencil->pass->attachment->attachment.get();
361 16 : desc->addImageUsage(ImageUsage::DepthStencilAttachment);
362 : }
363 : }
364 : }
365 : }
366 :
367 976 : for (auto &attachment : pass->attachments) {
368 704 : if (attachment->attachment->type == AttachmentType::Image) {
369 96 : auto desc = (ImageAttachment *)attachment->attachment->attachment.get();
370 96 : switch (attachment->finalLayout) {
371 64 : case AttachmentLayout::Undefined:
372 : case AttachmentLayout::General:
373 : case AttachmentLayout::ShaderReadOnlyOptimal:
374 : case AttachmentLayout::Preinitialized:
375 : case AttachmentLayout::Ignored:
376 64 : break;
377 16 : case AttachmentLayout::PresentSrc:
378 : // in alternative mode, images can be presented via transfer
379 16 : desc->addImageUsage(ImageUsage::TransferSrc);
380 16 : break;
381 0 : case AttachmentLayout::ColorAttachmentOptimal:
382 0 : desc->addImageUsage(ImageUsage::ColorAttachment);
383 0 : break;
384 0 : case AttachmentLayout::TransferSrcOptimal:
385 0 : desc->addImageUsage(ImageUsage::TransferSrc);
386 0 : break;
387 0 : case AttachmentLayout::TransferDstOptimal:
388 0 : desc->addImageUsage(ImageUsage::TransferDst);
389 0 : break;
390 16 : case AttachmentLayout::DepthStencilAttachmentOptimal:
391 : case AttachmentLayout::DepthStencilReadOnlyOptimal:
392 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
393 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
394 : case AttachmentLayout::DepthAttachmentOptimal:
395 : case AttachmentLayout::DepthReadOnlyOptimal:
396 : case AttachmentLayout::StencilAttachmentOptimal:
397 : case AttachmentLayout::StencilReadOnlyOptimal:
398 16 : desc->addImageUsage(ImageUsage::DepthStencilAttachment);
399 16 : break;
400 : }
401 : }
402 : }
403 :
404 464 : for (auto &layout : pass->pipelineLayouts) {
405 384 : for (auto &set : layout->sets) {
406 528 : for (auto &desc : set->descriptors) {
407 336 : if (desc->type != DescriptorType::Unknown) {
408 336 : if (dev.supportsUpdateAfterBind(desc->type)) {
409 320 : desc->updateAfterBind = true;
410 320 : pass->hasUpdateAfterBind = true;
411 : }
412 : }
413 : }
414 : }
415 : }
416 : }
417 176 : }
418 :
419 128 : static void Queue_addRequiredPass(QueuePassData &pass, const QueuePassData &required,
420 : const AttachmentData &attachment, const AttachmentPassData &desc, FrameRenderPassState defaultSync) {
421 128 : auto requiredState = (desc.dependency.requiredRenderPassState == FrameRenderPassState::Initial) ?
422 128 : defaultSync : desc.dependency.requiredRenderPassState;
423 128 : auto lockedState = desc.dependency.lockedRenderPassState;
424 128 : if (requiredState == FrameRenderPassState::Initial) {
425 0 : return;
426 : }
427 :
428 128 : auto lb = std::lower_bound(pass.required.begin(), pass.required.end(), &required,
429 48 : [&] (const QueuePassRequirements &l, const QueuePassData *r) {
430 48 : return l.data < r;
431 128 : });
432 128 : if (lb == pass.required.end()) {
433 90 : pass.required.emplace_back(QueuePassRequirements(required, requiredState, lockedState));
434 38 : } else if (lb->data != &required) {
435 6 : pass.required.emplace(lb, QueuePassRequirements(required, requiredState, lockedState));
436 : } else {
437 32 : lb->requiredState = FrameRenderPassState(std::max(toInt(lb->requiredState), toInt(requiredState)));
438 32 : lb->lockedState = FrameRenderPassState(std::min(toInt(lb->lockedState), toInt(lockedState)));
439 : }
440 : }
441 :
442 128 : static void Queue_addDirectDependency(QueueData *data, const AttachmentPassData &source, const AttachmentPassData &target) {
443 128 : if (target.dependency.initialUsageStage == PipelineStage::None) {
444 : // no pipeline stage specified for synchronization
445 48 : return;
446 : }
447 :
448 240 : for (auto &it : data->passDependencies) {
449 160 : if (it.source == source.pass && it.target == target.pass) {
450 0 : it.attachments.emplace_back(source.attachment);
451 0 : if (target.dependency.initialUsageStage != PipelineStage::None) {
452 0 : it.stageFlags |= target.dependency.initialUsageStage;
453 : }
454 0 : return;
455 : }
456 : }
457 :
458 160 : auto &it = data->passDependencies.emplace_back(QueuePassDependency{
459 80 : source.pass,
460 80 : target.pass,
461 80 : memory::vector<const AttachmentData *>{ source.attachment },
462 80 : target.dependency.initialUsageStage
463 : });
464 :
465 80 : const_cast<QueuePassData *>(it.source)->sourceQueueDependencies.emplace_back(&it);
466 80 : const_cast<QueuePassData *>(it.target)->targetQueueDependencies.emplace_back(&it);
467 : }
468 :
469 176 : static void Queue_buildRequirements(QueueData *data, Device &dev) {
470 448 : for (auto &passIt : data->passes) {
471 976 : for (auto &a : passIt->attachments) {
472 704 : auto &desc = a->attachment->passes;
473 704 : auto it = desc.begin();
474 832 : while (it != desc.end() && (*it)->pass != passIt) {
475 128 : Queue_addRequiredPass(*passIt, *(*it)->pass, *a->attachment, **it, data->defaultSyncPassState);
476 :
477 128 : if ((*(it + 1))->pass == passIt) {
478 : // direct dependency
479 128 : Queue_addDirectDependency(data, *(*it), **(it + 1));
480 : }
481 :
482 128 : ++ it;
483 : }
484 : }
485 : }
486 176 : }
487 :
488 80 : static void Queue_updateLayout(AttachmentSubpassData *attachemnt, Device &dev) {
489 80 : if (attachemnt->pass->attachment->type != AttachmentType::Image) {
490 0 : return;
491 : }
492 :
493 80 : auto a = (ImageAttachment *)attachemnt->pass->attachment->attachment.get();
494 :
495 80 : auto fmt = a->getImageInfo().format;
496 :
497 80 : bool separateDepthStencil = false;
498 80 : bool hasColor = false;
499 80 : bool hasDepth = false;
500 80 : bool hasStencil = false;
501 :
502 80 : switch (fmt) {
503 16 : case ImageFormat::D16_UNORM:
504 : case ImageFormat::X8_D24_UNORM_PACK32:
505 : case ImageFormat::D32_SFLOAT:
506 16 : hasDepth = true;
507 16 : break;
508 0 : case ImageFormat::S8_UINT:
509 0 : hasStencil = true;
510 0 : break;
511 0 : case ImageFormat::D16_UNORM_S8_UINT:
512 : case ImageFormat::D24_UNORM_S8_UINT:
513 : case ImageFormat::D32_SFLOAT_S8_UINT:
514 0 : hasDepth = true;
515 0 : hasStencil = true;
516 0 : break;
517 64 : default:
518 64 : hasColor = true;
519 64 : break;
520 : }
521 :
522 80 : switch (attachemnt->usage) {
523 16 : case AttachmentUsage::Input:
524 16 : switch (attachemnt->layout) {
525 0 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
526 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
527 : case AttachmentLayout::DepthReadOnlyOptimal:
528 : case AttachmentLayout::StencilReadOnlyOptimal:
529 : case AttachmentLayout::DepthStencilReadOnlyOptimal:
530 : case AttachmentLayout::ShaderReadOnlyOptimal:
531 : case AttachmentLayout::General:
532 0 : break;
533 16 : case AttachmentLayout::Ignored:
534 16 : if (hasColor) {
535 16 : attachemnt->layout = AttachmentLayout::ShaderReadOnlyOptimal;
536 0 : } else if ((!separateDepthStencil && (hasDepth || hasStencil)) || (hasDepth && hasStencil)) {
537 0 : attachemnt->layout = AttachmentLayout::DepthStencilReadOnlyOptimal;
538 0 : } else if (hasDepth) {
539 0 : attachemnt->layout = AttachmentLayout::DepthReadOnlyOptimal;
540 0 : } else if (hasStencil) {
541 0 : attachemnt->layout = AttachmentLayout::StencilReadOnlyOptimal;
542 : } else {
543 0 : attachemnt->layout = AttachmentLayout::General;
544 : }
545 16 : break;
546 0 : default:
547 0 : log::error("Gl-Error", "Invalid layout for attachment '", attachemnt->key,
548 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
549 0 : break;
550 : }
551 16 : break;
552 48 : case AttachmentUsage::Output:
553 : case AttachmentUsage::Resolve:
554 48 : switch (attachemnt->layout) {
555 0 : case AttachmentLayout::ColorAttachmentOptimal:
556 : case AttachmentLayout::General:
557 0 : break;
558 48 : case AttachmentLayout::Ignored:
559 48 : attachemnt->layout = AttachmentLayout::ColorAttachmentOptimal;
560 48 : break;
561 0 : default:
562 0 : log::error("Gl-Error", "Invalid layout for attachment '", attachemnt->key,
563 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
564 0 : break;
565 : }
566 48 : break;
567 0 : case AttachmentUsage::InputOutput:
568 0 : switch (attachemnt->layout) {
569 0 : case AttachmentLayout::General:
570 0 : break;
571 0 : case AttachmentLayout::Ignored:
572 0 : attachemnt->layout = AttachmentLayout::General;
573 0 : break;
574 0 : default:
575 0 : log::error("Gl-Error", "Invalid layout for attachment '", attachemnt->key,
576 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
577 0 : break;
578 : }
579 0 : break;
580 16 : case AttachmentUsage::DepthStencil:
581 16 : switch (attachemnt->layout) {
582 0 : case AttachmentLayout::DepthStencilAttachmentOptimal:
583 : case AttachmentLayout::DepthAttachmentOptimal:
584 : case AttachmentLayout::DepthReadOnlyOptimal:
585 : case AttachmentLayout::StencilAttachmentOptimal:
586 : case AttachmentLayout::StencilReadOnlyOptimal:
587 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
588 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
589 : case AttachmentLayout::DepthStencilReadOnlyOptimal:
590 : case AttachmentLayout::General:
591 0 : break;
592 16 : case AttachmentLayout::Ignored:
593 16 : if ((!separateDepthStencil && (hasDepth || hasStencil)) || (hasDepth && hasStencil)) {
594 16 : attachemnt->layout = AttachmentLayout::DepthStencilAttachmentOptimal;
595 0 : } else if (hasDepth) {
596 0 : attachemnt->layout = AttachmentLayout::DepthAttachmentOptimal;
597 0 : } else if (hasStencil) {
598 0 : attachemnt->layout = AttachmentLayout::StencilAttachmentOptimal;
599 : } else {
600 0 : attachemnt->layout = AttachmentLayout::General;
601 : }
602 16 : break;
603 0 : default:
604 0 : log::error("Gl-Error", "Invalid layout for attachment '", attachemnt->key,
605 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
606 0 : break;
607 : }
608 16 : break;
609 0 : case AttachmentUsage::Input | AttachmentUsage::DepthStencil:
610 0 : switch (attachemnt->layout) {
611 0 : case AttachmentLayout::DepthReadOnlyStencilAttachmentOptimal:
612 : case AttachmentLayout::DepthAttachmentStencilReadOnlyOptimal:
613 : case AttachmentLayout::DepthStencilReadOnlyOptimal:
614 : case AttachmentLayout::General:
615 0 : break;
616 0 : case AttachmentLayout::Ignored:
617 0 : attachemnt->layout = AttachmentLayout::General;
618 0 : break;
619 0 : default:
620 0 : log::error("Gl-Error", "Invalid layout for attachment '", attachemnt->key,
621 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
622 0 : break;
623 : }
624 0 : break;
625 0 : default:
626 0 : log::error("Gl-Error", "Invalid usage for attachment '", attachemnt->key,
627 0 : "' in renderpass ", attachemnt->pass->pass->key, ":", attachemnt->subpass->index);
628 0 : break;
629 : }
630 : }
631 :
632 704 : static void Queue_sortRefs(AttachmentPassData *attachemnt, Device &dev) {
633 704 : std::sort(attachemnt->subpasses.begin(), attachemnt->subpasses.end(),
634 64 : [&] (const AttachmentSubpassData *l, const AttachmentSubpassData *r) {
635 64 : return l->subpass->index < r->subpass->index;
636 : });
637 :
638 784 : for (auto &it : attachemnt->subpasses) {
639 80 : Queue_updateLayout(it, dev);
640 :
641 80 : attachemnt->dependency.requiredRenderPassState = FrameRenderPassState(std::max(toInt(attachemnt->dependency.requiredRenderPassState),
642 160 : toInt(it->dependency.requiredRenderPassState)));
643 : }
644 :
645 704 : if (!attachemnt->subpasses.empty()) {
646 48 : attachemnt->dependency.initialUsageStage = attachemnt->subpasses.front()->dependency.initialUsageStage;
647 48 : attachemnt->dependency.initialAccessMask = attachemnt->subpasses.front()->dependency.initialAccessMask;
648 48 : attachemnt->dependency.finalUsageStage = attachemnt->subpasses.back()->dependency.finalUsageStage;
649 48 : attachemnt->dependency.finalAccessMask = attachemnt->subpasses.back()->dependency.finalAccessMask;
650 : }
651 704 : }
652 :
653 576 : static void Queue_sortDescriptors(AttachmentData *attachemnt, Device &dev) {
654 576 : Set<uint32_t> priorities;
655 :
656 1280 : for (auto &it : attachemnt->passes) {
657 704 : auto pass = it->pass;
658 704 : auto iit = priorities.find(pass->ordering.get());
659 704 : if (iit == priorities.end()) {
660 704 : priorities.emplace(pass->ordering.get());
661 : } else {
662 0 : log::error("Gl-Error", "Duplicate render pass priority '", pass->ordering.get(),
663 0 : "' for attachment '", attachemnt->key, "', render ordering can be invalid");
664 : }
665 : }
666 :
667 576 : std::sort(attachemnt->passes.begin(), attachemnt->passes.end(),
668 256 : [&] (const AttachmentPassData *l, const AttachmentPassData *r) {
669 256 : return l->pass->ordering < r->pass->ordering;
670 : });
671 :
672 1280 : for (auto &it : attachemnt->passes) {
673 704 : Queue_sortRefs(it, dev);
674 : }
675 576 : }
676 :
677 1312 : static void Queue_validateShaderPipelineLayout(StringView pipelineName, const PipelineLayoutData *layout, const ProgramInfo *info) {
678 1312 : bool hasTexturesArray = false;
679 1312 : bool hasSamplersArray = false;
680 1312 : bool hasAtlasArray = false;
681 4240 : for (auto &binding : info->bindings) {
682 2928 : auto set = binding.set;
683 2928 : auto desc = binding.descriptor;
684 :
685 2928 : if (set < layout->sets.size()) {
686 2528 : auto s = layout->sets[set];
687 2528 : if (desc < s->descriptors.size()) {
688 2528 : auto d = s->descriptors[desc];
689 :
690 2528 : if (d->type == DescriptorType::Unknown) {
691 128 : d->type = binding.type;
692 2400 : } else if (d->type != binding.type) {
693 0 : log::warn("renderqueue::Queue", "[", layout->key, ":", pipelineName, ":", set, ":", desc,
694 0 : "] descriptor type conflict: (code)", getDescriptorTypeName(d->type), " vs. (shader)",
695 0 : getDescriptorTypeName(binding.type));
696 : }
697 2528 : d->stages |= info->stage;
698 2528 : if (!d->countIsPredefined) {
699 1488 : if (binding.count < maxOf<uint32_t>()) {
700 1488 : d->count = std::max(binding.count, d->count);
701 : }
702 1040 : } else if (binding.count < maxOf<uint32_t>() && binding.count > d->count) {
703 0 : log::warn("renderqueue::Queue", "[", layout->key, ":", pipelineName, ":", set, ":", desc,
704 0 : "] descriptor requires ", binding.count, " objects, but only ", d->count, "defined with addDescriptorArray");
705 : }
706 : } else {
707 0 : log::warn("renderqueue::Queue", "[", layout->key, ":", pipelineName, ":", set, ":", desc,
708 : "] descriptor target not found");
709 : }
710 : } else {
711 400 : if (desc == 0 && binding.type == DescriptorType::Sampler) {
712 112 : hasTexturesArray = true;
713 288 : } else if (desc == 1 && binding.type == DescriptorType::SampledImage) {
714 96 : hasSamplersArray = true;
715 192 : } else if (desc == 2 && binding.type == DescriptorType::StorageBuffer) {
716 128 : hasAtlasArray = true;
717 : } else {
718 64 : log::warn("renderqueue::Queue", "[", layout->key, ":", pipelineName, ":", set, ":", desc,
719 : "] descriptor set not found");
720 : }
721 : }
722 : }
723 :
724 1312 : if (hasTexturesArray || hasSamplersArray || hasAtlasArray) {
725 128 : ((PipelineLayoutData *)layout)->usesTextureSet = true;
726 : }
727 1312 : }
728 :
729 192 : Queue::Queue() { }
730 :
731 224 : Queue::~Queue() {
732 192 : if (_data) {
733 192 : _data->clear();
734 192 : auto p = _data->pool;
735 192 : _data->~QueueData();
736 192 : memory::pool::destroy(p);
737 192 : _data = nullptr;
738 : }
739 224 : }
740 :
741 192 : bool Queue::init(Builder && buf) {
742 192 : Rc<Resource> res;
743 192 : if (!buf._internalResource.empty()) {
744 48 : res = Rc<Resource>::create(move(buf._internalResource));
745 : }
746 192 : if (buf._data) {
747 192 : _data = buf._data;
748 192 : _data->queue = this;
749 192 : buf._data = nullptr;
750 :
751 512 : for (auto &it : _data->passes) {
752 320 : it->pass->_data = it;
753 : }
754 :
755 192 : if (res) {
756 48 : _data->resource = res;
757 48 : _data->resource->setOwner(this);
758 : }
759 :
760 192 : return true;
761 : }
762 0 : return false;
763 192 : }
764 :
765 32 : bool Queue::isCompiled() const {
766 32 : return _data->compiled;
767 : }
768 :
769 144 : void Queue::setCompiled(Device &dev, Function<void()> &&cb) {
770 144 : _data->compiled = true;
771 :
772 688 : for (auto &attachment : _data->attachments) {
773 544 : attachment->attachment->setCompiled(dev);
774 : }
775 :
776 144 : _data->releaseCallback = move(cb);
777 144 : }
778 :
779 0 : bool Queue::isCompatible(const ImageInfo &info) const {
780 0 : if (_data && _data->output.size() == 1) {
781 0 : auto out = _data->output.front();
782 0 : if (out->type == AttachmentType::Image) {
783 0 : return out->attachment->isCompatible(info);
784 : }
785 : }
786 0 : return false;
787 : }
788 :
789 16 : StringView Queue::getName() const {
790 16 : return _data->key;
791 : }
792 :
793 16 : FrameRenderPassState Queue::getDefaultSyncPassState() const {
794 16 : return _data->defaultSyncPassState;
795 : }
796 :
797 144 : const HashTable<ProgramData *> &Queue::getPrograms() const {
798 144 : return _data->programs;
799 : }
800 :
801 86201 : const HashTable<QueuePassData *> &Queue::getPasses() const {
802 86201 : return _data->passes;
803 : }
804 :
805 16 : const HashTable<GraphicPipelineData *> &Queue::getGraphicPipelines() const {
806 16 : return _data->graphicPipelines;
807 : }
808 :
809 16 : const HashTable<ComputePipelineData *> &Queue::getComputePipelines() const {
810 16 : return _data->computePipelines;
811 : }
812 :
813 85625 : const HashTable<AttachmentData *> &Queue::getAttachments() const {
814 85625 : return _data->attachments;
815 : }
816 :
817 16 : const HashTable<Rc<Resource>> &Queue::getLinkedResources() const {
818 16 : return _data->linked;
819 : }
820 :
821 208 : Rc<Resource> Queue::getInternalResource() const {
822 208 : return _data->resource;
823 : }
824 :
825 8166 : const memory::vector<AttachmentData *> &Queue::getInputAttachments() const {
826 8166 : return _data->input;
827 : }
828 :
829 16 : const memory::vector<AttachmentData *> &Queue::getOutputAttachments() const {
830 16 : return _data->output;
831 : }
832 :
833 16 : const Attachment *Queue::getInputAttachment(std::type_index name) const {
834 16 : auto it = _data->typedInput.find(name);
835 16 : if (it != _data->typedInput.end()) {
836 0 : return it->second;
837 : }
838 16 : return nullptr;
839 : }
840 :
841 16 : const Attachment *Queue::getOutputAttachment(std::type_index name) const {
842 16 : auto it = _data->typedOutput.find(name);
843 16 : if (it != _data->typedOutput.end()) {
844 0 : return it->second;
845 : }
846 16 : return nullptr;
847 : }
848 :
849 16 : const QueuePassData *Queue::getPass(StringView key) const {
850 16 : return _data->passes.get(key);
851 : }
852 :
853 16 : const ProgramData *Queue::getProgram(StringView key) const {
854 16 : return _data->programs.get(key);
855 : }
856 :
857 16 : const GraphicPipelineData *Queue::getGraphicPipeline(StringView key) const {
858 16 : return _data->graphicPipelines.get(key);
859 : }
860 :
861 16 : const ComputePipelineData *Queue::getComputePipeline(StringView key) const {
862 16 : return _data->computePipelines.get(key);
863 : }
864 :
865 115200 : const AttachmentData *Queue::getAttachment(StringView key) const {
866 115200 : return _data->attachments.get(key);
867 : }
868 :
869 16 : Vector<AttachmentData *> Queue::getOutput() const {
870 16 : Vector<AttachmentData *> ret; ret.reserve(_data->output.size());
871 64 : for (auto &it : _data->output) {
872 48 : ret.emplace_back(it);
873 : }
874 16 : return ret;
875 0 : }
876 :
877 16 : Vector<AttachmentData *> Queue::getOutput(AttachmentType t) const {
878 16 : Vector<AttachmentData *> ret;
879 64 : for (auto &it : _data->output) {
880 48 : if (it->type == t) {
881 32 : ret.emplace_back(it);
882 : }
883 : }
884 16 : return ret;
885 0 : }
886 :
887 7338 : AttachmentData *Queue::getPresentImageOutput() const {
888 7338 : for (auto &it : _data->output) {
889 7338 : if (it->type == AttachmentType::Image) {
890 7338 : auto img = (ImageAttachment *)it->attachment.get();
891 7338 : if (img->getFinalLayout() == AttachmentLayout::PresentSrc) {
892 7338 : return it;
893 : }
894 : }
895 : }
896 0 : return nullptr;
897 : }
898 :
899 16 : AttachmentData *Queue::getTransferImageOutput() const {
900 16 : for (auto &it : _data->output) {
901 16 : if (it->type == AttachmentType::Image) {
902 16 : auto img = (ImageAttachment *)it->attachment.get();
903 16 : if (img->getFinalLayout() == AttachmentLayout::TransferSrcOptimal) {
904 16 : return it;
905 : }
906 : }
907 : }
908 0 : return nullptr;
909 : }
910 :
911 28435 : uint64_t Queue::incrementOrder() {
912 28435 : auto ret = _data->order;
913 28435 : ++ _data->order;
914 28435 : return ret;
915 : }
916 :
917 176 : bool Queue::prepare(Device &dev) {
918 176 : memory::pool::context ctx(_data->pool);
919 :
920 416 : for (auto &it : _data->input) {
921 240 : auto &r = *it->attachment.get();
922 240 : _data->typedInput.emplace(std::type_index(typeid(r)), it->attachment.get());
923 : }
924 :
925 352 : for (auto &it : _data->output) {
926 176 : auto &r = *it->attachment.get();
927 176 : _data->typedOutput.emplace(std::type_index(typeid(r)), it->attachment.get());
928 : }
929 :
930 : // fill attachment descriptors
931 752 : for (auto &attachment : _data->attachments) {
932 576 : Queue_sortDescriptors(attachment, dev);
933 : }
934 :
935 176 : Queue_buildLoadStore(_data);
936 176 : Queue_buildDescriptors(_data, dev);
937 :
938 448 : for (auto &it : _data->passes) {
939 272 : it->pass->prepare(dev);
940 : }
941 :
942 176 : Queue_buildRequirements(_data, dev);
943 :
944 176 : return true;
945 176 : }
946 :
947 28435 : void Queue::beginFrame(FrameRequest &frame) {
948 28435 : if (_data->beginCallback) {
949 7338 : _data->beginCallback(frame);
950 : }
951 28435 : }
952 :
953 28435 : void Queue::endFrame(FrameRequest &frame) {
954 28435 : if (_data->endCallback) {
955 7338 : _data->endCallback(frame);
956 : }
957 28435 : }
958 :
959 28435 : void Queue::attachFrame(FrameHandle *frame) {
960 28435 : if (_data->attachCallback) {
961 7338 : _data->attachCallback(frame);
962 : }
963 28435 : }
964 :
965 28435 : void Queue::detachFrame(FrameHandle *frame) {
966 28435 : if (_data->detachCallback) {
967 7338 : _data->detachCallback(frame);
968 : }
969 28435 : }
970 :
971 624 : void AttachmentBuilder::setType(AttachmentType type) {
972 624 : _data->type = type;
973 624 : }
974 :
975 256 : void AttachmentBuilder::defineAsInput(AttachmentOps ops) {
976 256 : _data->usage |= AttachmentUsage::Input;
977 256 : _data->ops |= ops;
978 :
979 256 : ((QueueData *)_data->queue)->input.emplace_back(_data);
980 256 : }
981 :
982 224 : void AttachmentBuilder::defineAsOutput(AttachmentOps ops, FrameRenderPassState pass) {
983 224 : _data->usage |= AttachmentUsage::Output;
984 224 : _data->ops |= ops;
985 224 : _data->outputState = pass;
986 :
987 224 : ((QueueData *)_data->queue)->output.emplace_back(_data);
988 224 : }
989 :
990 16 : void AttachmentBuilder::defineAsOutput(FrameRenderPassState pass) {
991 16 : defineAsOutput(AttachmentOps::ReadColor | AttachmentOps::ReadStencil, pass);
992 16 : }
993 :
994 624 : AttachmentBuilder::AttachmentBuilder(AttachmentData *data) : _data(data) { }
995 :
996 16 : void AttachmentPassBuilder::setAttachmentOps(AttachmentOps ops) {
997 16 : _data->ops = ops;
998 16 : }
999 :
1000 16 : void AttachmentPassBuilder::setInitialLayout(AttachmentLayout l) {
1001 16 : _data->initialLayout = l;
1002 16 : }
1003 :
1004 16 : void AttachmentPassBuilder::setFinalLayout(AttachmentLayout l) {
1005 16 : _data->finalLayout = l;
1006 16 : }
1007 :
1008 16 : void AttachmentPassBuilder::setLoadOp(AttachmentLoadOp op) {
1009 16 : _data->loadOp = op;
1010 16 : }
1011 :
1012 16 : void AttachmentPassBuilder::setStoreOp(AttachmentStoreOp op) {
1013 16 : _data->storeOp = op;
1014 16 : }
1015 :
1016 16 : void AttachmentPassBuilder::setStencilLoadOp(AttachmentLoadOp op) {
1017 16 : _data->stencilLoadOp = op;
1018 16 : }
1019 :
1020 16 : void AttachmentPassBuilder::setStencilStoreOp(AttachmentStoreOp op) {
1021 16 : _data->stencilStoreOp = op;
1022 16 : }
1023 :
1024 16 : void AttachmentPassBuilder::setColorMode(const ColorMode &mode) {
1025 16 : _data->colorMode = mode;
1026 16 : }
1027 :
1028 96 : void AttachmentPassBuilder::setDependency(const AttachmentDependencyInfo &dep) {
1029 96 : _data->dependency = dep;
1030 96 : }
1031 :
1032 848 : AttachmentPassBuilder::AttachmentPassBuilder(AttachmentPassData *data) : _data(data) { }
1033 :
1034 192 : bool DescriptorSetBuilder::addDescriptor(const AttachmentPassData *attachment, DescriptorType type, AttachmentLayout layout) {
1035 192 : auto pool = _data->layout->pass->queue->pool;
1036 192 : memory::pool::context ctx(pool);
1037 :
1038 192 : auto p = new (pool) PipelineDescriptor;
1039 192 : p->key = attachment->key;
1040 192 : p->set = _data;
1041 192 : p->attachment = attachment;
1042 192 : p->type = type;
1043 192 : p->layout = layout;
1044 192 : p->count = 1;
1045 192 : p->index = _data->descriptors.size();
1046 :
1047 192 : _data->descriptors.emplace_back(p);
1048 192 : ((AttachmentPassData *)attachment)->descriptors.emplace_back(p);
1049 :
1050 192 : return true;
1051 192 : }
1052 :
1053 144 : bool DescriptorSetBuilder::addDescriptorArray(const AttachmentPassData *attachment, uint32_t count, DescriptorType type, AttachmentLayout layout) {
1054 144 : auto pool = _data->layout->pass->queue->pool;
1055 144 : memory::pool::context ctx(pool);
1056 :
1057 144 : auto p = new (pool) PipelineDescriptor;
1058 144 : p->key = attachment->key;
1059 144 : p->set = _data;
1060 144 : p->attachment = attachment;
1061 144 : p->type = type;
1062 144 : p->layout = layout;
1063 144 : p->count = count;
1064 144 : p->index = _data->descriptors.size();
1065 144 : p->countIsPredefined = true;
1066 :
1067 144 : _data->descriptors.emplace_back(p);
1068 144 : ((AttachmentPassData *)attachment)->descriptors.emplace_back(p);
1069 :
1070 144 : return true;
1071 144 : }
1072 :
1073 192 : DescriptorSetBuilder::DescriptorSetBuilder(DescriptorSetData *data)
1074 192 : : _data(data) { }
1075 :
1076 192 : bool PipelineLayoutBuilder::addSet(const Callback<void(DescriptorSetBuilder &)> &cb) {
1077 192 : auto pool = _data->pass->queue->pool;
1078 192 : memory::pool::context ctx(pool);
1079 :
1080 192 : auto s = new (pool) DescriptorSetData;
1081 192 : s->key = _data->key;
1082 192 : s->layout = _data;
1083 192 : s->index = _data->sets.size();
1084 :
1085 192 : DescriptorSetBuilder builder(s);
1086 192 : cb(builder);
1087 :
1088 192 : _data->sets.emplace_back(s);
1089 :
1090 192 : return true;
1091 192 : }
1092 :
1093 16 : void PipelineLayoutBuilder::setUsesTextureSet(bool value) {
1094 16 : _data->usesTextureSet = value;
1095 16 : }
1096 :
1097 208 : PipelineLayoutBuilder::PipelineLayoutBuilder(PipelineLayoutData *data)
1098 208 : : _data(data) { }
1099 :
1100 48 : bool SubpassBuilder::addColor(const AttachmentPassData *attachment, AttachmentDependencyInfo dependency,
1101 : AttachmentLayout layout, AttachmentOps ops, BlendInfo blendInfo) {
1102 48 : auto pool = _data->pass->queue->pool;
1103 48 : memory::pool::context ctx(pool);
1104 :
1105 48 : auto a = new (pool) AttachmentSubpassData;
1106 48 : a->key = attachment->key;
1107 48 : a->pass = attachment;
1108 48 : a->subpass = _data;
1109 48 : a->layout = layout;
1110 48 : a->dependency = dependency;
1111 48 : a->usage = AttachmentUsage::Output;
1112 48 : a->ops = ops;
1113 48 : a->blendInfo = blendInfo;
1114 :
1115 48 : _data->outputImages.emplace_back(a);
1116 48 : ((AttachmentPassData *)attachment)->subpasses.emplace_back(a);
1117 :
1118 48 : return true;
1119 48 : }
1120 :
1121 16 : bool SubpassBuilder::addColor(const AttachmentPassData *attachment, AttachmentDependencyInfo dependency, BlendInfo blendInfo) {
1122 16 : auto pool = _data->pass->queue->pool;
1123 16 : memory::pool::context ctx(pool);
1124 :
1125 16 : auto a = new (pool) AttachmentSubpassData;
1126 16 : a->key = attachment->key;
1127 16 : a->pass = attachment;
1128 16 : a->subpass = _data;
1129 16 : a->dependency = dependency;
1130 16 : a->usage = AttachmentUsage::Output;
1131 16 : a->blendInfo = blendInfo;
1132 :
1133 16 : _data->outputImages.emplace_back(a);
1134 16 : ((AttachmentPassData *)attachment)->subpasses.emplace_back(a);
1135 :
1136 16 : return true;
1137 16 : }
1138 :
1139 16 : bool SubpassBuilder::addInput(const AttachmentPassData *attachment, AttachmentDependencyInfo dependency,
1140 : AttachmentLayout layout, AttachmentOps ops) {
1141 16 : auto pool = _data->pass->queue->pool;
1142 16 : memory::pool::context ctx(pool);
1143 :
1144 16 : auto a = new (pool) AttachmentSubpassData;
1145 16 : a->key = attachment->key;
1146 16 : a->pass = attachment;
1147 16 : a->subpass = _data;
1148 16 : a->layout = layout;
1149 16 : a->dependency = dependency;
1150 16 : a->usage = AttachmentUsage::Input;
1151 16 : a->ops = ops;
1152 :
1153 16 : _data->inputImages.emplace_back(a);
1154 16 : ((AttachmentPassData *)attachment)->subpasses.emplace_back(a);
1155 :
1156 16 : return true;
1157 16 : }
1158 :
1159 16 : bool SubpassBuilder::addResolve(const AttachmentPassData *color, const AttachmentPassData *resolve,
1160 : AttachmentDependencyInfo colorDep, AttachmentDependencyInfo resolveDep) {
1161 16 : auto pool = _data->pass->queue->pool;
1162 16 : memory::pool::context ctx(pool);
1163 :
1164 16 : auto a = new (pool) AttachmentSubpassData;
1165 16 : a->key = color->key;
1166 16 : a->pass = color;
1167 16 : a->subpass = _data;
1168 16 : a->dependency = colorDep;
1169 16 : a->usage = AttachmentUsage::Output;
1170 :
1171 16 : _data->outputImages.emplace_back(a);
1172 16 : _data->resolveImages.resize(_data->outputImages.size() - 1, nullptr);
1173 16 : ((AttachmentPassData *)color)->subpasses.emplace_back(a);
1174 :
1175 16 : auto res = new (pool) AttachmentSubpassData;
1176 16 : res->key = resolve->key;
1177 16 : res->pass = resolve;
1178 16 : res->subpass = _data;
1179 16 : res->dependency = resolveDep;
1180 16 : res->usage = AttachmentUsage::Resolve;
1181 :
1182 16 : _data->resolveImages.emplace_back(res);
1183 16 : ((AttachmentPassData *)resolve)->subpasses.emplace_back(res);
1184 :
1185 16 : return true;
1186 16 : }
1187 :
1188 16 : bool SubpassBuilder::setDepthStencil(const AttachmentPassData *attachment, AttachmentDependencyInfo dependency,
1189 : AttachmentLayout layout, AttachmentOps ops) {
1190 16 : auto pool = _data->pass->queue->pool;
1191 16 : memory::pool::context ctx(pool);
1192 :
1193 16 : auto a = new (pool) AttachmentSubpassData;
1194 16 : a->key = attachment->key;
1195 16 : a->pass = attachment;
1196 16 : a->subpass = _data;
1197 16 : a->layout = layout;
1198 16 : a->dependency = dependency;
1199 16 : a->usage = AttachmentUsage::DepthStencil;
1200 16 : a->ops = ops;
1201 :
1202 16 : _data->depthStencil = a;
1203 16 : ((AttachmentPassData *)attachment)->subpasses.emplace_back(a);
1204 :
1205 16 : return true;
1206 16 : }
1207 :
1208 1152 : const ComputePipelineData *SubpassBuilder::addComputePipeline(StringView key, const PipelineLayoutData *layout,
1209 : SpecializationInfo &&spec) {
1210 1152 : auto it = _data->computePipelines.find(key);
1211 1152 : if (it != _data->computePipelines.end()) {
1212 0 : log::error("Resource", _data->key, ": Pipeline '", key, "' already added");
1213 0 : return nullptr;
1214 : }
1215 :
1216 1152 : auto pool = _data->pass->queue->pool;
1217 1152 : memory::pool::context ctx(pool);
1218 :
1219 1152 : auto pipeline = new (pool) ComputePipelineData;
1220 1152 : pipeline->key = key.pdup(pool);
1221 1152 : pipeline->shader = move(spec);
1222 1152 : pipeline->layout = layout;
1223 1152 : pipeline->subpass = _data;
1224 :
1225 1152 : Queue_validateShaderPipelineLayout(pipeline->key, pipeline->layout, pipeline->shader.data);
1226 :
1227 1152 : _data->computePipelines.emplace(pipeline);
1228 1152 : ((PipelineLayoutData *)pipeline->layout)->computePipelines.emplace_back(pipeline);
1229 :
1230 1152 : return pipeline;
1231 1152 : }
1232 :
1233 112 : void SubpassBuilder::setPrepareCallback(memory::function<void(const SubpassData &, FrameQueue &)> &&cb) {
1234 112 : _data->prepareCallback = move(cb);
1235 112 : }
1236 :
1237 112 : void SubpassBuilder::setCommandsCallback(memory::function<void(const SubpassData &, FrameQueue &, CommandBuffer &)> &&cb) {
1238 112 : _data->commandsCallback = move(cb);
1239 112 : }
1240 :
1241 96 : GraphicPipelineData *SubpassBuilder::emplacePipeline(StringView key, const PipelineLayoutData *layout) {
1242 96 : auto it = _data->graphicPipelines.find(key);
1243 96 : if (it != _data->graphicPipelines.end()) {
1244 0 : log::error("Resource", _data->key, ": Pipeline '", key, "' already added");
1245 0 : return nullptr;
1246 : }
1247 :
1248 96 : auto pool = _data->pass->queue->pool;
1249 96 : memory::pool::context ctx(pool);
1250 :
1251 96 : auto pipeline = new (pool) GraphicPipelineData;
1252 96 : pipeline->key = key.pdup(pool);
1253 96 : pipeline->layout = layout;
1254 96 : pipeline->subpass = _data;
1255 :
1256 96 : return pipeline;
1257 96 : }
1258 :
1259 80 : void SubpassBuilder::finalizePipeline(GraphicPipelineData *data) {
1260 : // validate shaders descriptors
1261 :
1262 240 : for (auto &shaderSpec : data->shaders) {
1263 160 : Queue_validateShaderPipelineLayout(data->key, data->layout, shaderSpec.data);
1264 : }
1265 :
1266 80 : _data->graphicPipelines.emplace(data);
1267 :
1268 80 : ((PipelineLayoutData *)data->layout)->graphicPipelines.emplace_back(data);
1269 80 : }
1270 :
1271 16 : void SubpassBuilder::erasePipeline(GraphicPipelineData *data) {
1272 16 : _data->graphicPipelines.erase(data->key);
1273 16 : }
1274 :
1275 16 : bool SubpassBuilder::setPipelineOption(GraphicPipelineData &f, DynamicState state) {
1276 16 : f.dynamicState = state;
1277 16 : return true;
1278 : }
1279 :
1280 96 : bool SubpassBuilder::setPipelineOption(GraphicPipelineData &f, const Vector<SpecializationInfo> &programs) {
1281 256 : for (auto &it : programs) {
1282 176 : auto p = _data->pass->queue->programs.get(it.data->key);
1283 176 : if (!p) {
1284 16 : log::error("PipelineRequest", _data->key, ": Shader not found in request: ", it.data->key);
1285 16 : return false;
1286 : }
1287 : }
1288 :
1289 80 : f.shaders.reserve(programs.size());
1290 240 : for (auto &it : programs) {
1291 160 : f.shaders.emplace_back(move(it));
1292 : }
1293 80 : return true;
1294 : }
1295 :
1296 80 : bool SubpassBuilder::setPipelineOption(GraphicPipelineData &f, const PipelineMaterialInfo &info) {
1297 80 : f.material = info;
1298 80 : return true;
1299 : }
1300 :
1301 224 : SubpassBuilder::SubpassBuilder(SubpassData *data) : _data(data) { }
1302 :
1303 208 : const PipelineLayoutData * QueuePassBuilder::addDescriptorLayout(const Callback<void(PipelineLayoutBuilder &)> &cb) {
1304 208 : auto pool = _data->queue->pool;
1305 208 : memory::pool::context ctx(pool);
1306 :
1307 208 : auto layout = new (pool) PipelineLayoutData;
1308 208 : layout->key = _data->key;
1309 208 : layout->pass = _data;
1310 208 : layout->index = _data->subpasses.size();
1311 :
1312 208 : PipelineLayoutBuilder builder(layout);
1313 208 : cb(builder);
1314 :
1315 208 : _data->pipelineLayouts.emplace_back(layout);
1316 208 : return layout;
1317 208 : }
1318 :
1319 224 : const SubpassData * QueuePassBuilder::addSubpass(const Callback<void(SubpassBuilder &)> &cb) {
1320 224 : auto pool = _data->queue->pool;
1321 224 : memory::pool::context ctx(pool);
1322 :
1323 224 : auto subpass = new (pool) SubpassData;
1324 224 : subpass->key = _data->key;
1325 224 : subpass->pass = _data;
1326 224 : subpass->index = _data->subpasses.size();
1327 :
1328 224 : SubpassBuilder builder(subpass);
1329 224 : cb(builder);
1330 :
1331 224 : _data->subpasses.emplace_back(subpass);
1332 224 : return subpass;
1333 224 : }
1334 :
1335 32 : bool QueuePassBuilder::addSubpassDependency(const SubpassData *src, PipelineStage srcStage, AccessType srcAccess,
1336 : const SubpassData *dst, PipelineStage dstStage, AccessType dstAccess, bool byRegion) {
1337 32 : _data->dependencies.emplace_back(SubpassDependency{src->index, srcStage, srcAccess, dst->index, dstStage, dstAccess, byRegion});
1338 32 : return true;
1339 : }
1340 :
1341 736 : const AttachmentPassData *QueuePassBuilder::addAttachment(const AttachmentData *data) {
1342 736 : return addAttachment(data, [] (AttachmentPassBuilder &builder) { });
1343 : }
1344 :
1345 80 : const AttachmentPassData *QueuePassBuilder::addAttachment(const AttachmentData *data, const AttachmentDependencyInfo &deps) {
1346 160 : return addAttachment(data, [&] (AttachmentPassBuilder &builder) {
1347 80 : builder.setDependency(deps);
1348 160 : });
1349 : }
1350 :
1351 848 : const AttachmentPassData *QueuePassBuilder::addAttachment(const AttachmentData *data, const Callback<void(AttachmentPassBuilder &)> &cb) {
1352 848 : auto pool = _data->queue->pool;
1353 848 : memory::pool::context ctx(pool);
1354 :
1355 2128 : for (auto &it : _data->attachments) {
1356 1280 : if (it->attachment == data) {
1357 0 : return it;
1358 : }
1359 : }
1360 :
1361 848 : auto a = new (pool) AttachmentPassData;
1362 848 : a->key = data->key;
1363 848 : a->attachment = data;
1364 848 : a->pass = _data;
1365 848 : a->index = _data->attachments.size();
1366 :
1367 848 : AttachmentPassBuilder builder(a);
1368 848 : cb(builder);
1369 :
1370 848 : _data->attachments.emplace_back(a);
1371 848 : ((AttachmentData *)data)->passes.emplace_back(a);
1372 :
1373 848 : return a;
1374 848 : }
1375 :
1376 992 : StringView QueuePassBuilder::getName() const {
1377 992 : return _data->key;
1378 : }
1379 :
1380 16 : void QueuePassBuilder::addSubmittedCallback(memory::function<void(const QueuePassData &, FrameQueue &, bool success)> &&cb) {
1381 16 : _data->submittedCallbacks.emplace_back(move(cb));
1382 16 : }
1383 :
1384 112 : void QueuePassBuilder::addCompleteCallback(memory::function<void(const QueuePassData &, FrameQueue &, bool success)> &&cb) {
1385 112 : _data->submittedCallbacks.emplace_back(move(cb));
1386 112 : }
1387 :
1388 320 : QueuePassBuilder::QueuePassBuilder(QueuePassData *data) : _data(data) { }
1389 :
1390 192 : Queue::Builder::Builder(StringView name) : _internalResource(toString(name, "_resource")) {
1391 192 : auto p = memory::pool::create((memory::pool_t *)nullptr);
1392 192 : memory::pool::push(p);
1393 192 : _data = new (p) QueueData;
1394 192 : _data->pool = p;
1395 192 : _data->key = name.pdup(p);
1396 192 : memory::pool::pop();
1397 192 : }
1398 :
1399 192 : Queue::Builder::~Builder() {
1400 192 : if (_data) {
1401 0 : auto p = _data->pool;
1402 0 : memory::pool::destroy(p);
1403 0 : _data = nullptr;
1404 : }
1405 192 : }
1406 :
1407 : static std::atomic<uint64_t> s_AttachmentCurrentIndex = 1;
1408 :
1409 16 : void Queue::Builder::setDefaultSyncPassState(FrameRenderPassState val) {
1410 16 : _data->defaultSyncPassState = val;
1411 16 : }
1412 :
1413 624 : const AttachmentData *Queue::Builder::addAttachemnt(StringView name, const Callback<Rc<Attachment>(AttachmentBuilder &)> &cb) {
1414 624 : auto it = _data->attachments.find(name);
1415 624 : if (it == _data->attachments.end()) {
1416 624 : memory::pool::push(_data->pool);
1417 624 : auto ret = new (_data->pool) AttachmentData();
1418 624 : ret->key = name.pdup(_data->pool);
1419 624 : ret->id = s_AttachmentCurrentIndex.fetch_add(1);
1420 624 : ret->queue = _data;
1421 :
1422 624 : AttachmentBuilder builder(ret);
1423 624 : auto p = cb(builder);
1424 :
1425 624 : ret->attachment = p;
1426 624 : _data->attachments.emplace(ret);
1427 624 : memory::pool::pop();
1428 624 : return ret;
1429 624 : } else {
1430 0 : log::error("Queue::Builder", "Attachment for name already defined: ", name);
1431 : }
1432 0 : return nullptr;
1433 : }
1434 :
1435 320 : const QueuePassData *Queue::Builder::addPass(StringView name, PassType type, RenderOrdering ordering, const Callback<Rc<QueuePass>(QueuePassBuilder &)> &cb) {
1436 320 : auto it = _data->passes.find(name);
1437 320 : if (it == _data->passes.end()) {
1438 320 : memory::pool::push(_data->pool);
1439 320 : auto ret = new (_data->pool) QueuePassData();
1440 320 : ret->key = name.pdup(_data->pool);
1441 320 : ret->queue = _data;
1442 320 : ret->ordering = ordering;
1443 320 : ret->type = type;
1444 :
1445 320 : QueuePassBuilder builder(ret);
1446 320 : auto p = cb(builder);
1447 :
1448 320 : ret->pass = p;
1449 320 : _data->passes.emplace(ret);
1450 320 : memory::pool::pop();
1451 320 : return ret;
1452 320 : } else {
1453 0 : log::error("Queue::Builder", "RenderPass for name already defined: ", name);
1454 : }
1455 0 : return nullptr;
1456 : }
1457 :
1458 80 : const ProgramData * Queue::Builder::addProgram(StringView key, SpanView<uint32_t> data, const ProgramInfo *info) {
1459 80 : if (!_data) {
1460 0 : log::error("Resource", "Fail to add shader: ", key, ", not initialized");
1461 0 : return nullptr;
1462 : }
1463 :
1464 80 : if (auto r = Resource_conditionalInsert<ProgramData>(_data->programs, key, [&, this] () -> ProgramData * {
1465 64 : auto program = new (_data->pool) ProgramData;
1466 64 : program->key = key.pdup(_data->pool);
1467 64 : program->data = data.pdup(_data->pool);
1468 64 : if (info) {
1469 32 : program->stage = info->stage;
1470 32 : program->bindings = info->bindings;
1471 32 : program->constants = info->constants;
1472 : } else {
1473 32 : program->inspect(data);
1474 : }
1475 64 : return program;
1476 80 : }, _data->pool)) {
1477 64 : return r;
1478 : }
1479 :
1480 16 : log::error("Resource", _data->key, ": Shader already added: ", key);
1481 16 : return nullptr;
1482 : }
1483 :
1484 1232 : const ProgramData * Queue::Builder::addProgramByRef(StringView key, SpanView<uint32_t> data, const ProgramInfo *info) {
1485 1232 : if (!_data) {
1486 0 : log::error("Resource", "Fail tom add shader: ", key, ", not initialized");
1487 0 : return nullptr;
1488 : }
1489 :
1490 1232 : if (auto r = Resource_conditionalInsert<ProgramData>(_data->programs, key, [&, this] () -> ProgramData * {
1491 1216 : auto program = new (_data->pool) ProgramData;
1492 1216 : program->key = key.pdup(_data->pool);
1493 1216 : program->data = data;
1494 1216 : if (info) {
1495 32 : program->stage = info->stage;
1496 32 : program->bindings = info->bindings;
1497 32 : program->constants = info->constants;
1498 : } else {
1499 1184 : program->inspect(data);
1500 : }
1501 1216 : return program;
1502 1232 : }, _data->pool)) {
1503 1216 : return r;
1504 : }
1505 :
1506 16 : log::error("Resource", _data->key, ": Shader already added: ", key);
1507 16 : return nullptr;
1508 : }
1509 :
1510 64 : const ProgramData * Queue::Builder::addProgram(StringView key, const memory::function<void(const ProgramData::DataCallback &)> &cb,
1511 : const ProgramInfo *info) {
1512 64 : if (!_data) {
1513 0 : log::error("Resource", "Fail to add shader: ", key, ", not initialized");
1514 0 : return nullptr;
1515 : }
1516 :
1517 64 : if (auto r = Resource_conditionalInsert<ProgramData>(_data->programs, key, [&, this] () -> ProgramData * {
1518 48 : auto program = new (_data->pool) ProgramData;
1519 48 : program->key = key.pdup(_data->pool);
1520 48 : program->callback = cb;
1521 48 : if (info) {
1522 32 : program->stage = info->stage;
1523 32 : program->bindings = info->bindings;
1524 32 : program->constants = info->constants;
1525 : } else {
1526 16 : cb([&] (SpanView<uint32_t> data) {
1527 16 : program->inspect(data);
1528 16 : });
1529 : }
1530 48 : return program;
1531 64 : }, _data->pool)) {
1532 48 : return r;
1533 : }
1534 :
1535 16 : log::error("Resource", _data->key, ": Shader already added: ", key);
1536 16 : return nullptr;
1537 : }
1538 :
1539 : /*void Queue::Builder::setInternalResource(Rc<Resource> &&res) {
1540 : if (!_data) {
1541 : log::error("Resource", "Fail to set internal resource: ", res->getName(), ", not initialized");
1542 : return;
1543 : }
1544 : if (_data->resource) {
1545 : log::error("Resource", "Fail to set internal resource: resource already defined");
1546 : return;
1547 : }
1548 : if (res->getOwner() != nullptr) {
1549 : log::error("Resource", "Fail to set internal resource: ", res->getName(), ", already owned by ", res->getOwner()->getName());
1550 : return;
1551 : }
1552 : _data->resource = move(res);
1553 : }*/
1554 :
1555 32 : void Queue::Builder::addLinkedResource(const Rc<Resource> &res) {
1556 32 : if (!_data) {
1557 0 : log::error("Resource", "Fail to add linked resource: ", res->getName(), ", not initialized");
1558 0 : return;
1559 : }
1560 32 : if (res->getOwner() != nullptr) {
1561 0 : log::error("Resource", "Fail to add linked resource: ", res->getName(), ", it's owned by ", res->getOwner()->getName());
1562 0 : return;
1563 : }
1564 32 : if (!res->isCompiled()) {
1565 16 : log::error("Resource", "Fail to add linked resource: ", res->getName(), ", resource is not compiled");
1566 16 : return;
1567 : }
1568 16 : _data->linked.emplace(res);
1569 : }
1570 :
1571 16 : void Queue::Builder::setBeginCallback(Function<void(FrameRequest &)> &&cb) {
1572 16 : _data->beginCallback = move(cb);
1573 16 : }
1574 :
1575 16 : void Queue::Builder::setEndCallback(Function<void(FrameRequest &)> &&cb) {
1576 16 : _data->endCallback = move(cb);
1577 16 : }
1578 :
1579 16 : void Queue::Builder::setAttachCallback(Function<void(const FrameHandle *)> &&cb) {
1580 16 : _data->attachCallback = move(cb);
1581 16 : }
1582 :
1583 16 : void Queue::Builder::setDetachCallback(Function<void(const FrameHandle *)> &&cb) {
1584 16 : _data->detachCallback = move(cb);
1585 16 : }
1586 :
1587 32 : const BufferData * Queue::Builder::addBufferByRef(StringView key, BufferInfo &&info, BytesView data, Rc<DataAtlas> &&atlas, AccessType access) {
1588 32 : return _internalResource.addBufferByRef(key, move(info), data, move(atlas), access);
1589 : }
1590 :
1591 32 : const BufferData * Queue::Builder::addBuffer(StringView key, BufferInfo &&info, FilePath data, Rc<DataAtlas> &&atlas, AccessType access) {
1592 32 : return _internalResource.addBuffer(key, move(info), data, move(atlas), access);
1593 : }
1594 :
1595 32 : const BufferData * Queue::Builder::addBuffer(StringView key, BufferInfo &&info, BytesView data, Rc<DataAtlas> &&atlas, AccessType access) {
1596 32 : return _internalResource.addBuffer(key, move(info), data, move(atlas), access);
1597 : }
1598 :
1599 336 : const BufferData * Queue::Builder::addBuffer(StringView key, BufferInfo &&info,
1600 : const memory::function<void(uint8_t *, uint64_t, const BufferData::DataCallback &)> &cb, Rc<DataAtlas> &&atlas, AccessType access) {
1601 336 : return _internalResource.addBuffer(key, move(info), cb, move(atlas), access);
1602 : }
1603 :
1604 32 : const ImageData * Queue::Builder::addImageByRef(StringView key, ImageInfo &&info, BytesView data, AttachmentLayout layout, AccessType access) {
1605 32 : return _internalResource.addImageByRef(key, move(info), data, layout, access);
1606 : }
1607 64 : const ImageData * Queue::Builder::addImage(StringView key, ImageInfo &&info, FilePath data, AttachmentLayout layout, AccessType access) {
1608 64 : return _internalResource.addImage(key, move(info), data, layout, access);
1609 : }
1610 32 : const ImageData * Queue::Builder::addImage(StringView key, ImageInfo &&info, BytesView data, AttachmentLayout layout, AccessType access) {
1611 32 : return _internalResource.addImage(key, move(info), data, layout, access);
1612 : }
1613 32 : const ImageData * Queue::Builder::addImage(StringView key, ImageInfo &&info,
1614 : const memory::function<void(uint8_t *, uint64_t, const ImageData::DataCallback &)> &cb, AttachmentLayout layout, AccessType access) {
1615 32 : return _internalResource.addImage(key, move(info), cb, layout, access);
1616 : }
1617 :
1618 : }
|