LCOV - code coverage report
Current view: top level - xenolith/renderer/basic2d/backend/vk - XL2dVkShadowPass.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 289 302 95.7 %
Date: 2024-05-12 00:16:13 Functions: 31 31 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XL2dVkShadowPass.h"
      24             : 
      25             : #include "XLPlatform.h"
      26             : #include "XLApplication.h"
      27             : #include "XLVkLoop.h"
      28             : #include "XLVkRenderPass.h"
      29             : #include "XLVkPipeline.h"
      30             : #include "XLCoreFrameHandle.h"
      31             : #include "XLCoreFrameQueue.h"
      32             : #include "XLCoreFrameCache.h"
      33             : #include "XL2dFrameContext.h"
      34             : #include "glsl/XL2dShaders.h"
      35             : 
      36             : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d::vk {
      37             : 
      38          10 : bool ShadowPass::makeDefaultRenderQueue(Queue::Builder &builder, RenderQueueInfo &info) {
      39             :         using namespace core;
      40             : 
      41          10 :         Rc<ComputeShadowPass> computePass;
      42             : 
      43          10 :         builder.addPass("MaterialComputeShadowPass", PassType::Compute, RenderOrdering(0), [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
      44          10 :                 computePass = Rc<ComputeShadowPass>::create(builder, passBuilder, info.extent);
      45          10 :                 return computePass;
      46             :         });
      47             : 
      48          10 :         builder.addPass("MaterialSwapchainPass", PassType::Graphics, RenderOrderingHighest, [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
      49          20 :                 return Rc<ShadowPass>::create(builder, passBuilder, PassCreateInfo{
      50          10 :                         info.target, info.extent, info.flags,
      51          10 :                         computePass->getSdf(), computePass->getLights(), computePass->getPrimitives()
      52          20 :                 });
      53             :         });
      54             : 
      55          10 :         return true;
      56          10 : }
      57             : 
      58          10 : bool ShadowPass::init(Queue::Builder &queueBuilder, QueuePassBuilder &passBuilder, const PassCreateInfo &info) {
      59             :         using namespace core;
      60             : 
      61          20 :         _output = queueBuilder.addAttachemnt("Output", [&] (AttachmentBuilder &builder) -> Rc<Attachment> {
      62             :                 // swapchain output
      63          10 :                 builder.defineAsOutput();
      64             : 
      65          20 :                 return Rc<vk::ImageAttachment>::create(builder,
      66          10 :                         ImageInfo(
      67          10 :                                 info.extent,
      68           0 :                                 core::ForceImageUsage(core::ImageUsage::ColorAttachment),
      69          10 :                                 platform::getCommonFormat()),
      70          20 :                         core::ImageAttachment::AttachmentInfo{
      71             :                                 .initialLayout = AttachmentLayout::Undefined,
      72             :                                 .finalLayout = AttachmentLayout::PresentSrc,
      73             :                                 .clearOnLoad = true,
      74             :                                 .clearColor = Color4F(1.0f, 1.0f, 1.0f, 1.0f) // Color4F::WHITE;
      75          20 :                 });
      76             :         });
      77             : 
      78          10 :         _shadow = queueBuilder.addAttachemnt("Shadow", [&] (AttachmentBuilder &builder) -> Rc<Attachment> {
      79             :                 // swapchain output
      80          20 :                 return Rc<vk::ImageAttachment>::create(builder,
      81          10 :                         ImageInfo(
      82          10 :                                 info.extent,
      83          10 :                                 core::ForceImageUsage(core::ImageUsage::ColorAttachment | core::ImageUsage::InputAttachment),
      84          10 :                                 core::ImageFormat::R16_SFLOAT),
      85          20 :                         core::ImageAttachment::AttachmentInfo{
      86             :                                 .initialLayout = AttachmentLayout::Undefined,
      87             :                                 .finalLayout = AttachmentLayout::ShaderReadOnlyOptimal,
      88             :                                 .clearOnLoad = true,
      89             :                                 .clearColor = Color4F(0.0f, 0.0f, 0.0f, 0.0f) // Color4F::BLACK;
      90          20 :                 });
      91             :         });
      92             : 
      93          10 :         _depth2d = queueBuilder.addAttachemnt("CommonDepth2d", [&] (AttachmentBuilder &builder) -> Rc<Attachment> {
      94             :                 // swapchain output
      95          20 :                 return Rc<vk::ImageAttachment>::create(builder,
      96          10 :                         ImageInfo(
      97          10 :                                 info.extent,
      98           0 :                                 core::ForceImageUsage(core::ImageUsage::DepthStencilAttachment),
      99          10 :                                 VertexPass::selectDepthFormat(info.target->getGlLoop()->getSupportedDepthStencilFormat())),
     100          20 :                         core::ImageAttachment::AttachmentInfo{
     101             :                                 .initialLayout = AttachmentLayout::Undefined,
     102             :                                 .finalLayout = AttachmentLayout::DepthStencilAttachmentOptimal,
     103             :                                 .clearOnLoad = true,
     104             :                                 .clearColor = Color4F::WHITE
     105          20 :                 });
     106             :         });
     107             : 
     108          10 :         _sdf = info.shadowSdfAttachment;
     109             : 
     110          10 :         _materials = queueBuilder.addAttachemnt(FrameContext2d::MaterialAttachmentName, [] (AttachmentBuilder &builder) -> Rc<Attachment> {
     111          20 :                 return Rc<vk::MaterialAttachment>::create(builder, BufferInfo(core::BufferUsage::StorageBuffer));
     112             :         });
     113             : 
     114          20 :         _vertexes = queueBuilder.addAttachemnt(FrameContext2d::VertexAttachmentName, [&, this] (AttachmentBuilder &builder) -> Rc<Attachment> {
     115          10 :                 builder.defineAsInput();
     116          20 :                 return Rc<VertexAttachment>::create(builder, BufferInfo(core::BufferUsage::StorageBuffer), _materials);
     117             :         });
     118             : 
     119          10 :         _lightsData = info.lightsAttachment;
     120          10 :         _shadowPrimitives = info.sdfPrimitivesAttachment;
     121             : 
     122          10 :         auto colorAttachment = passBuilder.addAttachment(_output);
     123          10 :         auto shadowAttachment = passBuilder.addAttachment(_shadow);
     124          10 :         auto sdfAttachment = passBuilder.addAttachment(_sdf);
     125          10 :         auto depth2dAttachment = passBuilder.addAttachment(_depth2d);
     126             : 
     127          10 :         auto layout2d = passBuilder.addDescriptorLayout([&, this] (PipelineLayoutBuilder &layoutBuilder) {
     128             :                 // Vertex input attachment - per-frame vertex list
     129          10 :                 layoutBuilder.addSet([&, this] (DescriptorSetBuilder &setBuilder) {
     130          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_vertexes));
     131          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_materials));
     132          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_lightsData));
     133          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_shadowPrimitives));
     134          10 :                         setBuilder.addDescriptor(shadowAttachment, DescriptorType::InputAttachment, AttachmentLayout::ShaderReadOnlyOptimal);
     135          20 :                         setBuilder.addDescriptor(sdfAttachment, DescriptorType::SampledImage, AttachmentLayout::ShaderReadOnlyOptimal);
     136          10 :                 });
     137          20 :         });
     138             : 
     139          10 :         auto subpass2d = passBuilder.addSubpass([&, this] (SubpassBuilder &subpassBuilder) {
     140             :                 // load shaders by ref - do not copy data into engine
     141          10 :                 auto materialVert = queueBuilder.addProgramByRef("Loader_MaterialVert", shaders::MaterialVert);
     142          10 :                 auto materialFrag = queueBuilder.addProgramByRef("Loader_MaterialFrag", shaders::MaterialFrag);
     143             : 
     144             :                 auto shaderSpecInfo = Vector<SpecializationInfo>({
     145             :                         // no specialization required for vertex shader
     146          20 :                         core::SpecializationInfo(materialVert, Vector<SpecializationConstant>{
     147             :                                 SpecializationConstant(PredefinedConstant::BuffersArraySize)
     148             :                         }),
     149             :                         // specialization for fragment shader - use platform-dependent array sizes
     150          20 :                         core::SpecializationInfo(materialFrag, Vector<SpecializationConstant>{
     151             :                                 SpecializationConstant(PredefinedConstant::SamplersArraySize),
     152             :                                 SpecializationConstant(PredefinedConstant::TexturesArraySize)
     153             :                         })
     154          70 :                 });
     155             : 
     156             :                 // pipelines for material-besed rendering
     157          10 :                 auto materialPipeline = subpassBuilder.addGraphicPipeline("Solid", layout2d, shaderSpecInfo, PipelineMaterialInfo({
     158          10 :                         BlendInfo(),
     159          10 :                         DepthInfo(true, true, CompareOp::Less)
     160          10 :                 }));
     161             : 
     162          10 :                 auto transparentPipeline = subpassBuilder.addGraphicPipeline("Transparent", layout2d, shaderSpecInfo, PipelineMaterialInfo({
     163          10 :                         BlendInfo(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha, BlendOp::Add,
     164             :                                         BlendFactor::Zero, BlendFactor::One, BlendOp::Add),
     165          10 :                         DepthInfo(false, true, CompareOp::LessOrEqual)
     166          10 :                 }));
     167             : 
     168             :                 // pipeline for debugging - draw lines instead of triangles
     169          10 :                 subpassBuilder.addGraphicPipeline("DebugTriangles", layout2d, shaderSpecInfo, PipelineMaterialInfo(
     170          10 :                         BlendInfo(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha, BlendOp::Add,
     171             :                                         BlendFactor::Zero, BlendFactor::One, BlendOp::Add),
     172          10 :                         DepthInfo(false, true, CompareOp::LessOrEqual),
     173          10 :                         LineWidth(1.0f)
     174             :                 ));
     175             : 
     176          10 :                 auto cache = info.target->getResourceCache();
     177          70 :                 static_cast<MaterialAttachment *>(_materials->attachment.get())->addPredefinedMaterials(Vector<Rc<Material>>({
     178          10 :                         Rc<Material>::create(Material::MaterialIdInitial, materialPipeline, cache->getEmptyImage(), ColorMode::IntensityChannel),
     179          10 :                         Rc<Material>::create(Material::MaterialIdInitial, materialPipeline, cache->getSolidImage(), ColorMode::IntensityChannel),
     180          10 :                         Rc<Material>::create(Material::MaterialIdInitial, transparentPipeline, cache->getEmptyImage(), ColorMode()),
     181          20 :                         Rc<Material>::create(Material::MaterialIdInitial, transparentPipeline, cache->getSolidImage(), ColorMode()),
     182          50 :                 }));
     183             : 
     184          10 :                 subpassBuilder.addColor(colorAttachment, AttachmentDependencyInfo{
     185             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     186             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     187             :                         FrameRenderPassState::Submitted,
     188             :                 });
     189             : 
     190          10 :                 subpassBuilder.addColor(shadowAttachment, AttachmentDependencyInfo{
     191             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     192             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     193             :                         FrameRenderPassState::Submitted
     194             :                 }, BlendInfo(BlendFactor::One, core::BlendFactor::One, core::BlendOp::Max));
     195             : 
     196          10 :                 subpassBuilder.setDepthStencil(depth2dAttachment, AttachmentDependencyInfo{
     197             :                         PipelineStage::EarlyFragmentTest, AccessType::DepthStencilAttachmentRead | AccessType::DepthStencilAttachmentWrite,
     198             :                         PipelineStage::LateFragmentTest, AccessType::DepthStencilAttachmentRead | AccessType::DepthStencilAttachmentWrite,
     199             :                         FrameRenderPassState::Submitted,
     200             :                 });
     201          10 :         });
     202             : 
     203          10 :         auto subpassShadows = passBuilder.addSubpass([&] (SubpassBuilder &subpassBuilder) {
     204          10 :                 subpassBuilder.addColor(colorAttachment, AttachmentDependencyInfo{
     205             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     206             :                         PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     207             :                         FrameRenderPassState::Submitted,
     208             :                 });
     209             : 
     210          10 :                 subpassBuilder.addInput(shadowAttachment, AttachmentDependencyInfo{ // 4
     211             :                         PipelineStage::FragmentShader, AccessType::ShaderRead,
     212             :                         PipelineStage::FragmentShader, AccessType::ShaderRead,
     213             :                         FrameRenderPassState::Submitted,
     214             :                 });
     215             : 
     216          10 :                 auto shadowVert = queueBuilder.addProgramByRef("ShadowMergeVert", shaders::SdfShadowsVert);
     217          10 :                 auto shadowFrag = queueBuilder.addProgramByRef("ShadowMergeFrag", shaders::SdfShadowsFrag);
     218             : 
     219          50 :                 subpassBuilder.addGraphicPipeline(ShadowPass::ShadowPipeline, layout2d, Vector<SpecializationInfo>({
     220             :                         // no specialization required for vertex shader
     221             :                         shadowVert,
     222             :                         // specialization for fragment shader - use platform-dependent array sizes
     223          20 :                         SpecializationInfo(shadowFrag, Vector<SpecializationConstant>{
     224             :                                 SpecializationConstant(PredefinedConstant::SamplersArraySize),
     225             :                         })
     226          40 :                 }), PipelineMaterialInfo({
     227          10 :                         BlendInfo(BlendFactor::Zero, BlendFactor::SrcColor, BlendOp::Add,
     228             :                                         BlendFactor::Zero, BlendFactor::One, BlendOp::Add),
     229          10 :                         DepthInfo()
     230             :                 }));
     231          10 :         });
     232             : 
     233          10 :         passBuilder.addSubpassDependency(subpass2d, PipelineStage::LateFragmentTest, AccessType::DepthStencilAttachmentWrite,
     234             :                         subpassShadows, PipelineStage::FragmentShader, AccessType::ShaderRead, true);
     235          10 :         passBuilder.addSubpassDependency(subpass2d, PipelineStage::ColorAttachmentOutput, AccessType::ColorAttachmentWrite,
     236             :                         subpassShadows, PipelineStage::FragmentShader, AccessType::ShaderRead, true);
     237             : 
     238          10 :         if (!VertexPass::init(passBuilder)) {
     239           0 :                 return false;
     240             :         }
     241             : 
     242          10 :         _flags = info.flags;
     243          10 :         return true;
     244             : }
     245             : 
     246        4650 : auto ShadowPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
     247        9300 :         return Rc<ShadowPassHandle>::create(*this, handle);
     248             : }
     249             : 
     250        4640 : bool ShadowPassHandle::prepare(FrameQueue &q, Function<void(bool)> &&cb) {
     251        4640 :         auto pass = static_cast<ShadowPass *>(_queuePass.get());
     252             : 
     253        4640 :         if (auto lightsBuffer = q.getAttachment(pass->getLightsData())) {
     254        4640 :                 _shadowData = static_cast<const ShadowLightDataAttachmentHandle *>(lightsBuffer->handle.get());
     255             :         }
     256             : 
     257        4640 :         if (auto shadowPrimitives = q.getAttachment(pass->getShadowPrimitives())) {
     258        4640 :                 _shadowPrimitives = static_cast<const ShadowPrimitivesAttachmentHandle *>(shadowPrimitives->handle.get());
     259             :         }
     260             : 
     261        4640 :         if (auto sdfImage = q.getAttachment(pass->getSdf())) {
     262        4640 :                 _sdfImage = static_cast<const ShadowSdfImageAttachmentHandle *>(sdfImage->handle.get());
     263             :         }
     264             : 
     265        4640 :         return VertexPassHandle::prepare(q, move(cb));
     266             : }
     267             : 
     268        4640 : void ShadowPassHandle::prepareRenderPass(CommandBuffer &buf) {
     269        4640 :         Vector<BufferMemoryBarrier> bufferBarriers;
     270        4640 :         Vector<ImageMemoryBarrier> imageBarriers;
     271        4640 :         if (_shadowData->getLightsCount() && _shadowData->getBuffer()) {
     272        4640 :                 if (auto b = _shadowData->getBuffer()->getPendingBarrier()) {
     273        1105 :                         bufferBarriers.emplace_back(*b);
     274             :                 }
     275             :         }
     276             : 
     277        4640 :         if (_shadowPrimitives->getObjects()) {
     278        1105 :                 if (auto b = _shadowPrimitives->getObjects()->getPendingBarrier()) {
     279        1105 :                         bufferBarriers.emplace_back(*b);
     280             :                 }
     281             :         }
     282             : 
     283        4640 :         if (_shadowPrimitives->getGridSize()) {
     284        1105 :                 if (auto b = _shadowPrimitives->getGridSize()->getPendingBarrier()) {
     285        1105 :                         bufferBarriers.emplace_back(*b);
     286             :                 }
     287             :         }
     288             : 
     289        4640 :         if (_shadowPrimitives->getGridIndex()) {
     290        1105 :                 if (auto b = _shadowPrimitives->getGridIndex()->getPendingBarrier()) {
     291        1105 :                         bufferBarriers.emplace_back(*b);
     292             :                 }
     293             :         }
     294             : 
     295        4640 :         if (auto image = _sdfImage->getImage()) {
     296        4640 :                 if (auto b = image->getImage().cast<vk::Image>()->getPendingBarrier()) {
     297        4640 :                         imageBarriers.emplace_back(*b);
     298             :                 }
     299        4640 :         }
     300             : 
     301        4640 :         if (!imageBarriers.empty() || !bufferBarriers.empty()) {
     302        4640 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, bufferBarriers, imageBarriers);
     303           0 :         } else if (!imageBarriers.empty()) {
     304           0 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, imageBarriers);
     305           0 :         } else if (!bufferBarriers.empty()) {
     306           0 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, bufferBarriers);
     307             :         }
     308        4640 : }
     309             : 
     310        4640 : void ShadowPassHandle::prepareMaterialCommands(core::MaterialSet * materials, CommandBuffer &buf) {
     311        4640 :         VertexPassHandle::prepareMaterialCommands(materials, buf);
     312             : 
     313        4640 :         auto &fb = getFramebuffer();
     314        4640 :         auto currentExtent = fb->getExtent();
     315             : 
     316        4640 :         auto subpassIdx = buf.cmdNextSubpass();
     317        4640 :         auto pass = static_cast<RenderPass *>(_data->impl.get());
     318             : 
     319        4640 :         if (_shadowData->getLightsCount() && _shadowData->getBuffer() && _shadowData->getObjectsCount()) {
     320        1105 :                 auto pipeline = static_cast<GraphicPipeline *>(_data->subpasses[subpassIdx]->graphicPipelines
     321        1105 :                                 .get(StringView(ShadowPass::ShadowPipeline))->pipeline.get());
     322             : 
     323        1105 :                 buf.cmdBindDescriptorSets(pass, 0);
     324        1105 :                 buf.cmdBindPipeline(pipeline);
     325             : 
     326        1105 :                 auto viewport = VkViewport{ 0.0f, 0.0f, float(currentExtent.width), float(currentExtent.height), 0.0f, 1.0f };
     327        1105 :                 buf.cmdSetViewport(0, makeSpanView(&viewport, 1));
     328             : 
     329        1105 :                 auto scissorRect = VkRect2D{ { 0, 0}, { currentExtent.width, currentExtent.height } };
     330        1105 :                 buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
     331             : 
     332        1105 :                 uint32_t samplerIndex = 1; // linear filtering
     333        1105 :                 buf.cmdPushConstants(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
     334             :                                 0, BytesView(reinterpret_cast<const uint8_t *>(&samplerIndex), sizeof(uint32_t)));
     335             : 
     336        1105 :                 buf.cmdDrawIndexed(
     337             :                         6, // indexCount
     338             :                         1, // instanceCount
     339             :                         6, // firstIndex
     340             :                         0, // int32_t   vertexOffset
     341             :                         0  // uint32_t  firstInstance
     342             :                 );
     343             :         }
     344        4640 : }
     345             : 
     346          10 : bool ComputeShadowPass::init(Queue::Builder &queueBuilder, QueuePassBuilder &passBuilder, Extent2 defaultExtent) {
     347             :         using namespace core;
     348             : 
     349          20 :         _lights = queueBuilder.addAttachemnt(FrameContext2d::LightDataAttachmentName, [] (AttachmentBuilder &builder) -> Rc<Attachment> {
     350          10 :                 builder.defineAsInput();
     351          20 :                 return Rc<ShadowLightDataAttachment>::create(builder);
     352             :         });
     353             : 
     354          20 :         _vertexes = queueBuilder.addAttachemnt(FrameContext2d::ShadowVertexAttachmentName, [] (AttachmentBuilder &builder) -> Rc<Attachment> {
     355          10 :                 builder.defineAsInput();
     356          20 :                 return Rc<ShadowVertexAttachment>::create(builder);
     357             :         });
     358             : 
     359          10 :         _primitives = queueBuilder.addAttachemnt("ShadowPrimitivesAttachment", [] (AttachmentBuilder &builder) -> Rc<Attachment> {
     360          20 :                 return Rc<ShadowPrimitivesAttachment>::create(builder);
     361             :         });
     362             : 
     363          20 :         _sdf = queueBuilder.addAttachemnt(FrameContext2d::SdfImageAttachmentName, [&] (AttachmentBuilder &builder) -> Rc<Attachment> {
     364          10 :                 builder.defineAsInput();
     365             :                 //builder.defineAsOutput();
     366          20 :                 return Rc<ShadowSdfImageAttachment>::create(builder, defaultExtent);
     367             :         });
     368             : 
     369          10 :         auto layout = passBuilder.addDescriptorLayout([&, this] (PipelineLayoutBuilder &layoutBuilder) {
     370          10 :                 layoutBuilder.addSet([&, this] (DescriptorSetBuilder &setBuilder) {
     371          20 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_lights));
     372          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_vertexes));
     373          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_primitives));
     374          10 :                         setBuilder.addDescriptor(passBuilder.addAttachment(_sdf), DescriptorType::StorageImage, AttachmentLayout::General);
     375          10 :                 });
     376          20 :         });
     377             : 
     378          10 :         passBuilder.addSubpass([&] (SubpassBuilder &subpassBuilder) {
     379          10 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfTrianglesComp, layout,
     380          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfTrianglesComp", shaders::SdfTrianglesComp));
     381             : 
     382          20 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfCirclesComp, layout,
     383          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfCirclesComp", shaders::SdfCirclesComp));
     384             : 
     385          20 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfRectsComp, layout,
     386          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfRectsComp", shaders::SdfRectsComp));
     387             : 
     388          20 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfRoundedRectsComp, layout,
     389          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfRoundedRectsComp", shaders::SdfRoundedRectsComp));
     390             : 
     391          20 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfPolygonsComp, layout,
     392          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfPolygonsComp", shaders::SdfPolygonsComp));
     393             : 
     394          20 :                 subpassBuilder.addComputePipeline(ComputeShadowPass::SdfImageComp, layout,
     395          10 :                                 queueBuilder.addProgramByRef("ShadowPass_SdfImageComp", shaders::SdfImageComp));
     396          10 :         });
     397             : 
     398          20 :         return QueuePass::init(passBuilder);
     399             : }
     400             : 
     401        4650 : auto ComputeShadowPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
     402        9300 :         return Rc<ComputeShadowPassHandle>::create(*this, handle);
     403             : }
     404             : 
     405        4640 : bool ComputeShadowPassHandle::prepare(FrameQueue &q, Function<void(bool)> &&cb) {
     406        4640 :         auto pass = static_cast<ComputeShadowPass *>(_queuePass.get());
     407             : 
     408        4640 :         ShadowPrimitivesAttachmentHandle *trianglesHandle = nullptr;
     409        4640 :         ShadowLightDataAttachmentHandle *lightsHandle = nullptr;
     410             : 
     411        4640 :         if (auto lightsBuffer = q.getAttachment(pass->getLights())) {
     412        4640 :                 _lightsBuffer = lightsHandle = static_cast<ShadowLightDataAttachmentHandle *>(lightsBuffer->handle.get());
     413             :         }
     414             : 
     415        4640 :         if (auto primitivesBuffer = q.getAttachment(pass->getPrimitives())) {
     416        4640 :                 _primitivesBuffer = trianglesHandle = static_cast<ShadowPrimitivesAttachmentHandle *>(primitivesBuffer->handle.get());
     417             :         }
     418             : 
     419        4640 :         if (auto vertexBuffer = q.getAttachment(pass->getVertexes())) {
     420        4640 :                 _vertexBuffer = static_cast<const ShadowVertexAttachmentHandle *>(vertexBuffer->handle.get());
     421             :         }
     422             : 
     423        4640 :         if (auto sdfImage = q.getAttachment(pass->getSdf())) {
     424        4640 :                 _sdfImage = static_cast<const ShadowSdfImageAttachmentHandle *>(sdfImage->handle.get());
     425             :         }
     426             : 
     427        4640 :         if (lightsHandle && lightsHandle->getLightsCount()) {
     428        4640 :                 lightsHandle->allocateBuffer(static_cast<DeviceFrameHandle *>(q.getFrame().get()), _vertexBuffer, _gridCellSize);
     429             : 
     430        4640 :                 if (lightsHandle->getObjectsCount() > 0 && trianglesHandle) {
     431        1105 :                         trianglesHandle->allocateBuffer(static_cast<DeviceFrameHandle *>(q.getFrame().get()),
     432             :                                         lightsHandle->getShadowData());
     433             :                 }
     434             : 
     435        4640 :                 return QueuePassHandle::prepare(q, move(cb));
     436             :         } else {
     437           0 :                 cb(true);
     438           0 :                 return true;
     439             :         }
     440             : }
     441             : 
     442        4640 : void ComputeShadowPassHandle::writeShadowCommands(RenderPass *pass, CommandBuffer &buf) {
     443        4640 :         auto sdfImage = static_cast<Image *>(_sdfImage->getImage()->getImage().get());
     444             : 
     445        4640 :         if (!_lightsBuffer || _lightsBuffer->getObjectsCount() == 0) {
     446             :                 ImageMemoryBarrier inImageBarriers[] = {
     447             :                         ImageMemoryBarrier(sdfImage, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL)
     448        3535 :                 };
     449             : 
     450        3535 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, inImageBarriers);
     451        3535 :                 buf.cmdClearColorImage(sdfImage, VK_IMAGE_LAYOUT_GENERAL, Color4F(128.0f, 0.0f, 0.0f, 0.0f));
     452             : 
     453        3535 :                 auto gIdx = _device->getQueueFamily(QueueOperations::Graphics)->index;
     454             : 
     455        3535 :                 if (_pool->getFamilyIdx() != gIdx) {
     456        3535 :                         BufferMemoryBarrier transferBufferBarrier(_lightsBuffer->getBuffer(),
     457             :                                 VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_READ_BIT,
     458        3535 :                                 QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx}, 0, VK_WHOLE_SIZE);
     459             : 
     460             :                         ImageMemoryBarrier transferImageBarrier(sdfImage,
     461             :                                 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     462             :                                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
     463        3535 :                                 QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx});
     464        3535 :                         sdfImage->setPendingBarrier(transferImageBarrier);
     465             : 
     466        3535 :                         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
     467        7070 :                                         makeSpanView(&transferBufferBarrier, 1), makeSpanView(&transferImageBarrier, 1));
     468             :                 } else {
     469             :                         ImageMemoryBarrier transferImageBarrier(sdfImage,
     470             :                                 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     471           0 :                                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
     472             : 
     473           0 :                         sdfImage->setPendingBarrier(transferImageBarrier);
     474             :                 }
     475        3535 :                 return;
     476             :         }
     477             : 
     478        1105 :         ComputePipeline *pipeline = nullptr;
     479        1105 :         buf.cmdBindDescriptorSets(pass, 0);
     480        1105 :         buf.cmdFillBuffer(_primitivesBuffer->getGridSize(), 0);
     481             : 
     482        1105 :         BufferMemoryBarrier bufferBarrier(_primitivesBuffer->getGridSize(),
     483             :                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
     484        1105 :         );
     485             : 
     486        1105 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, makeSpanView(&bufferBarrier, 1));
     487             : 
     488        1105 :         if (_vertexBuffer->getTrianglesCount()) {
     489         634 :                 pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfTrianglesComp)->pipeline.get());
     490         634 :                 buf.cmdBindPipeline(pipeline);
     491         634 :                 buf.cmdDispatch((_vertexBuffer->getTrianglesCount() - 1) / pipeline->getLocalX() + 1);
     492             :         }
     493             : 
     494        1105 :         if (_vertexBuffer->getCirclesCount()) {
     495         634 :                 pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfCirclesComp)->pipeline.get());
     496         634 :                 buf.cmdBindPipeline(pipeline);
     497         634 :                 buf.cmdDispatch((_vertexBuffer->getCirclesCount() - 1) / pipeline->getLocalX() + 1);
     498             :         }
     499             : 
     500        1105 :         if (_vertexBuffer->getRectsCount()) {
     501         984 :                 pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfRectsComp)->pipeline.get());
     502         984 :                 buf.cmdBindPipeline(pipeline);
     503         984 :                 buf.cmdDispatch((_vertexBuffer->getRectsCount() - 1) / pipeline->getLocalX() + 1);
     504             :         }
     505             : 
     506        1105 :         if (_vertexBuffer->getRoundedRectsCount()) {
     507        1105 :                 pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfRoundedRectsComp)->pipeline.get());
     508        1105 :                 buf.cmdBindPipeline(pipeline);
     509        1105 :                 buf.cmdDispatch((_vertexBuffer->getRoundedRectsCount() - 1) / pipeline->getLocalX() + 1);
     510             :         }
     511             : 
     512        1105 :         if (_vertexBuffer->getPolygonsCount()) {
     513        1004 :                 pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfPolygonsComp)->pipeline.get());
     514        1004 :                 buf.cmdBindPipeline(pipeline);
     515        1004 :                 buf.cmdDispatch((_vertexBuffer->getPolygonsCount() - 1) / pipeline->getLocalX() + 1);
     516             :         }
     517             : 
     518             :         BufferMemoryBarrier bufferBarriers[] = {
     519        1105 :                 BufferMemoryBarrier(_vertexBuffer->getVertexes(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT),
     520        1105 :                 BufferMemoryBarrier(_primitivesBuffer->getObjects(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT),
     521        1105 :                 BufferMemoryBarrier(_primitivesBuffer->getGridSize(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT),
     522        1105 :                 BufferMemoryBarrier(_primitivesBuffer->getGridIndex(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT),
     523        1105 :         };
     524             : 
     525             :         ImageMemoryBarrier inImageBarriers[] = {
     526             :                 ImageMemoryBarrier(sdfImage, 0, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL)
     527        1105 :         };
     528             : 
     529        1105 :         buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
     530             :                         bufferBarriers, inImageBarriers);
     531             : 
     532        1105 :         pipeline = static_cast<ComputePipeline *>(_data->subpasses[0]->computePipelines.get(ComputeShadowPass::SdfImageComp)->pipeline.get());
     533        1105 :         buf.cmdBindPipeline(pipeline);
     534             : 
     535        2210 :         buf.cmdDispatch(
     536        1105 :                         (sdfImage->getInfo().extent.width - 1) / pipeline->getLocalX() + 1,
     537        1105 :                         (sdfImage->getInfo().extent.height - 1) / pipeline->getLocalY() + 1);
     538             : 
     539             :         // transfer image and buffer to transfer queue
     540        1105 :         auto gIdx = _device->getQueueFamily(QueueOperations::Graphics)->index;
     541             : 
     542        1105 :         if (_pool->getFamilyIdx() != gIdx) {
     543             : 
     544             :                 BufferMemoryBarrier bufferBarriers[] = {
     545        1105 :                         BufferMemoryBarrier(_primitivesBuffer->getObjects(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     546        1105 :                                         QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx}, 0, VK_WHOLE_SIZE),
     547        1105 :                         BufferMemoryBarrier(_primitivesBuffer->getGridSize(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     548        1105 :                                         QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx}, 0, VK_WHOLE_SIZE),
     549        1105 :                         BufferMemoryBarrier(_primitivesBuffer->getGridIndex(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     550        1105 :                                         QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx}, 0, VK_WHOLE_SIZE),
     551        1105 :                         BufferMemoryBarrier(_lightsBuffer->getBuffer(), VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_READ_BIT,
     552        1105 :                                         QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx}, 0, VK_WHOLE_SIZE)
     553        5525 :                 };
     554             : 
     555             :                 ImageMemoryBarrier transferImageBarrier(sdfImage,
     556             :                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     557             :                         VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
     558        1105 :                         QueueFamilyTransfer{_pool->getFamilyIdx(), gIdx});
     559        1105 :                 sdfImage->setPendingBarrier(transferImageBarrier);
     560             : 
     561        1105 :                 _primitivesBuffer->getObjects()->setPendingBarrier(bufferBarriers[0]);
     562        1105 :                 _primitivesBuffer->getGridSize()->setPendingBarrier(bufferBarriers[1]);
     563        1105 :                 _primitivesBuffer->getGridIndex()->setPendingBarrier(bufferBarriers[2]);
     564        1105 :                 _lightsBuffer->getBuffer()->setPendingBarrier(bufferBarriers[3]);
     565             : 
     566        1105 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
     567        2210 :                                 bufferBarriers, makeSpanView(&transferImageBarrier, 1));
     568             :         } else {
     569             :                 ImageMemoryBarrier transferImageBarrier(sdfImage,
     570             :                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     571           0 :                         VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
     572             : 
     573           0 :                 sdfImage->setPendingBarrier(transferImageBarrier);
     574             :         }
     575             : }
     576             : 
     577        4640 : Vector<const CommandBuffer *> ComputeShadowPassHandle::doPrepareCommands(FrameHandle &h) {
     578        4640 :         auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
     579        4640 :                 auto pass = static_cast<RenderPass *>(_data->impl.get());
     580             : 
     581        4640 :                 pass->perform(*this, buf, [&, this] {
     582        4640 :                         writeShadowCommands(pass, buf);
     583        4640 :                 });
     584        4640 :                 return true;
     585             :         });
     586             : 
     587        4640 :         return Vector<const CommandBuffer *>{buf};
     588             : }
     589             : 
     590             : }

Generated by: LCOV version 1.14