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