LCOV - code coverage report
Current view: top level - xenolith/core - XLCoreQueue.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 867 1037 83.6 %
Date: 2024-05-12 00:16:13 Functions: 121 122 99.2 %

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

Generated by: LCOV version 1.14