Lugdunum  0.1.0
Forward.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 
5 #include <lug/Config.hpp>
27 #include <lug/Math/Matrix.hpp>
28 #include <lug/Math/Vector.hpp>
30 
31 namespace lug {
32 namespace Graphics {
33 namespace Vulkan {
34 namespace Render {
35 namespace Technique {
36 
37 std::unique_ptr<BufferPool::Camera> Forward::_cameraBufferPool = nullptr;
38 std::unique_ptr<BufferPool::Light> Forward::_lightBufferPool = nullptr;
39 std::unique_ptr<BufferPool::Material> Forward::_materialBufferPool = nullptr;
40 
41 std::unique_ptr<DescriptorSetPool::Camera> Forward::_cameraDescriptorSetPool = nullptr;
42 std::unique_ptr<DescriptorSetPool::Light> Forward::_lightDescriptorSetPool = nullptr;
43 std::unique_ptr<DescriptorSetPool::Material> Forward::_materialDescriptorSetPool = nullptr;
44 std::unique_ptr<DescriptorSetPool::MaterialTextures> Forward::_materialTexturesDescriptorSetPool = nullptr;
45 std::unique_ptr<DescriptorSetPool::SkyBox> Forward::_skyBoxDescriptorSetPool = nullptr;
46 
47 uint32_t Forward::_forwardCount = 0;
48 
49 Forward::Forward(Renderer& renderer, const Render::View& renderView) : Technique(renderer, renderView) {
50  ++_forwardCount;
51 }
52 
54  destroy();
55 }
56 
58  const Render::Queue& renderQueue,
59  const API::Semaphore& imageReadySemaphore,
60  const API::Semaphore& drawCompleteSemaphore,
61  uint32_t currentImageIndex
62 ) {
63  FrameData& frameData = _framesData[currentImageIndex];
64 
65  frameData.transferFence.wait();
66  frameData.transferFence.reset();
67 
68  if (!frameData.transferCmdBuffer.reset() || !frameData.transferCmdBuffer.begin()) {
69  return false;
70  }
71 
72  // Get the new (or old) camera buffer
73  {
74  const BufferPool::SubBuffer* cameraBuffer = _cameraBufferPool->allocate(frameData.transferCmdBuffer, *_renderView.getCamera());
75 
76  if (!cameraBuffer) {
77  LUG_LOG.error("Forward::render: Can't allocate camera buffer");
78  return false;
79  }
80 
81  _cameraBufferPool->free(frameData.cameraBuffer);
82  frameData.cameraBuffer = cameraBuffer;
83  }
84 
85  frameData.renderFence.wait();
86  frameData.renderFence.reset();
87 
88  if (!frameData.renderCmdBuffer.reset() || !frameData.renderCmdBuffer.begin()) {
89  return false;
90  }
91 
92  // Begin of the render pass
93  {
94  // All the pipelines have the same renderPass
95  const API::RenderPass* renderPass = _renderer.getPipeline(Pipeline::getBaseId())->getPipelineAPI().getRenderPass();
96 
97  API::CommandBuffer::CmdBeginRenderPass beginRenderPass{
98  /* beginRenderPass.framebuffer */ frameData.framebuffer,
99  /* beginRenderPass.renderArea */ {},
100  /* beginRenderPass.clearValues */ {}
101  };
102 
103  const auto& viewport = _renderView.getViewport();
104  beginRenderPass.renderArea.offset = {static_cast<int32_t>(viewport.offset.x), static_cast<int32_t>(viewport.offset.y)};
105  beginRenderPass.renderArea.extent = {static_cast<uint32_t>(viewport.extent.width), static_cast<uint32_t>(viewport.extent.height)};
106 
107  const auto& clearColor = _renderView.getClearColor();
108  beginRenderPass.clearValues.resize(2);
109  beginRenderPass.clearValues[0].color = {{clearColor.r(), clearColor.g(), clearColor.b(), 1.0f}};
110  beginRenderPass.clearValues[1].depthStencil = {1.0f, 0};
111 
112  frameData.renderCmdBuffer.beginRenderPass(*renderPass, beginRenderPass);
113 
114  const VkViewport vkViewport{
115  /* vkViewport.x */ viewport.offset.x,
116  /* vkViewport.y */ viewport.offset.y,
117  /* vkViewport.width */ viewport.extent.width,
118  /* vkViewport.height */ viewport.extent.height,
119  /* vkViewport.minDepth */ viewport.minDepth,
120  /* vkViewport.maxDepth */ viewport.maxDepth,
121  };
122 
123  const VkRect2D scissor{
124  /* scissor.offset */ {
125  static_cast<int32_t>(_renderView.getScissor().offset.x),
126  static_cast<int32_t>(_renderView.getScissor().offset.y)
127  },
128  /* scissor.extent */ {
129  static_cast<uint32_t>(_renderView.getScissor().extent.width),
130  static_cast<uint32_t>(_renderView.getScissor().extent.height)
131  }
132  };
133 
134  frameData.renderCmdBuffer.setViewport({vkViewport});
135  frameData.renderCmdBuffer.setScissor({scissor});
136  }
137 
138  // Get the new (or old) camera descriptor set
139  {
140  const DescriptorSetPool::DescriptorSet* cameraDescriptorSet = _cameraDescriptorSetPool->allocate(*frameData.cameraBuffer);
141 
142  if (!cameraDescriptorSet) {
143  LUG_LOG.error("Forward::render: Can't allocate camera descriptor set");
144  return false;
145  }
146 
148  frameData.cameraDescriptorSet = cameraDescriptorSet;
149  }
150 
151  // Bind descriptor set of the camera
152  {
153  const API::CommandBuffer::CmdBindDescriptors cameraBind{
154  /* cameraBind.pipelineLayout */ *_renderer.getPipeline(Pipeline::getBaseId())->getPipelineAPI().getLayout(),
155  /* cameraBind.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
156  /* cameraBind.firstSet */ 0,
157  /* cameraBind.descriptorSets */ {&frameData.cameraDescriptorSet->getDescriptorSet()},
158  /* cameraBind.dynamicOffsets */ {frameData.cameraBuffer->getOffset()},
159  };
160 
161  frameData.renderCmdBuffer.bindDescriptorSets(cameraBind);
162  }
163 
164  // Temporary array of light and material buffers use to render this frame
165  // they will replace frameData.lightBuffers and frameData.materialBuffers atfer the rendering
166  std::vector<const BufferPool::SubBuffer*> lightBuffers;
167  std::vector<const BufferPool::SubBuffer*> materialBuffers;
168 
169  // Temporary array of light and material descriptor sets use to render this frame
170  // they will replace frameData.lightDescriptorSets and frameData.materialDescriptorSets atfer the rendering
171  std::vector<const DescriptorSetPool::DescriptorSet*> lightDescriptorSets;
172  std::vector<const DescriptorSetPool::DescriptorSet*> materialDescriptorSets;
173  std::vector<const DescriptorSetPool::DescriptorSet*> materialTexturesDescriptorSets;
174 
175  // Bind a default pipeline for the rendering
176  frameData.renderCmdBuffer.bindPipeline(_renderer.getPipeline(Pipeline::getBaseId())->getPipelineAPI());
177 
178  // Render objects
179  {
180  // Blend constants are used as dst blend factor
181  // We set them to 0 so that there is no blending
182  {
183  const float blendConstants[4] = {0.0f, 0.0f, 0.0f, 0.0f};
184  frameData.renderCmdBuffer.setBlendConstants(blendConstants);
185  }
186 
187  auto& lights = renderQueue.getLights();
188  for (uint32_t i = 0; i < renderQueue.getLightsCount(); i += 50) {
189  // Get the new (or old) light buffer
190  const BufferPool::SubBuffer* lightBuffer = _lightBufferPool->allocate(
191  currentImageIndex,
192  frameData.transferCmdBuffer,
193  {lights.begin() + i, i + 50 > renderQueue.getLightsCount() ? lights.begin() + renderQueue.getLightsCount() : lights.begin() + i + 50}
194  );
195  lightBuffers.push_back(lightBuffer);
196 
197  if (!lightBuffer) {
198  LUG_LOG.error("Forward::render: Can't allocate light buffer");
199  return false;
200  }
201 
202  // Get the new (or old) light descriptor set
203  const DescriptorSetPool::DescriptorSet* lightDescriptorSet = _lightDescriptorSetPool->allocate(*lightBuffer);
204  lightDescriptorSets.push_back(lightDescriptorSet);
205 
206  if (!lightDescriptorSet) {
207  LUG_LOG.error("Forward::render: Can't allocate light descriptor set");
208  return false;
209  }
210 
211  // Bind descriptor set of the light
212  {
213  const API::CommandBuffer::CmdBindDescriptors lightBind{
214  /* lightBind.pipelineLayout */ *_renderer.getPipeline(Pipeline::getBaseId())->getPipelineAPI().getLayout(),
215  /* lightBind.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
216  /* lightBind.firstSet */ 1,
217  /* lightBind.descriptorSets */ {&lightDescriptorSet->getDescriptorSet()},
218  /* lightBind.dynamicOffsets */ {lightBuffer->getOffset()},
219  };
220 
221  frameData.renderCmdBuffer.bindDescriptorSets(lightBind);
222  }
223 
224  // After the first batch of lights we need to re-enable the blend
225  if (i == 50) {
226  const float blendConstants[4] = {1.0f, 1.0f, 1.0f, 1.0f};
227  frameData.renderCmdBuffer.setBlendConstants(blendConstants);
228  }
229 
230  for (const auto it : renderQueue.getPrimitiveSets()) {
231  // Bind pipeline
233  frameData.renderCmdBuffer.bindPipeline(pipeline->getPipelineAPI());
234 
235  // Display primitive set by primitive set
236  for (const auto primitiveSetInstance : it.second) {
237  auto& node = *primitiveSetInstance.node;
238  const auto& primitiveSet = *primitiveSetInstance.primitiveSet;
239  auto& material = *primitiveSetInstance.material;
240 
241  const Math::Mat4x4f pushConstants[] = {
242  node.getTransform()
243  };
244 
245  const API::CommandBuffer::CmdPushConstants cmdPushConstants{
246  /* cmdPushConstants.layout */ static_cast<VkPipelineLayout>(*pipeline->getPipelineAPI().getLayout()),
247  /* cmdPushConstants.stageFlags */ VK_SHADER_STAGE_VERTEX_BIT,
248  /* cmdPushConstants.offset */ 0,
249  /* cmdPushConstants.size */ sizeof(pushConstants),
250  /* cmdPushConstants.values */ pushConstants
251  };
252  frameData.renderCmdBuffer.pushConstants(cmdPushConstants);
253 
254  // Get the new (or old) material buffer
255  const BufferPool::SubBuffer* materialBuffer = _materialBufferPool->allocate(frameData.transferCmdBuffer, material);
256  materialBuffers.push_back(materialBuffer);
257 
258  if (!materialBuffer) {
259  LUG_LOG.error("Forward::render: Can't allocate material buffer");
260  return false;
261  }
262 
263  // Get the new (or old) material descriptor set
264  const DescriptorSetPool::DescriptorSet* materialDescriptorSet = _materialDescriptorSetPool->allocate(*materialBuffer);
265  materialDescriptorSets.push_back(materialDescriptorSet);
266 
267  if (!materialDescriptorSet) {
268  LUG_LOG.error("Forward::render: Can't allocate material descriptor set");
269  return false;
270  }
271 
272  std::vector<const API::DescriptorSet*> materialDescriptorSetsBind{&materialDescriptorSet->getDescriptorSet()};
273 
274  if (pipeline->getPipelineAPI().getLayout()->getDescriptorSetLayouts().size() > 3) {
275  // Get the new (or old) material descriptor set
276  const DescriptorSetPool::DescriptorSet* materialTexturesDescriptorSet = _materialTexturesDescriptorSetPool->allocate(
277  pipeline->getPipelineAPI(),
278  [&material]() {
279  std::vector<const ::lug::Graphics::Vulkan::Render::Texture*> textures;
280 
281  if (material.getPipelineId().baseColorInfo != 0b11) {
282  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getBaseColorTexture().texture.get()));
283  }
284 
285  if (material.getPipelineId().metallicRoughnessInfo != 0b11) {
286  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getMetallicRoughnessTexture().texture.get()));
287  }
288 
289  if (material.getPipelineId().normalInfo != 0b11) {
290  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getNormalTexture().texture.get()));
291  }
292 
293  if (material.getPipelineId().occlusionInfo != 0b11) {
294  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getOcclusionTexture().texture.get()));
295  }
296 
297  if (material.getPipelineId().emissiveInfo != 0b11) {
298  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getEmissiveTexture().texture.get()));
299  }
300 
301  if (material.getIrradianceMap() && material.getIrradianceMap()->getEnvironnementTexture()) {
302  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getIrradianceMap()->getEnvironnementTexture().get()));
303  }
304 
305  if (material.getPrefilteredMap() && material.getPrefilteredMap()->getEnvironnementTexture()) {
306  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(Render::SkyBox::getBrdfLut().get()));
307  textures.push_back(static_cast<const ::lug::Graphics::Vulkan::Render::Texture*>(material.getPrefilteredMap()->getEnvironnementTexture().get()));
308  }
309 
310  return textures;
311  }()
312  );
313 
314  if (!materialTexturesDescriptorSet) {
315  LUG_LOG.error("Forward::render: Can't allocate material textures descriptor set");
316  return false;
317  }
318 
319  materialTexturesDescriptorSets.push_back(materialTexturesDescriptorSet);
320  materialDescriptorSetsBind.push_back(&materialTexturesDescriptorSet->getDescriptorSet());
321  }
322 
323  // Bind descriptor set of the material
324  {
325  const API::CommandBuffer::CmdBindDescriptors materialBind{
326  /* materialBind.pipelineLayout */ *pipeline->getPipelineAPI().getLayout(),
327  /* materialBind.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
328  /* materialBind.firstSet */ 2,
329  /* materialBind.descriptorSets */ materialDescriptorSetsBind,
330  /* materialBind.dynamicOffsets */ {materialBuffer->getOffset()},
331  };
332 
333  frameData.renderCmdBuffer.bindDescriptorSets(materialBind);
334  }
335 
336 
337  if (!primitiveSet.position || !primitiveSet.normal) {
338  LUG_LOG.warn("Forward::render: Mesh should have positions and normals data");
339  continue;
340  }
341 
342  std::vector<const API::Buffer*> vertexBuffers{
343  static_cast<API::Buffer*>(primitiveSet.position->_data),
344  static_cast<API::Buffer*>(primitiveSet.normal->_data)
345  };
346 
347  if (primitiveSet.tangent) {
348  vertexBuffers.push_back(static_cast<API::Buffer*>(primitiveSet.tangent->_data));
349  }
350 
351  for (const auto& texCoord: primitiveSet.texCoords) {
352  vertexBuffers.push_back(static_cast<API::Buffer*>(texCoord->_data));
353  }
354 
355  for (const auto& color: primitiveSet.colors) {
356  vertexBuffers.push_back(static_cast<API::Buffer*>(color->_data));
357  }
358 
359  const std::vector<VkDeviceSize> offsets(vertexBuffers.size());
360  frameData.renderCmdBuffer.bindVertexBuffers(vertexBuffers, offsets);
361 
362  if (primitiveSet.indices) {
363  API::Buffer* indicesBuffer = static_cast<API::Buffer*>(primitiveSet.indices->_data);
364 
365  if (primitiveSet.indices->buffer.size / primitiveSet.indices->buffer.elementsCount == 4) {
366  frameData.renderCmdBuffer.bindIndexBuffer(*indicesBuffer, VK_INDEX_TYPE_UINT32);
367  } else {
368  frameData.renderCmdBuffer.bindIndexBuffer(*indicesBuffer, VK_INDEX_TYPE_UINT16);
369  }
370 
371  const API::CommandBuffer::CmdDrawIndexed cmdDrawIndexed {
372  /* cmdDrawIndexed.indexCount */ primitiveSet.indices->buffer.elementsCount,
373  /* cmdDrawIndexed.instanceCount */ 1,
374  };
375 
376  frameData.renderCmdBuffer.drawIndexed(cmdDrawIndexed);
377  } else {
378  const API::CommandBuffer::CmdDraw cmdDraw {
379  /* cmdDrawIndexed.vertexCount */ primitiveSet.position->buffer.elementsCount,
380  /* cmdDrawIndexed.instanceCount */ 1,
381  };
382 
383  frameData.renderCmdBuffer.draw(cmdDraw);
384  }
385  }
386  }
387  }
388  }
389 
390  // Render skybox
391  {
392  Resource::SharedPtr<Render::SkyBox> skyBox = renderQueue.getSkyBox();
393  if (skyBox && skyBox->getBackgroundTexture()) {
394  Resource::SharedPtr<Render::Texture> skyBoxTexture = Resource::SharedPtr<Render::Texture>::cast(skyBox->getBackgroundTexture());
395  // Get the new (or old) skyBox descriptor set
396  {
397  const DescriptorSetPool::DescriptorSet* skyBoxDescriptorSet = _skyBoxDescriptorSetPool->allocate(skyBoxTexture.get());
398 
399  if (!skyBoxDescriptorSet) {
400  LUG_LOG.error("Forward::render: Can't allocate skyBox descriptor set");
401  return false;
402  }
403 
405  frameData.skyBoxDescriptorSet = skyBoxDescriptorSet;
406  }
407 
408  // Bind descriptor set of the skybox
409  {
410  const API::CommandBuffer::CmdBindDescriptors skyBoxBind{
411  /* skyBoxBind.pipelineLayout */ *SkyBox::getPipeline().getLayout(),
412  /* skyBoxBind.pipelineBindPoint */ VK_PIPELINE_BIND_POINT_GRAPHICS,
413  /* skyBoxBind.firstSet */ 1,
414  /* skyBoxBind.descriptorSets */ {&frameData.skyBoxDescriptorSet->getDescriptorSet()},
415  /* skyBoxBind.dynamicOffsets */ {},
416  };
417 
418  frameData.renderCmdBuffer.bindDescriptorSets(skyBoxBind);
419  }
420 
421  frameData.renderCmdBuffer.bindPipeline(SkyBox::getPipeline());
422 
423  auto& primitiveSet = SkyBox::getMesh()->getPrimitiveSets()[0];
424 
425  frameData.renderCmdBuffer.bindVertexBuffers(
426  {static_cast<API::Buffer*>(primitiveSet.position->_data)},
427  {0}
428  );
429 
430  API::Buffer* indicesBuffer = static_cast<API::Buffer*>(primitiveSet.indices->_data);
431  frameData.renderCmdBuffer.bindIndexBuffer(*indicesBuffer, VK_INDEX_TYPE_UINT16);
432  const API::CommandBuffer::CmdDrawIndexed cmdDrawIndexed {
433  /* cmdDrawIndexed.indexCount */ primitiveSet.indices->buffer.elementsCount,
434  /* cmdDrawIndexed.instanceCount */ 1,
435  };
436 
437  frameData.renderCmdBuffer.drawIndexed(cmdDrawIndexed);
438  }
439  }
440 
441  // Free and replace previous lightBuffers
442  {
443  for (const auto& subBuffer : frameData.lightBuffers) {
444  _lightBufferPool->free(subBuffer);
445  }
446 
447  frameData.lightBuffers = lightBuffers;
448  }
449 
450  // Free and replace previous materialBuffers
451  {
452  for (const auto& subBuffer : frameData.materialBuffers) {
453  _materialBufferPool->free(subBuffer);
454  }
455 
456  frameData.materialBuffers = materialBuffers;
457  }
458 
459  // Free and replace previous lightDescriptorSets
460  {
461  for (const auto& descriptorSet : frameData.lightDescriptorSets) {
462  _lightDescriptorSetPool->free(descriptorSet);
463  }
464 
465  frameData.lightDescriptorSets = lightDescriptorSets;
466  }
467 
468  // Free and replace previous materialDescriptorSets
469  {
470  for (const auto& descriptorSet : frameData.materialDescriptorSets) {
471  _materialDescriptorSetPool->free(descriptorSet);
472  }
473 
474  frameData.materialDescriptorSets = materialDescriptorSets;
475  }
476 
477  // Free and replace previous materialTexturesDescriptorSets
478  {
479  for (const auto& descriptorSet : frameData.materialTexturesDescriptorSets) {
480  _materialTexturesDescriptorSetPool->free(descriptorSet);
481  }
482 
483  frameData.materialTexturesDescriptorSets = materialTexturesDescriptorSets;
484  }
485 
486  // End of the render pass
487  frameData.renderCmdBuffer.endRenderPass();
488 
489  if (!frameData.renderCmdBuffer.end() || !frameData.transferCmdBuffer.end()) {
490  return false;
491  }
492 
493  return _transferQueue->submit(
494  frameData.transferCmdBuffer,
495  {static_cast<VkSemaphore>(frameData.transferSemaphore)},
496  {},
497  {},
498  static_cast<VkFence>(frameData.transferFence)
499  ) && _graphicsQueue->submit(
500  frameData.renderCmdBuffer,
501  {static_cast<VkSemaphore>(drawCompleteSemaphore)},
502  {static_cast<VkSemaphore>(frameData.transferSemaphore), static_cast<VkSemaphore>(imageReadySemaphore)},
503  {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
504  static_cast<VkFence>(frameData.renderFence)
505  );
506 }
507 
508 bool Forward::init(const std::vector<API::ImageView>& imageViews) {
509  VkResult result{VK_SUCCESS};
510 
511  // Init graphics queue
512  {
513  _graphicsQueue = _renderer.getDevice().getQueue("queue_graphics");
514  if (!_graphicsQueue) {
515  LUG_LOG.error("Forward::init: Can't find queue with name queue_graphics");
516  return false;
517  }
518 
520  if (!commandPoolBuilder.build(_graphicsCommandPool, &result)) {
521  LUG_LOG.error("Forward::init: Can't create the graphics command pool: {}", result);
522  return false;
523  }
524  }
525 
526  // Init transfer queue
527  {
528  _transferQueue = _renderer.getDevice().getQueue("queue_transfer");
529  if (!_transferQueue) {
530  LUG_LOG.error("Forward::init: Can't find queue with name queue_transfer");
531  return false;
532  }
533 
535  if (!commandPoolBuilder.build(_transferCommandPool, &result)) {
536  LUG_LOG.error("Forward::init: Can't create the transfer command pool: {}", result);
537  return false;
538  }
539  }
540 
541  API::Builder::Fence fenceBuilder(_renderer.getDevice());
542  fenceBuilder.setFlags(VK_FENCE_CREATE_SIGNALED_BIT); // Signaled state
543 
544  API::Builder::CommandBuffer graphicsCommandBufferBuilder(_renderer.getDevice(), _graphicsCommandPool);
545  graphicsCommandBufferBuilder.setLevel(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
546 
547  API::Builder::CommandBuffer transferCommandBufferBuilder(_renderer.getDevice(), _transferCommandPool);
548  transferCommandBufferBuilder.setLevel(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
549 
550  API::Builder::Semaphore semaphoreBuilder(_renderer.getDevice());
551 
552  _framesData.resize(imageViews.size());
553  for (uint32_t i = 0; i < _framesData.size(); ++i) {
554  // Create the render fence
555  if (!fenceBuilder.build(_framesData[i].renderFence, &result)) {
556  LUG_LOG.error("Forward::init: Can't create render fence: {}", result);
557  return false;
558  }
559 
560  // Create the transfer fence
561  if (!fenceBuilder.build(_framesData[i].transferFence, &result)) {
562  LUG_LOG.error("Forward::init: Can't create transfer fence: {}", result);
563  return false;
564  }
565 
566  // Create the render command buffer
567  if (!graphicsCommandBufferBuilder.build(_framesData[i].renderCmdBuffer, &result)) {
568  LUG_LOG.error("Forward::init: Can't create the render command buffer: {}", result);
569  return false;
570  }
571 
572  // Create the transfer command buffer
573  if (!transferCommandBufferBuilder.build(_framesData[i].transferCmdBuffer, &result)) {
574  LUG_LOG.error("Forward::init: Can't create the transfer command buffer: {}", result);
575  return false;
576  }
577 
578  if (!semaphoreBuilder.build(_framesData[i].transferSemaphore, &result)) {
579  LUG_LOG.error("Forward::init: Can't create the transfer semaphore: {}", result);
580  return false;
581  }
582  }
583 
584  if (!_cameraBufferPool) {
585  _cameraBufferPool = std::make_unique<BufferPool::Camera>(_renderer);
586  }
587 
588  if (!_lightBufferPool) {
589  _lightBufferPool = std::make_unique<BufferPool::Light>(_renderer);
590  }
591 
592  if (!_materialBufferPool) {
593  _materialBufferPool = std::make_unique<BufferPool::Material>(_renderer);
594  }
595 
597  _cameraDescriptorSetPool = std::make_unique<DescriptorSetPool::Camera>(_renderer);
598  if (!_cameraDescriptorSetPool->init()) {
599  return false;
600  }
601  }
602 
604  _lightDescriptorSetPool = std::make_unique<DescriptorSetPool::Light>(_renderer);
605  if (!_lightDescriptorSetPool->init()) {
606  return false;
607  }
608  }
609 
611  _materialDescriptorSetPool = std::make_unique<DescriptorSetPool::Material>(_renderer);
612  if (!_materialDescriptorSetPool->init()) {
613  return false;
614  }
615  }
616 
618  _materialTexturesDescriptorSetPool = std::make_unique<DescriptorSetPool::MaterialTextures>(_renderer);
619  if (!_materialTexturesDescriptorSetPool->init()) {
620  return false;
621  }
622  }
623 
625  _skyBoxDescriptorSetPool = std::make_unique<DescriptorSetPool::SkyBox>(_renderer);
626  if (!_skyBoxDescriptorSetPool->init()) {
627  return false;
628  }
629  }
630 
631  return initDepthBuffers(imageViews) && initFramebuffers(imageViews);
632 }
633 
635  --_forwardCount;
636 
639 
640  for (auto& frameData : _framesData) {
641  _cameraBufferPool->free(frameData.cameraBuffer);
642 
643  for (const auto& subBuffer : frameData.lightBuffers) {
644  _lightBufferPool->free(subBuffer);
645  }
646 
647  for (const auto& subBuffer : frameData.materialBuffers) {
648  _lightBufferPool->free(subBuffer);
649  }
650 
651  _cameraDescriptorSetPool->free(frameData.cameraDescriptorSet);
652 
653  for (const auto& descriptorSet : frameData.lightDescriptorSets) {
654  _lightDescriptorSetPool->free(descriptorSet);
655  }
656 
657  for (const auto& descriptorSet : frameData.materialDescriptorSets) {
658  _materialDescriptorSetPool->free(descriptorSet);
659  }
660 
661  for (const auto& descriptorSet : frameData.materialTexturesDescriptorSets) {
662  _materialTexturesDescriptorSetPool->free(descriptorSet);
663  }
664 
665  _skyBoxDescriptorSetPool->free(frameData.skyBoxDescriptorSet);
666  }
667 
668  _framesData.clear();
669 
671 
672  if (_forwardCount == 0) {
673  _cameraBufferPool.reset();
674  _lightBufferPool.reset();
675  _materialBufferPool.reset();
676 
677  _cameraDescriptorSetPool.reset();
678  _lightDescriptorSetPool.reset();
681  _skyBoxDescriptorSetPool.reset();
682  }
683 
686 }
687 
688 bool Forward::initDepthBuffers(const std::vector<API::ImageView>& imageViews) {
689  API::Builder::Image imageBuilder(_renderer.getDevice());
690 
691  imageBuilder.setUsage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
692  imageBuilder.setPreferedFormats({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT});
693  imageBuilder.setFeatureFlags(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
694 
695  _framesData.resize(imageViews.size());
696 
697  API::Builder::DeviceMemory deviceMemoryBuilder(_renderer.getDevice());
698  deviceMemoryBuilder.setMemoryFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
699 
700  // Create images and add them to API::Builder::DeviceMemory
701  for (uint32_t i = 0; i < imageViews.size(); ++i) {
702  const VkExtent3D extent{
703  /* extent.width */ imageViews[i].getImage()->getExtent().width,
704  /* extent.height */ imageViews[i].getImage()->getExtent().height,
705  /* extent.depth */ 1
706  };
707 
708  imageBuilder.setExtent(extent);
709 
710  // Create depth buffer image
711  {
712  VkResult result{VK_SUCCESS};
713  if (!imageBuilder.build(_framesData[i].depthBuffer.image, &result)) {
714  LUG_LOG.error("Forward::initDepthBuffers: Can't create depth buffer image: {}", result);
715  return false;
716  }
717 
718  if (!deviceMemoryBuilder.addImage(_framesData[i].depthBuffer.image)) {
719  LUG_LOG.error("Forward::initDepthBuffers: Can't add image to device memory");
720  return false;
721  }
722  }
723  }
724 
725  // Initialize depth buffer memory (This memory is common for all depth buffer images)
726  {
727  VkResult result{VK_SUCCESS};
728  if (!deviceMemoryBuilder.build(_depthBufferMemory, &result)) {
729  LUG_LOG.error("Forward::initDepthBuffers: Can't create device memory: {}", result);
730  return false;
731  }
732  }
733 
734  // Create images views
735  for (uint32_t i = 0; i < imageViews.size(); ++i) {
736 
737  // Create depth buffer image view
738  API::Builder::ImageView imageViewBuilder(_renderer.getDevice(), _framesData[i].depthBuffer.image);
739 
740  imageViewBuilder.setFormat(_framesData[i].depthBuffer.image.getFormat());
741  imageViewBuilder.setAspectFlags(VK_IMAGE_ASPECT_DEPTH_BIT);
742 
743  VkResult result{VK_SUCCESS};
744  if (!imageViewBuilder.build(_framesData[i].depthBuffer.imageView, &result)) {
745  LUG_LOG.error("Forward::initDepthBuffers: Can't create depth buffer image view: {}", result);
746  return false;
747  }
748  }
749 
750  return true;
751 }
752 
753 bool Forward::initFramebuffers(const std::vector<API::ImageView>& imageViews) {
754  // The lights pipelines renderpass are compatible, so we don't need to create different frame buffers for each pipeline
755  const auto& basePipeline = _renderer.getPipeline(Pipeline::getBaseId());
756 
757  if (!basePipeline) {
758  return false;
759  }
760 
761  const API::RenderPass* renderPass = basePipeline->getPipelineAPI().getRenderPass();
762 
763  _framesData.resize(imageViews.size());
764 
765  for (uint32_t i = 0; i < imageViews.size(); i++) {
766  // Create depth buffer image view
767  API::Builder::Framebuffer framebufferBuilder(_renderer.getDevice());
768 
769  framebufferBuilder.setRenderPass(renderPass);
770  framebufferBuilder.addAttachment(&imageViews[i]);
771  framebufferBuilder.addAttachment(&_framesData[i].depthBuffer.imageView);
772  framebufferBuilder.setWidth(imageViews[i].getImage()->getExtent().width);
773  framebufferBuilder.setHeight(imageViews[i].getImage()->getExtent().height);
774 
775  VkResult result{VK_SUCCESS};
776  if (!framebufferBuilder.build(_framesData[i].framebuffer, &result)) {
777  LUG_LOG.error("Forward::initFramebuffers: Can't create framebuffer: {}", result);
778  return false;
779  }
780  }
781 
782  return true;
783 }
784 
785 } // Technique
786 } // Render
787 } // Vulkan
788 } // Graphics
789 } // lug
bool render(const Render::Queue &renderQueue, const API::Semaphore &imageReadySemaphore, const API::Semaphore &drawCompleteSemaphore, uint32_t currentImageIndex) override final
Definition: Forward.cpp:57
bool reset(bool releaseRessources=false) const
std::vector< const DescriptorSetPool::DescriptorSet * > lightDescriptorSets
Definition: Forward.hpp:57
struct lug::Graphics::Render::View::Scissor::@2 offset
Resource::SharedPtr< Camera::Camera > getCamera() const
Definition: View.inl:39
const std::vector< Scene::Node * > getLights() const
Definition: Queue.cpp:66
static std::unique_ptr< BufferPool::Material > _materialBufferPool
Definition: Forward.hpp:101
bool initDepthBuffers(const std::vector< API::ImageView > &imageViews) override final
Definition: Forward.cpp:688
void setFlags(VkFenceCreateFlags flags)
Definition: Fence.inl:1
static const API::GraphicsPipeline & getPipeline()
Definition: SkyBox.inl:1
const API::Queue * getQueue(const std::string &queueName) const
Definition: Device.cpp:70
bool init(const std::vector< API::ImageView > &imageViews) override final
Definition: Forward.cpp:508
bool submit(const CommandBuffer &commandBuffer, const std::vector< VkSemaphore > &signalSemaphores={}, const std::vector< VkSemaphore > &waitSemaphores={}, const std::vector< VkPipelineStageFlags > &waitDstStageMasks={}, VkFence fence=VK_NULL_HANDLE) const
Definition: Queue.cpp:32
Resource::SharedPtr< Render::Pipeline > getPipeline(Render::Pipeline::Id id)
Definition: Renderer.inl:77
void setLevel(VkCommandBufferLevel level)
Dummy class for a shared pointer.
Definition: Resource.hpp:66
const std::map< Render::Pipeline::Id, std::vector< PrimitiveSetInstance > > getPrimitiveSets() const
Definition: Queue.cpp:62
std::vector< const DescriptorSetPool::DescriptorSet * > materialTexturesDescriptorSets
Definition: Forward.hpp:59
const DescriptorSetPool::DescriptorSet * skyBoxDescriptorSet
Definition: Forward.hpp:56
std::vector< const DescriptorSetPool::DescriptorSet * > materialDescriptorSets
Definition: Forward.hpp:58
void beginRenderPass(const API::RenderPass &renderPass, const CmdBeginRenderPass &parameters, VkSubpassContents contents=VK_SUBPASS_CONTENTS_INLINE) const
const Scissor & getScissor() const
Definition: View.inl:13
static std::unique_ptr< DescriptorSetPool::MaterialTextures > _materialTexturesDescriptorSetPool
Definition: Forward.hpp:106
const QueueFamily * getQueueFamily() const
Definition: Queue.cpp:86
std::vector< const BufferPool::SubBuffer * > lightBuffers
Definition: Forward.hpp:52
void setUsage(VkImageUsageFlags usage)
Definition: Image.inl:37
struct lug::Graphics::Render::View::Scissor::@3 extent
bool initFramebuffers(const std::vector< API::ImageView > &imageViews) override final
Definition: Forward.cpp:753
const Viewport & getViewport() const
Definition: View.inl:9
const std::vector< Mesh::PrimitiveSet > & getPrimitiveSets() const
Definition: Mesh.inl:1
static SharedPtr< T > cast(const SharedPtr< RhsT > &rhs)
Dynamic casting of a SharedPtr to another one (RhsT to T)
static std::unique_ptr< DescriptorSetPool::Material > _materialDescriptorSetPool
Definition: Forward.hpp:105
static const lug::Graphics::Resource::SharedPtr< lug::Graphics::Render::Mesh > getMesh()
Definition: SkyBox.inl:5
static std::unique_ptr< BufferPool::Light > _lightBufferPool
Definition: Forward.hpp:100
void setMemoryFlags(VkMemoryPropertyFlags flags)
Definition: DeviceMemory.inl:1
const DescriptorSetPool::DescriptorSet * cameraDescriptorSet
Definition: Forward.hpp:55
#define LUG_LOG
Definition: Logger.hpp:73
static std::unique_ptr< DescriptorSetPool::SkyBox > _skyBoxDescriptorSetPool
Definition: Forward.hpp:107
const Resource::SharedPtr< Render::SkyBox > getSkyBox() const
Definition: Queue.cpp:74
const PipelineLayout * getLayout() const
static const lug::Graphics::Resource::SharedPtr< lug::Graphics::Render::Texture > getBrdfLut()
Definition: SkyBox.inl:9
const Math::Vec3f & getClearColor() const
Definition: View.inl:17
void setRenderPass(const API::RenderPass *renderPass)
Definition: Framebuffer.inl:1
static std::unique_ptr< BufferPool::Camera > _cameraBufferPool
Definition: Forward.hpp:99
void pushConstants(const CmdPushConstants &parameters) const
std::vector< const BufferPool::SubBuffer * > materialBuffers
Definition: Forward.hpp:53
static std::unique_ptr< DescriptorSetPool::Camera > _cameraDescriptorSetPool
Definition: Forward.hpp:103
std::size_t getLightsCount() const
Definition: Queue.cpp:70
bool begin(VkCommandBufferUsageFlags flags=VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) const
Forward(Renderer &renderer, const View &renderView)
Definition: Forward.cpp:49
static std::unique_ptr< DescriptorSetPool::Light > _lightDescriptorSetPool
Definition: Forward.hpp:104