TDME2  1.9.200
VKRenderer.cpp
Go to the documentation of this file.
1 /**
2  * Vulkan renderer
3  * based on
4  * https://github.com/glfw/glfw/blob/master/tests/vulkan.c and util.c from Vulkan samples
5  * https://vulkan-tutorial.com
6  * https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples
7  * https://github.com/SaschaWillems/Vulkan
8  * ...
9  */
10 
12 
13 #if defined(_MSC_VER)
14  // this suppresses a warning redefinition of APIENTRY macro
15  #define NOMINMAX
16  #include <windows.h>
17 #endif
18 #define GLFW_INCLUDE_VULKAN
19 #include <GLFW/glfw3.h>
20 
21 #include <ext/vulkan/glslang/Public/ShaderLang.h>
22 #include <ext/vulkan/spirv/GlslangToSpv.h>
23 #include <ext/vulkan/vma/src/VmaUsage.h>
24 #include <ext/vulkan/OGLCompilersDLL/InitializeDll.h>
25 
26 #define THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION
27 #include <ext/vulkan/svs/thsvs_simpler_vulkan_synchronization.h>
28 
29 #include <array>
30 #include <cassert>
31 #include <cstring>
32 #include <iterator>
33 #include <map>
34 #include <memory>
35 #include <stack>
36 #include <string>
37 #include <unordered_map>
38 #include <unordered_set>
39 #include <vector>
40 
41 #include <tdme/tdme.h>
43 #include <tdme/engine/Texture.h>
49 #include <tdme/engine/Engine.h>
52 #include <tdme/engine/Timing.h>
53 #include <tdme/math/Matrix4x4.h>
59 #include <tdme/utilities/Buffer.h>
61 #include <tdme/utilities/Console.h>
64 #include <tdme/utilities/Integer.h>
66 #include <tdme/utilities/RTTI.h>
69 #include <tdme/utilities/Time.h>
70 
71 using std::unique_ptr;
72 using std::floor;
73 using std::log2;
74 using std::max;
75 using std::to_string;
76 
77 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
78 #define ERR_EXIT(err_msg, err_class) \
79  do { \
80  Console::println(err_msg); \
81  Application::exit(1); \
82  } while (0)
83 
84 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
85  { \
86  fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
87  if (fp##entrypoint == nullptr) { \
88  ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, "vkGetInstanceProcAddr Failure"); \
89  } \
90  }
91 
92 #define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
93  { \
94  fp##entrypoint = (PFN_vk##entrypoint)vkGetDeviceProcAddr(dev, "vk" #entrypoint); \
95  if (fp##entrypoint == nullptr) { \
96  ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, "vkGetDeviceProcAddr Failure"); \
97  } \
98  }
99 
100 using std::array;
101 using std::iterator;
102 using std::map;
103 using std::memcpy;
104 using std::stack;
105 using std::string;
106 using std::to_string;
107 using std::unordered_map;
108 using std::unordered_set;
109 using std::vector;
110 
112 
140 
141 VKRenderer::VKRenderer():
142  Renderer(),
143  queueSpinlock("queue_spinlock"),
144  buffersMutex("buffers_mutex"),
145  texturesMutex("textures_mutex"),
146  deleteMutex("delete_mutex"),
147  disposeMutex("dispose_mutex"),
148  pipelinesSpinLock("pipelines_spinlock"),
149  vmaSpinlock("vma_spinlock")
150 {
152  // setup consts
153  ID_NONE = 0;
156  CULLFACE_FRONT = VK_CULL_MODE_FRONT_BIT;
157  CULLFACE_BACK = VK_CULL_MODE_BACK_BIT;
158  FRONTFACE_CW = VK_FRONT_FACE_CLOCKWISE + 1;
159  FRONTFACE_CCW = VK_FRONT_FACE_COUNTER_CLOCKWISE + 1;
160  SHADER_FRAGMENT_SHADER = VK_SHADER_STAGE_FRAGMENT_BIT;
161  SHADER_VERTEX_SHADER = VK_SHADER_STAGE_VERTEX_BIT;
162  SHADER_COMPUTE_SHADER = VK_SHADER_STAGE_COMPUTE_BIT;
163  DEPTHFUNCTION_ALWAYS = VK_COMPARE_OP_ALWAYS;
164  DEPTHFUNCTION_EQUAL = VK_COMPARE_OP_EQUAL;
165  DEPTHFUNCTION_LESSEQUAL = VK_COMPARE_OP_LESS_OR_EQUAL;
166  DEPTHFUNCTION_GREATEREQUAL = VK_COMPARE_OP_GREATER_OR_EQUAL;
174  //
175  viewport.x = 0.0f;
176  viewport.y = 0.0f;
177  viewport.minDepth = 0.0f;
178  viewport.maxDepth = 1.0f;
179  scissor.offset.x = 0;
180  scissor.offset.y = 0;
183 }
184 
185 inline VkBool32 VKRenderer::checkLayers(uint32_t checkCount, const char **checkNames, const vector<VkLayerProperties>& instanceLayers) {
186  uint32_t i, j;
187  for (i = 0; i < checkCount; i++) {
188  VkBool32 found = 0;
189  for (j = 0; j < instanceLayers.size(); j++) {
190  if (!strcmp(checkNames[i], instanceLayers[j].layerName)) {
191  found = 1;
192  break;
193  }
194  }
195  if (!found) {
196  fprintf(stderr, "Cannot find layer: %s\n", checkNames[i]);
197  return 0;
198  }
199  }
200  return 1;
201 }
202 
203 inline void VKRenderer::prepareSetupCommandBuffer(int contextIdx) {
204  auto& currentContext = contexts[contextIdx];
205  if (currentContext.setupCommandInUse == VK_NULL_HANDLE) {
206  currentContext.setupCommandInUse = currentContext.setupCommand;
207 
208  //
209  const VkCommandBufferBeginInfo cmdBufInfo = {
210  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
211  .pNext = nullptr,
212  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
213  .pInheritanceInfo = nullptr
214  };
215 
216  VkResult err;
217  err = vkBeginCommandBuffer(currentContext.setupCommandInUse, &cmdBufInfo);
218  assert(!err);
219 
220  //
221  AtomicOperations::increment(statistics.drawCommands);
222  }
223 }
224 
225 inline void VKRenderer::finishSetupCommandBuffer(int contextIdx) {
226  auto& currentContext = contexts[contextIdx];
227 
228  //
229  if (currentContext.setupCommandInUse != VK_NULL_HANDLE) {
230  //
231  VkResult err;
232  err = vkEndCommandBuffer(currentContext.setupCommandInUse);
233  assert(!err);
234 
235  VkFence nullFence = { VK_NULL_HANDLE };
236  VkSubmitInfo submitInfo = {
237  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
238  .pNext = nullptr,
239  .waitSemaphoreCount = 0,
240  .pWaitSemaphores = nullptr,
241  .pWaitDstStageMask = nullptr,
242  .commandBufferCount = 1,
243  .pCommandBuffers = &currentContext.setupCommandInUse,
244  .signalSemaphoreCount = 0,
245  .pSignalSemaphores = nullptr
246  };
247 
249 
250  err = vkQueueSubmit(queue, 1, &submitInfo, currentContext.setupFence);
251  assert(!err);
252 
253  //
255 
256  //
257  AtomicOperations::increment(statistics.submits);
258 
259  //
260  VkResult fenceResult;
261  do {
262  fenceResult = vkWaitForFences(device, 1, &currentContext.setupFence, VK_TRUE, 100000000);
263  } while (fenceResult == VK_TIMEOUT);
264  vkResetFences(device, 1, &currentContext.setupFence);
265 
266  //
267  currentContext.setupCommandInUse = VK_NULL_HANDLE;
268  }
269 }
270 
271 inline bool VKRenderer::beginDrawCommandBuffer(int contextIdx, int bufferId) {
272  auto& currentContext = contexts[contextIdx];
273 
274  //
275  if (bufferId == -1) bufferId = currentContext.currentCommandBuffer;
276 
277  //
278  auto& commandBuffer = currentContext.commandBuffers[bufferId];
279  if (commandBuffer.drawCmdStarted == true) return false;
280 
281  //
282  VkResult fenceResult;
283  do {
284  fenceResult = vkWaitForFences(device, 1, &commandBuffer.drawFence, VK_TRUE, 100000000);
285  } while (fenceResult == VK_TIMEOUT);
286  vkResetFences(device, 1, &commandBuffer.drawFence);
287 
288  //
289  const VkCommandBufferBeginInfo cmdBufInfo = {
290  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
291  .pNext = nullptr,
292  .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
293  .pInheritanceInfo = nullptr
294  };
295 
296  //
297  VkResult err;
298  err = vkBeginCommandBuffer(commandBuffer.drawCommand, &cmdBufInfo);
299  assert(!err);
300 
301  array<ThsvsAccessType, 2> nextAccessTypes { THSVS_ACCESS_COLOR_ATTACHMENT_WRITE, THSVS_ACCESS_NONE };
302  ThsvsImageLayout nextLayout { THSVS_IMAGE_LAYOUT_OPTIMAL };
303 
304  // check if we need a change at all
305  if (boundFrameBufferId == ID_NONE &&
306  (windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes != nextAccessTypes || windowFramebufferBuffers[currentWindowFramebufferIdx].svsLayout != nextLayout)) {
307  ThsvsImageBarrier svsImageBarrier = {
308  .prevAccessCount = static_cast<uint32_t>(windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes[1] != THSVS_ACCESS_NONE?2:1),
309  .pPrevAccesses = windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes.data(),
310  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
311  .pNextAccesses = nextAccessTypes.data(),
312  .prevLayout = windowFramebufferBuffers[currentWindowFramebufferIdx].svsLayout,
313  .nextLayout = nextLayout,
314  .discardContents = true,
315  .srcQueueFamilyIndex = 0,
316  .dstQueueFamilyIndex = 0,
318  .subresourceRange = {
319  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
320  .baseMipLevel = 0,
321  .levelCount = 1,
322  .baseArrayLayer = 0,
323  .layerCount = 1
324  }
325  };
326  VkImageMemoryBarrier vkImageMemoryBarrier;
327  VkPipelineStageFlags srcStages;
328  VkPipelineStageFlags dstStages;
329  thsvsGetVulkanImageMemoryBarrier(
330  svsImageBarrier,
331  &srcStages,
332  &dstStages,
333  &vkImageMemoryBarrier
334  );
335 
336  //
337  VkResult err;
338 
339  //
340  vkCmdPipelineBarrier(commandBuffer.drawCommand, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
341 
342  //
343  windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes = nextAccessTypes;
345  }
346 
347  //
348  commandBuffer.drawCmdStarted = true;
349 
350  //
351  AtomicOperations::increment(statistics.drawCommands);
352 
353  //
354  return true;
355 }
356 
357 inline VkCommandBuffer VKRenderer::endDrawCommandBuffer(int contextIdx, int bufferId, bool cycleBuffers) {
358  auto& currentContext = contexts[contextIdx];
359  //
360  if (bufferId == -1) bufferId = currentContext.currentCommandBuffer;
361  auto& commandBuffer = currentContext.commandBuffers[bufferId];
362 
363  //
364  currentContext.pipeline = VK_NULL_HANDLE;
365 
366  //
367  if (commandBuffer.drawCmdStarted == false) return VK_NULL_HANDLE;
368 
369  //
370  VkResult err;
371  err = vkEndCommandBuffer(commandBuffer.drawCommand);
372  assert(!err);
373 
374  //
375  auto endedCommandBuffer = commandBuffer.drawCommand;
376 
377  //
378  commandBuffer.drawCmdStarted = false;
379 
380  //
381  if (cycleBuffers == true) currentContext.currentCommandBuffer = (currentContext.currentCommandBuffer + 1) % DRAW_COMMANDBUFFER_MAX;
382 
383  //
384  return endedCommandBuffer;
385 }
386 
387 inline void VKRenderer::submitDrawCommandBuffers(int commandBufferCount, VkCommandBuffer* commandBuffers, VkFence& fence) {
388  //
389  VkResult err;
390  VkPipelineStageFlags pipeStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
391  VkSubmitInfo submitInfo = {
392  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
393  .pNext = nullptr,
394  .waitSemaphoreCount = 0,
395  .pWaitSemaphores = nullptr,
396  .pWaitDstStageMask = &pipeStageFlags,
397  .commandBufferCount = static_cast<uint32_t>(commandBufferCount),
398  .pCommandBuffers = commandBuffers,
399  .signalSemaphoreCount = 0,
400  .pSignalSemaphores = nullptr
401  };
402 
403  //
405 
406  err = vkQueueSubmit(queue, 1, &submitInfo, fence);
407  assert(!err);
408 
410 
411  //
412  AtomicOperations::increment(statistics.submits);
413 }
414 
416  for (auto contextIdx = 0; contextIdx < Engine::getThreadCount(); contextIdx++) finishSetupCommandBuffer(contextIdx);
417 }
418 
419 inline void VKRenderer::setImageLayout(int contextIdx, texture_type* textureObject, const array<ThsvsAccessType,2>& nextAccessTypes, ThsvsImageLayout nextLayout, bool discardContent, uint32_t baseMipLevel, uint32_t levelCount, bool submit) {
420  auto& currentContext = contexts[contextIdx];
421 
422  // does this texture object point to a cube map color/depth buffer texture?
423  auto _textureObject = textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapBufferTexture:textureObject;
424 
425  // base array layer that applies to cube maps only
426  auto baseArrayLayer = static_cast<uint32_t>(textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapTextureIndex - CUBEMAPTEXTUREINDEX_MIN:0);
427 
428  // check if we need a change at all
429  if (_textureObject->accessTypes[baseArrayLayer] == nextAccessTypes && _textureObject->svsLayout == nextLayout) return;
430 
431  ThsvsImageBarrier svsImageBarrier = {
432  .prevAccessCount = static_cast<uint32_t>(_textureObject->accessTypes[baseArrayLayer][1] != THSVS_ACCESS_NONE?2:1),
433  .pPrevAccesses = _textureObject->accessTypes[baseArrayLayer].data(),
434  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
435  .pNextAccesses = nextAccessTypes.data(),
436  .prevLayout = _textureObject->svsLayout,
437  .nextLayout = nextLayout,
438  .discardContents = discardContent,
439  .srcQueueFamilyIndex = 0,
440  .dstQueueFamilyIndex = 0,
441  .image = _textureObject->image,
442  .subresourceRange = {
443  .aspectMask = _textureObject->aspectMask,
444  .baseMipLevel = baseMipLevel,
445  .levelCount = levelCount,
446  .baseArrayLayer = baseArrayLayer, // cube map texture index if cube map or 0 for framebuffer or ordinary textures
447  .layerCount = 1
448  }
449  };
450  VkImageMemoryBarrier vkImageMemoryBarrier;
451  VkPipelineStageFlags srcStages;
452  VkPipelineStageFlags dstStages;
453  thsvsGetVulkanImageMemoryBarrier(
454  svsImageBarrier,
455  &srcStages,
456  &dstStages,
457  &vkImageMemoryBarrier
458  );
459 
460  //
461  prepareSetupCommandBuffer(contextIdx);
462  vkCmdPipelineBarrier(currentContext.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
463  if (submit == true) finishSetupCommandBuffer(contextIdx);
464 
465  //
466  _textureObject->accessTypes[baseArrayLayer] = nextAccessTypes;
467  _textureObject->svsLayout = nextLayout;
468  _textureObject->vkLayout = vkImageMemoryBarrier.newLayout;
469 }
470 
472  image_layout_change& imageLayoutChange,
473  texture_type* textureObject,
474  const array<ThsvsAccessType,2>& prevAccessTypes,
475  const array<ThsvsAccessType,2>& nextAccessTypes,
476  ThsvsImageLayout prevLayout,
477  ThsvsImageLayout nextLayout,
478  bool discardContent,
479  uint32_t baseMipLevel,
480  uint32_t levelCount
481 ) {
482  // does this texture object point to a cube map color/depth buffer texture?
483  auto _textureObject = textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapBufferTexture:textureObject;
484 
485  // base array layer that applies to cube maps only
486  auto baseArrayLayer = static_cast<uint32_t>(textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapTextureIndex - CUBEMAPTEXTUREINDEX_MIN:0);
487 
488  //
489  ThsvsImageBarrier svsImageBarrier = {
490  .prevAccessCount = static_cast<uint32_t>(prevAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
491  .pPrevAccesses = prevAccessTypes.data(),
492  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
493  .pNextAccesses = nextAccessTypes.data(),
494  .prevLayout = prevLayout,
495  .nextLayout = nextLayout,
496  .discardContents = discardContent,
497  .srcQueueFamilyIndex = 0,
498  .dstQueueFamilyIndex = 0,
499  .image = _textureObject->image, // cubemap color/depth buffer image or framebuffer / ordinary texture image
500  .subresourceRange = {
501  .aspectMask = _textureObject->aspectMask,
502  .baseMipLevel = baseMipLevel,
503  .levelCount = levelCount,
504  .baseArrayLayer = baseArrayLayer, // cube map texture index if cube map or 0 for framebuffer or ordinary textures
505  .layerCount = 1
506  }
507  };
508  thsvsGetVulkanImageMemoryBarrier(
509  svsImageBarrier,
510  &imageLayoutChange.srcStages,
511  &imageLayoutChange.dstStages,
512  &imageLayoutChange.vkImageMemoryBarrier
513  );
514 
515  //
516  imageLayoutChange.accessTypes = nextAccessTypes;
517  imageLayoutChange.svsLayout = nextLayout;
518  imageLayoutChange.vkLayout = imageLayoutChange.vkImageMemoryBarrier.newLayout;
519  imageLayoutChange.valid = true;
520 }
521 
522 inline void VKRenderer::applyImageLayoutChange(int contextIdx, const image_layout_change& imageLayoutChange, texture_type* textureObject, bool submit) {
523  auto& currentContext = contexts[contextIdx];
524 
525  // does this texture object point to a cube map color/depth buffer texture?
526  auto _textureObject = textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapBufferTexture:textureObject;
527 
528  //
529  prepareSetupCommandBuffer(contextIdx);
530  vkCmdPipelineBarrier(currentContext.setupCommandInUse, imageLayoutChange.srcStages, imageLayoutChange.dstStages, 0, 0, nullptr, 0, nullptr, 1, &imageLayoutChange.vkImageMemoryBarrier);
531  if (submit == true) finishSetupCommandBuffer(contextIdx);
532 
533  // base array layer that applies to cube maps only
534  auto baseArrayLayer = static_cast<uint32_t>(textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapTextureIndex - CUBEMAPTEXTUREINDEX_MIN:0);
535 
536  //
537  _textureObject->accessTypes[baseArrayLayer] = imageLayoutChange.accessTypes;
538  _textureObject->svsLayout = imageLayoutChange.svsLayout;
539  _textureObject->vkLayout = imageLayoutChange.vkLayout;
540 }
541 
542 void VKRenderer::applyImageLayoutChanges(int contextIdx, const array<image_layout_change, 8> imageLayoutChanges, array<texture_type*, 8> textureObjects, bool submit) {
543  auto& currentContext = contexts[contextIdx];
544 
545  //
546  array<VkImageMemoryBarrier, 8> vkImageMemoryBarriers = {
547  imageLayoutChanges[0].vkImageMemoryBarrier,
548  imageLayoutChanges[1].vkImageMemoryBarrier,
549  imageLayoutChanges[2].vkImageMemoryBarrier,
550  imageLayoutChanges[3].vkImageMemoryBarrier,
551  imageLayoutChanges[4].vkImageMemoryBarrier,
552  imageLayoutChanges[5].vkImageMemoryBarrier,
553  imageLayoutChanges[6].vkImageMemoryBarrier,
554  imageLayoutChanges[7].vkImageMemoryBarrier
555  };
556 
557  //
558  prepareSetupCommandBuffer(contextIdx);
559  vkCmdPipelineBarrier(currentContext.setupCommandInUse, imageLayoutChanges[0].srcStages, imageLayoutChanges[0].dstStages, 0, 0, nullptr, 0, nullptr, vkImageMemoryBarriers.size(), vkImageMemoryBarriers.data());
560  if (submit == true) finishSetupCommandBuffer(contextIdx);
561 
562  //
563  auto i = 0;
564  for (auto textureObject: textureObjects) {
565  // does this texture object point to a cube map color/depth buffer texture?
566  auto _textureObject = textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapBufferTexture:textureObject;
567 
568  // base array layer that applies to cube maps only
569  auto baseArrayLayer = static_cast<uint32_t>(textureObject->cubemapBufferTexture != nullptr?textureObject->cubemapTextureIndex - CUBEMAPTEXTUREINDEX_MIN:0);
570 
571  //
572  _textureObject->accessTypes[baseArrayLayer] = imageLayoutChanges[i].accessTypes;
573  _textureObject->svsLayout = imageLayoutChanges[i].svsLayout;
574  _textureObject->vkLayout = imageLayoutChanges[i].vkLayout;
575  i++;
576  }
577 }
578 
579 inline void VKRenderer::setImageLayout2(int contextIdx, texture_type* textureObject, const array<ThsvsAccessType,2>& accessTypes, const array<ThsvsAccessType,2>& nextAccessTypes, ThsvsImageLayout layout, ThsvsImageLayout nextLayout, bool discardContent, uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, uint32_t layerCount, bool updateTextureObject) {
580  auto& currentContext = contexts[contextIdx];
581 
582  //
583  ThsvsImageBarrier svsImageBarrier = {
584  .prevAccessCount = static_cast<uint32_t>(accessTypes[1] != THSVS_ACCESS_NONE?2:1),
585  .pPrevAccesses = accessTypes.data(),
586  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
587  .pNextAccesses = nextAccessTypes.data(),
588  .prevLayout = layout,
589  .nextLayout = nextLayout,
590  .discardContents = discardContent,
591  .srcQueueFamilyIndex = 0,
592  .dstQueueFamilyIndex = 0,
593  .image = textureObject->image,
594  .subresourceRange = {
595  .aspectMask = textureObject->aspectMask,
596  .baseMipLevel = baseMipLevel,
597  .levelCount = levelCount,
598  .baseArrayLayer = baseArrayLayer,
599  .layerCount = layerCount
600  }
601  };
602  VkImageMemoryBarrier vkImageMemoryBarrier;
603  VkPipelineStageFlags srcStages;
604  VkPipelineStageFlags dstStages;
605  thsvsGetVulkanImageMemoryBarrier(
606  svsImageBarrier,
607  &srcStages,
608  &dstStages,
609  &vkImageMemoryBarrier
610  );
611 
612  //
613  prepareSetupCommandBuffer(contextIdx);
614  vkCmdPipelineBarrier(currentContext.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
615  finishSetupCommandBuffer(contextIdx);
616 
617  //
618  textureObject->accessTypes[baseArrayLayer] = nextAccessTypes;
619  textureObject->svsLayout = nextLayout;
620  textureObject->vkLayout = vkImageMemoryBarrier.newLayout;
621 }
622 
623 inline void VKRenderer::setImageLayout3(int contextIdx, VkImage image, VkImageAspectFlags aspectMask, const array<ThsvsAccessType,2>& accessTypes, const array<ThsvsAccessType,2>& nextAccessTypes, ThsvsImageLayout layout, ThsvsImageLayout nextLayout) {
624  auto& currentContext = contexts[contextIdx];
625 
626  //
627  ThsvsImageBarrier svsImageBarrier = {
628  .prevAccessCount = static_cast<uint32_t>(accessTypes[1] != THSVS_ACCESS_NONE?2:1),
629  .pPrevAccesses = accessTypes.data(),
630  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
631  .pNextAccesses = nextAccessTypes.data(),
632  .prevLayout = layout,
633  .nextLayout = nextLayout,
634  .discardContents = false,
635  .srcQueueFamilyIndex = 0,
636  .dstQueueFamilyIndex = 0,
637  .image = image,
638  .subresourceRange = {
639  .aspectMask = aspectMask,
640  .baseMipLevel = 0,
641  .levelCount = 1,
642  .baseArrayLayer = 0,
643  .layerCount = 1
644  }
645  };
646  VkImageMemoryBarrier vkImageMemoryBarrier;
647  VkPipelineStageFlags srcStages;
648  VkPipelineStageFlags dstStages;
649  thsvsGetVulkanImageMemoryBarrier(
650  svsImageBarrier,
651  &srcStages,
652  &dstStages,
653  &vkImageMemoryBarrier
654  );
655 
656  //
657  prepareSetupCommandBuffer(contextIdx);
658  vkCmdPipelineBarrier(currentContext.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
659  finishSetupCommandBuffer(contextIdx);
660 }
661 
662 inline void VKRenderer::prepareTextureImage(int contextIdx, struct texture_type* textureObject, VkImageTiling tiling, VkImageUsageFlags usage, VkFlags requiredFlags, Texture* texture, const array<ThsvsAccessType,2>& nextAccesses, ThsvsImageLayout imageLayout, bool disableMipMaps, uint32_t baseLevel, uint32_t levelCount) {
663  auto& currentContext = contexts[contextIdx];
664 
665  VkResult err;
666  bool pass;
667 
668  auto textureWidth = static_cast<uint32_t>(texture->getTextureWidth());
669  auto textureHeight = static_cast<uint32_t>(texture->getTextureHeight());
670 
671  const VkImageCreateInfo imageCreateInfo = {
672  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
673  .pNext = nullptr,
674  .flags = 0,
675  .imageType = VK_IMAGE_TYPE_2D,
676  .format = textureCompressionAvailable == true && texture->isUseCompression() == true?VK_FORMAT_BC7_UNORM_BLOCK:VK_FORMAT_R8G8B8A8_UNORM,
677  .extent = {
678  .width = textureWidth,
679  .height = textureHeight,
680  .depth = 1
681  },
682  .mipLevels = disableMipMaps == false && texture->isUseMipMap() == true?static_cast<uint32_t>(texture->getMipLevels()):1,
683  .arrayLayers = 1,
684  .samples = VK_SAMPLE_COUNT_1_BIT,
685  .tiling = tiling,
686  .usage = usage,
687  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
688  .queueFamilyIndexCount = 0,
689  .pQueueFamilyIndices = 0,
690  .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
691  };
692 
693  VmaAllocationCreateInfo imageAllocCreateInfo = {};
694  imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_UNKNOWN;
695  imageAllocCreateInfo.requiredFlags = requiredFlags;
696 
697  VmaAllocationInfo allocationInfo = {};
698  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &imageAllocCreateInfo, &textureObject->image, &textureObject->allocation, &allocationInfo);
699  assert(!err);
700 
701  if ((requiredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
702  const VkImageSubresource imageSubResource = {
703  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
704  .mipLevel = 0,
705  .arrayLayer = 0,
706  };
707  VkSubresourceLayout subResourceLayout;
708  vkGetImageSubresourceLayout(device, textureObject->image, &imageSubResource, &subResourceLayout);
709 
710  //
711  vmaSpinlock.lock();
712 
713  //
714  void* data;
715  err = vmaMapMemory(vmaAllocator, textureObject->allocation, &data);
716  assert(!err);
717 
718  // rgba
719  auto bytesPerPixel = texture->getRGBDepthBitsPerPixel() / 8;
720  auto textureTextureData = texture->getRGBTextureData();
721  for (auto y = 0; y < textureHeight; y++) {
722  uint8_t* row = (uint8_t*)((uint8_t*)data + subResourceLayout.offset + subResourceLayout.rowPitch * y);
723  for (auto x = 0; x < textureWidth; x++) {
724  row[x * 4 + 0] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 0);
725  row[x * 4 + 1] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 1);
726  row[x * 4 + 2] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 2);
727  row[x * 4 + 3] = bytesPerPixel == 4?textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 3):0xff;
728  }
729  }
730 
731  //
732  vmaFlushAllocation(vmaAllocator, textureObject->allocation, 0, VK_WHOLE_SIZE);
733  vmaUnmapMemory(vmaAllocator, textureObject->allocation);
734 
735  //
737  }
738 
739  //
740  textureObject->accessTypes = { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE };
742  contextIdx,
743  textureObject,
744  nextAccesses,
745  THSVS_IMAGE_LAYOUT_OPTIMAL,
746  false,
747  baseLevel,
748  levelCount,
749  true
750  );
751 }
752 
753 inline void VKRenderer::prepareMipMapTextureImage(int contextIdx, struct texture_type* textureObject, VkImageTiling tiling, VkImageUsageFlags usage, VkFlags requiredFlags, Texture* texture, const Texture::MipMapTexture& mipMapTexture, const array<ThsvsAccessType,2>& nextAccesses, ThsvsImageLayout imageLayout) {
754  auto& currentContext = contexts[contextIdx];
755 
756  VkResult err;
757  bool pass;
758 
759  auto textureWidth = static_cast<uint32_t>(mipMapTexture.width);
760  auto textureHeight = static_cast<uint32_t>(mipMapTexture.height);
761 
762  const VkImageCreateInfo imageCreateInfo = {
763  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
764  .pNext = nullptr,
765  .flags = 0,
766  .imageType = VK_IMAGE_TYPE_2D,
767  .format = textureCompressionAvailable == true && texture->isUseCompression() == true?VK_FORMAT_BC7_UNORM_BLOCK:VK_FORMAT_R8G8B8A8_UNORM,
768  .extent = {
769  .width = textureWidth,
770  .height = textureHeight,
771  .depth = 1
772  },
773  .mipLevels = 1,
774  .arrayLayers = 1,
775  .samples = VK_SAMPLE_COUNT_1_BIT,
776  .tiling = tiling,
777  .usage = usage,
778  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
779  .queueFamilyIndexCount = 0,
780  .pQueueFamilyIndices = 0,
781  .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
782  };
783 
784  VmaAllocationCreateInfo imageAllocCreateInfo = {};
785  imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_UNKNOWN;
786  imageAllocCreateInfo.requiredFlags = requiredFlags;
787 
788  VmaAllocationInfo allocationInfo = {};
789  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &imageAllocCreateInfo, &textureObject->image, &textureObject->allocation, &allocationInfo);
790  assert(!err);
791 
792  if ((requiredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
793  const VkImageSubresource imageSubResource = {
794  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
795  .mipLevel = 0,
796  .arrayLayer = 0,
797  };
798  VkSubresourceLayout subResourceLayout;
799  vkGetImageSubresourceLayout(device, textureObject->image, &imageSubResource, &subResourceLayout);
800 
801  //
802  vmaSpinlock.lock();
803 
804  //
805  void* data;
806  err = vmaMapMemory(vmaAllocator, textureObject->allocation, &data);
807  assert(!err);
808 
809  // rgba
810  auto bytesPerPixel = texture->getRGBDepthBitsPerPixel() / 8;
811  auto& textureTextureData = mipMapTexture.textureData;
812  for (auto y = 0; y < textureHeight; y++) {
813  uint8_t* row = (uint8_t*)((uint8_t*)data + subResourceLayout.offset + subResourceLayout.rowPitch * y);
814  for (auto x = 0; x < textureWidth; x++) {
815  row[x * 4 + 0] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 0);
816  row[x * 4 + 1] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 1);
817  row[x * 4 + 2] = textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 2);
818  row[x * 4 + 3] = bytesPerPixel == 4?textureTextureData.get((y * textureWidth * bytesPerPixel) + (x * bytesPerPixel) + 3):0xff;
819  }
820  }
821 
822  //
823  vmaFlushAllocation(vmaAllocator, textureObject->allocation, 0, VK_WHOLE_SIZE);
824  vmaUnmapMemory(vmaAllocator, textureObject->allocation);
825 
826  //
828  }
829 
830  //
831  textureObject->accessTypes = { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE };
833  contextIdx,
834  textureObject,
835  nextAccesses,
836  THSVS_IMAGE_LAYOUT_OPTIMAL,
837  false,
838  0,
839  1,
840  true
841  );
842 }
843 
845  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
846 
847  VkResult err;
848  VkSwapchainKHR oldSwapchain = windowSwapchain;
849 
850  // Check the surface capabilities and formats
851  VkSurfaceCapabilitiesKHR surfCapabilities;
853  assert(err == VK_SUCCESS);
854 
855  uint32_t presentModeCount;
856  err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr);
857  assert(err == VK_SUCCESS);
858  vector<VkPresentModeKHR> presentModes(presentModeCount);
859  err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
860  assert(err == VK_SUCCESS);
861 
862  VkExtent2D swapchainExtent;
863  // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
864  if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
865  // If the surface size is undefined, the size is set to the size
866  // of the images requested, which must fit within the minimum and
867  // maximum values.
868  swapchainExtent.width = windowWidth;
869  swapchainExtent.height = windowHeight;
870 
871  if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
872  swapchainExtent.width = surfCapabilities.minImageExtent.width;
873  } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) {
874  swapchainExtent.width = surfCapabilities.maxImageExtent.width;
875  }
876 
877  if (swapchainExtent.height < surfCapabilities.minImageExtent.height) {
878  swapchainExtent.height = surfCapabilities.minImageExtent.height;
879  } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {
880  swapchainExtent.height = surfCapabilities.maxImageExtent.height;
881  }
882  } else {
883  // If the surface size is defined, the swap chain size must match
884  swapchainExtent = surfCapabilities.currentExtent;
885  windowWidth = surfCapabilities.currentExtent.width;
886  windowHeight = surfCapabilities.currentExtent.height;
887  }
888 
889  // Determine the number of VkImage's to use in the swap chain.
890  // Application desires to only acquire 1 image at a time (which is
891  // "surfCapabilities.minImageCount").
892  uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
893  // If maxImageCount is 0, we can ask for as many images as we want;
894  // otherwise we're limited to maxImageCount
895  if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
896  // Application must settle for fewer images than desired:
897  desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
898  }
899 
900  //
901  VkSurfaceTransformFlagsKHR preTransform {};
902  if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
903  preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
904  } else {
905  preTransform = surfCapabilities.currentTransform;
906  }
907 
908  const VkSwapchainCreateInfoKHR swapchainCreateInfo = {
909  .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
910  .pNext = nullptr,
911  .flags = 0,
912  .surface = surface,
913  .minImageCount = desiredNumOfSwapchainImages,
914  .imageFormat = windowFormat,
915  .imageColorSpace = windowColorSpace,
916  .imageExtent = {
917  .width = swapchainExtent.width,
918  .height = swapchainExtent.height
919  },
920  .imageArrayLayers = 1,
921  .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
922  .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
923  .queueFamilyIndexCount = 0,
924  .pQueueFamilyIndices = 0,
925  .preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform, /// TODO = a.drewke, ???
926  .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
927  .presentMode = swapchainPresentMode,
928  .clipped = true,
929  .oldSwapchain = oldSwapchain,
930  };
931 
932  err = fpCreateSwapchainKHR(device, &swapchainCreateInfo, nullptr, &windowSwapchain);
933  assert(!err);
934 
935  // If we just re-created an existing swapchain, we should destroy the old
936  // swapchain at this point.
937  // Note: destroying the swapchain also cleans up all its associated
938  // presentable images once the platform is done with them.
939  if (oldSwapchain != VK_NULL_HANDLE) {
940  fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
941  }
942 
943  //
944  windowSwapchainImageCount = desiredNumOfSwapchainImages;
945 
946  //
948  assert(err == VK_SUCCESS);
949 
950  vector<VkImage> swapchainImages(windowSwapchainImageCount);
952  assert(err == VK_SUCCESS);
953 
954  //
956  for (auto i = 0; i < windowFramebufferBuffers.size(); i++) {
957  //
958  windowFramebufferBuffers[i].width = swapchainExtent.width;
959  windowFramebufferBuffers[i].height = swapchainExtent.height;
960 
961  //
962  VkImageViewCreateInfo colorAttachmentView = {
963  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
964  .pNext = nullptr,
965  .flags = 0,
966  .image = swapchainImages[i],
967  .viewType = VK_IMAGE_VIEW_TYPE_2D,
968  .format = windowFormat,
969  .components = {
970  .r = VK_COMPONENT_SWIZZLE_R,
971  .g = VK_COMPONENT_SWIZZLE_G,
972  .b = VK_COMPONENT_SWIZZLE_B,
973  .a = VK_COMPONENT_SWIZZLE_A
974  },
975  .subresourceRange = {
976  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
977  .baseMipLevel = 0,
978  .levelCount = 1,
979  .baseArrayLayer = 0,
980  .layerCount = 1
981  }
982  };
983  windowFramebufferBuffers[i].image = swapchainImages[i];
984  err = vkCreateImageView(device, &colorAttachmentView, nullptr, &windowFramebufferBuffers[i].view);
985  assert(err == VK_SUCCESS);
986  }
987 
989 }
990 
991 const string VKRenderer::getVendor() {
992  return StringTools::tokenize(deviceName, " \t\n")[0];
993 }
994 
995 const string VKRenderer::getRenderer() {
996  return deviceName + " [VK]";
997 }
998 
1000 {
1001  return "gl3";
1002 }
1003 
1005  return false;
1006 }
1007 
1009 {
1010  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
1011 
1012  // create VK shader cache folder
1013  try {
1014  if (FileSystem::getInstance()->exists("shader/vk") == false) {
1015  FileSystem::getInstance()->createPath("shader/vk");
1016  }
1017  } catch (Exception& exception) {
1018  Console::println(string() + "An error occurred: " + exception.what());
1019  }
1020 
1021  //
1022  glfwGetWindowSize(Application::glfwWindow, (int32_t*)&windowWidth, (int32_t*)&windowHeight);
1023 
1024  //
1025  glslang::InitProcess();
1026  glslang::InitThread();
1027  ShInitialize();
1028 
1029  VkResult err;
1030  uint32_t i = 0;
1031  uint32_t requiredExtensionCount = 0;
1032  uint32_t instanceExtensionCount = 0;
1033  uint32_t instanceLayerCount = 0;
1034  uint32_t validationLayerCount = 0;
1035  const char** requiredExtensions = nullptr;
1036  const char** instanceValidationLayers = nullptr;
1037 
1038  uint32_t enabledExtensionCount = 0;
1039  uint32_t enabledLayerCount = 0;
1040  array<const char*, 64> extensionNames {};
1041  array<const char*, 64>enabledLayers {};
1042 
1043  const char* instanceValidationLayersAlt1[] = {
1044  "VK_LAYER_KHRONOS_validation"
1045  };
1046  const char* instanceValidationLayersAlt2[] = {
1047  "VK_LAYER_LUNARG_standard_validation"
1048  };
1049 
1050  // enable validation layers if app runs in debug mode
1051  auto enableValidationLayers = Application::getApplication()->isDebuggingEnabled();
1052  if (enableValidationLayers == true) {
1053  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): \"--debug\" mode enabled: Enabling validation layers");
1054 
1055  VkBool32 validationFound = 0;
1056  err = vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr);
1057  assert(!err);
1058 
1059  instanceValidationLayers = (const char**)instanceValidationLayersAlt1;
1060  if (instanceLayerCount > 0) {
1061  vector<VkLayerProperties> instanceLayers(instanceLayerCount);
1062  err = vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers.data());
1063  assert(!err);
1064 
1065  validationFound = checkLayers(
1066  ARRAY_SIZE(instanceValidationLayersAlt1),
1067  instanceValidationLayers,
1068  instanceLayers
1069  );
1070  if (validationFound == VK_SUCCESS) {
1071  enabledLayerCount = ARRAY_SIZE(instanceValidationLayersAlt1);
1072  enabledLayers[0] = "VK_LAYER_LUNARG_standard_validation";
1073  validationLayerCount = 1;
1074  } else {
1075  // use alternative set of validation layers
1076  instanceValidationLayers = (const char**) instanceValidationLayersAlt2;
1077  enabledLayerCount = ARRAY_SIZE(instanceValidationLayersAlt2);
1078  validationFound = checkLayers(
1079  ARRAY_SIZE(instanceValidationLayersAlt2),
1080  instanceValidationLayers,
1081  instanceLayers
1082  );
1083  validationLayerCount = ARRAY_SIZE(instanceValidationLayersAlt2);
1084  for (i = 0; i < validationLayerCount; i++) {
1085  enabledLayers[i] = instanceValidationLayers[i];
1086  }
1087  }
1088  }
1089 
1090  if (!validationFound) {
1091  ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
1092  "required validation layer.\n\n"
1093  "Please look at the Getting Started guide for additional "
1094  "information.\n", "vkCreateInstance Failure");
1095  }
1096  }
1097 
1098  // Look for instance extensions
1099  requiredExtensions = glfwGetRequiredInstanceExtensions(&requiredExtensionCount);
1100  if (!requiredExtensions) {
1101  ERR_EXIT("glfwGetRequiredInstanceExtensions failed to find the "
1102  "platform surface extensions.\n\nDo you have a compatible "
1103  "Vulkan installable client driver (ICD) installed?\nPlease "
1104  "look at the Getting Started guide for additional "
1105  "information.\n", "vkCreateInstance Failure"
1106  );
1107  }
1108 
1109  for (i = 0; i < requiredExtensionCount; i++) {
1110  extensionNames[enabledExtensionCount++] = requiredExtensions[i];
1111  assert(enabledExtensionCount < 64);
1112  }
1113 
1114  err = vkEnumerateInstanceExtensionProperties(
1115  nullptr, &instanceExtensionCount, nullptr);
1116  assert(!err);
1117 
1118  if (instanceExtensionCount > 0) {
1119  vector<VkExtensionProperties> instanceExtensions(instanceExtensionCount);
1120  err = vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, instanceExtensions.data());
1121  assert(!err);
1122  for (i = 0; i < instanceExtensionCount; i++) {
1123  if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instanceExtensions[i].extensionName)) {
1124  if (enableValidationLayers == true) {
1125  extensionNames[enabledExtensionCount++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1126  }
1127  }
1128  assert(enabledExtensionCount < 64);
1129  }
1130  }
1131 
1132  const VkApplicationInfo applicationInfo = {
1133  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1134  .pNext = nullptr,
1135  .pApplicationName = Application::getApplication()->getTitle().c_str(),
1136  .applicationVersion = 0,
1137  .pEngineName = "TDME2",
1138  .engineVersion = 200,
1139  .apiVersion = VK_API_VERSION_1_0,
1140  };
1141  VkInstanceCreateInfo instanceCreateInfo = {
1142  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1143  .pNext = nullptr,
1144  .flags = 0,
1145  .pApplicationInfo = &applicationInfo,
1146  .enabledLayerCount = enabledLayerCount,
1147  .ppEnabledLayerNames = instanceValidationLayers,
1148  .enabledExtensionCount = enabledExtensionCount,
1149  .ppEnabledExtensionNames = extensionNames.data(),
1150  };
1151  err = vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
1152  if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1153  ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1154  "(ICD).\n\nPlease look at the Getting Started guide for "
1155  "additional information.\n", "vkCreateInstance Failure");
1156  } else
1157  if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1158  ERR_EXIT("Cannot find a specified extension library"
1159  ".\nMake sure your layers path is set appropriately\n",
1160  "vkCreateInstance Failure");
1161  } else
1162  if (err) {
1163  ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
1164  "installable client driver (ICD) installed?\nPlease look at "
1165  "the Getting Started guide for additional information.\n",
1166  "vkCreateInstance Failure");
1167  }
1168 
1169  // Make initial call to query gpu_count, then second call for gpu info
1170  uint32_t gpuCount = 0;
1171  err = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr);
1172  assert(!err && gpuCount > 0);
1173 
1174  //
1175  if (gpuCount > 0) {
1176  vector<VkPhysicalDevice> physicalDevices(gpuCount);
1177  err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
1178  assert(!err);
1179  physicalDevice = physicalDevices[0];
1180  } else {
1181  ERR_EXIT(
1182  "vkEnumeratePhysicalDevices reported zero accessible devices."
1183  "\n\nDo you have a compatible Vulkan installable client"
1184  " driver (ICD) installed?\nPlease look at the Getting Started"
1185  " guide for additional information.\n",
1186  "vkEnumeratePhysicalDevices Failure"
1187  );
1188  }
1189 
1190  // Look for device extensions
1191  uint32_t deviceExtensionCount = 0;
1192  VkBool32 swapchainExtFound = 0;
1193  enabledExtensionCount = 0;
1194 
1195  err = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, nullptr);
1196  assert(!err);
1197 
1198  if (deviceExtensionCount > 0) {
1199  vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
1200  err = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, deviceExtensions.data());
1201  assert(!err);
1202  for (i = 0; i < deviceExtensionCount; i++) {
1203  if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, deviceExtensions[i].extensionName)) {
1204  swapchainExtFound = 1;
1205  extensionNames[enabledExtensionCount++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
1206  }
1207  assert(enabledExtensionCount < 64);
1208  }
1209  }
1210 
1211  if (!swapchainExtFound) {
1212  ERR_EXIT(
1213  "vkEnumerateDeviceExtensionProperties failed to find "
1214  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
1215  " extension.\n\nDo you have a compatible "
1216  "Vulkan installable client driver (ICD) installed?\nPlease "
1217  "look at the Getting Started guide for additional "
1218  "information.\n", "vkCreateInstance Failure"
1219  );
1220  }
1221 
1222  // Having these GIPA queries of device extension entry points both
1223  // BEFORE and AFTER vkCreateDevice is a good test for the loader
1224  GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
1225  GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
1226  GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
1227  GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
1228 
1229  vkGetPhysicalDeviceProperties(physicalDevice, &gpuProperties);
1230 
1231  //
1232  deviceName = gpuProperties.deviceName;
1233 
1234  // Query with nullptr data to get count
1235  vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, nullptr);
1236 
1237  queueProperties = new VkQueueFamilyProperties[queueCount];
1238  vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProperties);
1239  assert(queueCount >= 1);
1240 
1241  vkGetPhysicalDeviceFeatures(physicalDevice, &gpuFeatures);
1242 
1243  //
1244  textureCompressionAvailable = gpuFeatures.textureCompressionBC == VK_TRUE;
1245 
1246  // Create a WSI surface for the window:
1247  err = glfwCreateWindowSurface(instance, Application::glfwWindow, nullptr, &surface);
1248  assert(!err);
1249 
1250  // Iterate over each queue to learn whether it supports presenting:
1251  vector<VkBool32> supportsPresent(queueCount);
1252  for (i = 0; i < queueCount; i++) {
1254  }
1255 
1256  // Search for a graphics and a present queue in the array of queue
1257  // families, try to find one that supports both
1258  graphicsQueueNodeIndex = UINT32_MAX;
1259  uint32_t presentQueueNodeIndex = UINT32_MAX;
1260  for (i = 0; i < queueCount; i++) {
1261  if ((queueProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
1262  if (graphicsQueueNodeIndex == UINT32_MAX) {
1264  }
1265  if (supportsPresent[i] == VK_TRUE) {
1267  presentQueueNodeIndex = i;
1268  break;
1269  }
1270  }
1271  }
1272  if (presentQueueNodeIndex == UINT32_MAX) {
1273  // If didn't find a queue that supports both graphics and present, then
1274  // find a separate present queue.
1275  for (i = 0; i < queueCount; ++i) {
1276  if (supportsPresent[i] == VK_TRUE) {
1277  presentQueueNodeIndex = i;
1278  break;
1279  }
1280  }
1281  }
1282 
1283  // Generate error if could not find both a graphics and a present queue
1284  if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
1285  ERR_EXIT(
1286  "Could not find a graphics and a present queue\n",
1287  "Swapchain Initialization Failure"
1288  );
1289  }
1290 
1291  // TODO: Add support for separate queues, including presentation,
1292  // synchronization, and appropriate tracking for QueueSubmit.
1293  // NOTE: While it is possible for an application to use a separate graphics
1294  // and a present queues, this demo program assumes it is only using
1295  // one:
1296  if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
1297  ERR_EXIT(
1298  "Could not find a common graphics and a present queue\n",
1299  "Swapchain Initialization Failure"
1300  );
1301  }
1302 
1303  // init_device
1304  array<float, 1> queuePriorities { 0.0f };
1305  const VkDeviceQueueCreateInfo queueCreateInfo = {
1306  .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
1307  .pNext = nullptr,
1308  .flags = 0,
1309  .queueFamilyIndex = graphicsQueueNodeIndex,
1310  .queueCount = queuePriorities.size(),
1311  .pQueuePriorities = queuePriorities.data()
1312  };
1313 
1314  VkPhysicalDeviceFeatures features {};
1315  if (gpuFeatures.shaderClipDistance) features.shaderClipDistance = VK_TRUE;
1316  if (gpuFeatures.wideLines) features.wideLines = VK_TRUE; // TODO: a.drewke, store enabled GPU features and check them on rendering if available
1317 
1318  VkDeviceCreateInfo deviceCreateInfo = {
1319  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1320  .pNext = nullptr,
1321  .flags = 0,
1322  .queueCreateInfoCount = 1,
1323  .pQueueCreateInfos = &queueCreateInfo,
1324  .enabledLayerCount = 0,
1325  .ppEnabledLayerNames = nullptr,
1326  .enabledExtensionCount = enabledExtensionCount,
1327  .ppEnabledExtensionNames = extensionNames.data(),
1328  .pEnabledFeatures = &features
1329  };
1330  err = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device);
1331  assert(!err);
1332 
1333  GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
1334  GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
1335  GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
1336  GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
1337  GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
1338 
1339  vkGetDeviceQueue(device, graphicsQueueNodeIndex, 0, &queue);
1340 
1341  // Get the list of VkFormat's that are supported:
1342  uint32_t surfaceFormatCount;
1343  err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, nullptr);
1344  assert(!err);
1345  vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
1346  err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, surfaceFormats.data());
1347  assert(!err);
1348 
1349  // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
1350  // the surface has no preferred format. Otherwise, at least one
1351  // supported format will be returned.
1352  // We for now only support VK_FORMAT_R8G8B8A8_UNORM
1353  if (surfaceFormatCount == 1 && surfaceFormats[0].format == VK_FORMAT_UNDEFINED) {
1354  windowFormat = VK_FORMAT_B8G8R8A8_UNORM;
1355  windowColorSpace = surfaceFormats[0].colorSpace;
1356  } else {
1357  for (auto i = 0; i < surfaceFormatCount; i++) {
1358  if (surfaceFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM) {
1359  windowFormat = VK_FORMAT_B8G8R8A8_UNORM;
1360  windowColorSpace = surfaceFormats[i].colorSpace;
1361  break;
1362  }
1363  }
1364  }
1365  if (windowFormat == VK_FORMAT_UNDEFINED) {
1366  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): No format given");
1367  ERR_EXIT(
1368  "Could not use VK_FORMAT_R8G8B8A8_UNORM as format\n",
1369  "Format Failure"
1370  );
1371  }
1372 
1373  // Get Memory information and properties
1374  vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
1375 
1376  // initialize allocator
1377  VmaAllocatorCreateInfo allocatorCreateInfo = {};
1378  allocatorCreateInfo.physicalDevice = physicalDevice;
1379  allocatorCreateInfo.device = device;
1380  allocatorCreateInfo.instance = instance;
1381  allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_0;
1382 
1383  //
1384  vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator);
1385 
1386  // swap chain
1388 
1389  // create descriptor pool 1
1390  {
1391  array<VkDescriptorPoolSize, 2> desc1TypesCount = {{
1392  {
1393  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1394  // 100 shaders * 3 command buffers * 2 shader stages * 1 uniform buffers
1395  .descriptorCount = static_cast<uint32_t>(DESC_MAX_UNCACHED * Engine::getThreadCount() * SHADERS_MAX * DRAW_COMMANDBUFFER_MAX * SHADERSSTAGES_MAX * 1)
1396  },
1397  {
1398  .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1399  // 1 shader * 3 command buffers * 1 shader stage * 8 storage buffers
1401  }
1402  }};
1403  const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
1404  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1405  .pNext = nullptr,
1406  .flags = 0,
1407  // 100 shaders * 2 stages
1408  .maxSets = static_cast<uint32_t>(DESC_MAX_UNCACHED * Engine::getThreadCount() * SHADERS_MAX * SHADERSSTAGES_MAX),
1409  .poolSizeCount = desc1TypesCount.size(),
1410  .pPoolSizes = desc1TypesCount.data(),
1411  };
1412  //
1413  err = vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool1);
1414  assert(!err);
1415  }
1416 
1417  // create descriptor pool 2
1418  {
1419  const VkDescriptorPoolSize desc2TypesCount = {
1420  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1421  // 100 shaders * 2 stages * 8 image sampler
1422  .descriptorCount = static_cast<uint32_t>((DESC_MAX_CACHED + DESC_MAX_UNCACHED) * Engine::getThreadCount() * SHADERS_MAX * SHADERSSTAGES_MAX * TEXTUREUNITS_MAX)
1423  };
1424  const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {
1425  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1426  .pNext = nullptr,
1427  .flags = 0,
1428  // 100 shaders * 2 stages
1429  .maxSets = static_cast<uint32_t>((DESC_MAX_CACHED + DESC_MAX_UNCACHED) * Engine::getThreadCount() * SHADERS_MAX * SHADERSSTAGES_MAX),
1430  .poolSizeCount = 1,
1431  .pPoolSizes = &desc2TypesCount,
1432  };
1433  //
1434  err = vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool2);
1435  assert(!err);
1436  }
1437 
1438  //
1439  contexts.resize(Engine::getThreadCount());
1440  // create set up command buffers
1441  for (auto contextIdx = 0; contextIdx < Engine::getThreadCount(); contextIdx++) {
1442  auto& context = contexts[contextIdx];
1443  //
1444  context.idx = contextIdx;
1445  context.setupCommandInUse = VK_NULL_HANDLE;
1446  context.currentCommandBuffer = 0;
1447  context.pipelineIdx = ID_NONE;
1448  context.pipeline = VK_NULL_HANDLE;
1449  context.renderPassStarted = false;
1450 
1451  //
1452  for (auto i = 0; i < DRAW_COMMANDBUFFER_MAX; i++) {
1453  context.commandBuffers[i].drawCmdStarted = false;
1454  VkFenceCreateInfo fenceCreateInfoSignaled = {
1455  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1456  .pNext = nullptr,
1457  .flags = VK_FENCE_CREATE_SIGNALED_BIT
1458  };
1459  vkCreateFence(device, &fenceCreateInfoSignaled, nullptr, &context.commandBuffers[i].drawFence);
1460  contextsDrawFences.push_back(context.commandBuffers[i].drawFence);
1461  }
1462 
1463  //
1464  {
1465  // command pool
1466  const VkCommandPoolCreateInfo commandPoolCreateInfo = {
1467  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1468  .pNext = nullptr,
1469  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1470  .queueFamilyIndex = graphicsQueueNodeIndex
1471  };
1472  err = vkCreateCommandPool(device, &commandPoolCreateInfo, nullptr, &context.setupCommandPool);
1473  assert(!err);
1474 
1475  // command buffer
1476  const VkCommandBufferAllocateInfo commandBufferAllocationInfo = {
1477  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1478  .pNext = nullptr,
1479  .commandPool = context.setupCommandPool,
1480  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1481  .commandBufferCount = 1
1482  };
1483  err = vkAllocateCommandBuffers(device, &commandBufferAllocationInfo, &context.setupCommand);
1484  assert(!err);
1485  }
1486 
1487  {
1488  // draw command pool
1489  const VkCommandPoolCreateInfo commandPoolCreateInfo = {
1490  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1491  .pNext = nullptr,
1492  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1493  .queueFamilyIndex = graphicsQueueNodeIndex
1494  };
1495  err = vkCreateCommandPool(device, &commandPoolCreateInfo, nullptr, &context.drawCommandPool);
1496  assert(!err);
1497 
1498  // command buffer
1499  const VkCommandBufferAllocateInfo commandBufferAllocationInfo = {
1500  .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1501  .pNext = nullptr,
1502  .commandPool = context.drawCommandPool,
1503  .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1504  .commandBufferCount = 1
1505  };
1506  for (auto i = 0; i < DRAW_COMMANDBUFFER_MAX; i++) {
1507  err = vkAllocateCommandBuffers(device, &commandBufferAllocationInfo, &context.commandBuffers[i].drawCommand);
1508  assert(!err);
1509  }
1510  }
1511 
1512  {
1513  VkFenceCreateInfo fenceCreateInfo = {
1514  .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1515  .pNext = nullptr,
1516  .flags = 0
1517  };
1518  vkCreateFence(device, &fenceCreateInfo, nullptr, &context.setupFence);
1519  }
1520  }
1521 
1522  //
1523  buffers.fill(nullptr);
1524  textures.fill(nullptr);
1525 
1526  //
1527  emptyVertexBufferId = createBufferObjects(1, true, true)[0];
1529  array<float, 16> bogusVertexBuffer = {{
1530  0.0f, 0.0f, 0.0f, 0.0f,
1531  0.0f, 0.0f, 0.0f, 0.0f,
1532  0.0f, 0.0f, 0.0f, 0.0f,
1533  0.0f, 0.0f, 0.0f, 0.0f,
1534  }};
1535  uploadBufferObjectInternal(0, emptyVertexBuffer, bogusVertexBuffer.size() * sizeof(float), (uint8_t*)bogusVertexBuffer.data(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1537 
1538  // fall back texture white
1539  whiteTextureSampler2dDefaultId = Engine::getInstance()->getTextureManager()->addTexture(TextureReader::read("resources/engine/textures", "transparent_pixel.png"), CONTEXTINDEX_DEFAULT);
1541 
1542  // fallback cube map texture white
1544  "cubemap-default-white",
1545  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1546  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1547  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1548  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1549  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1550  TextureReader::read("resources/engine/textures", "transparent_pixel.png"),
1552  );
1554 
1555  //
1556  for (auto& context: contexts) unbindBufferObjects(context.idx);
1557 
1558  //
1561 
1562  // renderer contexts
1563  rendererContexts.resize(contexts.size());
1564  for (auto& rendererContext: rendererContexts) {
1565  for (auto i = 0; i < rendererContext.lights.size(); i++) {
1566  rendererContext.lights[i].spotCosCutoff = static_cast<float>(Math::cos(Math::PI / 180.0f * 180.0f));
1567  }
1568  rendererContext.textureMatrix.identity();
1569  }
1570 }
1571 
1573  VkResult err;
1574 
1575  //
1576  if (renderPass != VK_NULL_HANDLE) vkDestroyRenderPass(device, renderPass, nullptr);
1577 
1578  // depth buffer
1581  auto depthBufferTexture = getTextureInternal(depthBufferDefault);
1582 
1583  //
1585  0,
1586  depthBufferTexture,
1587  { THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE },
1588  THSVS_IMAGE_LAYOUT_OPTIMAL,
1589  false
1590  );
1591 
1592  // render pass
1593  array<VkAttachmentDescription, 2> attachments = {{
1594  {
1595  .flags = 0,
1596  .format = windowFormat,
1597  .samples = VK_SAMPLE_COUNT_1_BIT,
1598  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1599  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1600  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1601  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1602  .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1603  .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
1604  },
1605  {
1606  .flags = 0,
1607  .format = VK_FORMAT_D32_SFLOAT,
1608  .samples = VK_SAMPLE_COUNT_1_BIT,
1609  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1610  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1611  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1612  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
1613  .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1614  .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
1615  }
1616  }};
1617  const VkAttachmentReference colorReference = {
1618  .attachment = 0,
1619  .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1620  };
1621  const VkAttachmentReference depthReference = {
1622  .attachment = 1,
1623  .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1624  };
1625  const VkSubpassDescription subPass = {
1626  .flags = 0,
1627  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1628  .inputAttachmentCount = 0,
1629  .pInputAttachments = nullptr,
1630  .colorAttachmentCount = 1,
1631  .pColorAttachments = &colorReference,
1632  .pResolveAttachments = nullptr,
1633  .pDepthStencilAttachment = &depthReference,
1634  .preserveAttachmentCount = 0,
1635  .pPreserveAttachments = nullptr
1636  };
1637  const VkRenderPassCreateInfo rp_info = {
1638  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1639  .pNext = nullptr,
1640  .flags = 0,
1641  .attachmentCount = 2,
1642  .pAttachments = attachments.data(),
1643  .subpassCount = 1,
1644  .pSubpasses = &subPass,
1645  .dependencyCount = 0,
1646  .pDependencies = nullptr
1647  };
1648  err = vkCreateRenderPass(device, &rp_info, nullptr, &renderPass);
1649  assert(!err);
1650 }
1651 
1652 inline void VKRenderer::startRenderPass(int contextIdx) {
1653  auto& currentContext = contexts[contextIdx];
1654 
1655  if (currentContext.renderPassStarted == true) return;
1656  currentContext.renderPassStarted = true;
1657 
1658  auto usedFrameBuffer = windowFramebufferBuffers[currentWindowFramebufferIdx].framebuffer;
1659  auto vkRenderPass = renderPass;
1660  if (boundFrameBufferId != ID_NONE) {
1661  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
1662  if (frameBuffer == nullptr) {
1663  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer not found: " + to_string(boundFrameBufferId));
1664  } else {
1665  usedFrameBuffer = frameBuffer->frameBuffer;
1666  vkRenderPass = frameBuffer->renderPass;
1667  }
1668  }
1669 
1670  // TODO: clear here!!! If clearing was set up
1671  const VkRenderPassBeginInfo renderPassBegin = {
1672  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1673  .pNext = nullptr,
1674  .renderPass = vkRenderPass,
1675  .framebuffer = usedFrameBuffer,
1676  .renderArea = scissor,
1677  .clearValueCount = 0,
1678  .pClearValues = nullptr
1679  };
1680  vkCmdBeginRenderPass(currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
1681 
1682  //
1683  AtomicOperations::increment(statistics.renderPasses);
1684 }
1685 
1686 inline void VKRenderer::endRenderPass(int contextIdx) {
1687  auto& currentContext = contexts[contextIdx];
1688  if (currentContext.renderPassStarted == false) return;
1689  currentContext.renderPassStarted = false;
1690  vkCmdEndRenderPass(currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand);
1691 }
1692 
1694  array<VkImageView, 2> attachments;
1695  auto depthBufferTexture = getTextureInternal(depthBufferDefault);
1696  attachments[1] = depthBufferTexture->view;
1697 
1698  const VkFramebufferCreateInfo frameBufferCreateInfo = {
1699  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1700  .pNext = nullptr,
1701  .flags = 0,
1702  .renderPass = renderPass,
1703  .attachmentCount = 2,
1704  .pAttachments = attachments.data(),
1705  .width = windowWidth,
1706  .height = windowHeight,
1707  .layers = 1
1708  };
1709 
1710  for (auto i = 0; i < windowFramebufferBuffers.size(); i++) {
1711  attachments[0] = windowFramebufferBuffers[i].view;
1712  auto err = vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &windowFramebufferBuffers[i].framebuffer);
1713  assert(!err);
1714  }
1715 }
1716 
1718  Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
1719 
1720  // new dimensions
1721  glfwGetWindowSize(Application::glfwWindow, (int32_t*)&windowWidth, (int32_t*)&windowHeight);
1722 
1723  //
1724  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(windowWidth) + " x " + to_string(windowHeight));
1725 
1726  // dispose old frame buffers
1727  for (auto i = 0; i < windowFramebufferBuffers.size(); i++) {
1728  vkDestroyFramebuffer(device, windowFramebufferBuffers[i].framebuffer, nullptr);
1729  windowFramebufferBuffers[i].framebuffer = VK_NULL_HANDLE;
1730  }
1731 
1732  //
1734 
1735  // reinit swapchain, renderpass and framebuffers
1739 
1740  //
1743 
1744  //
1746 }
1747 
1749 {
1750  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
1751 
1752  // work around for AMD drivers not telling if window needs to be reshaped
1753  {
1754  int32_t currentWidth;
1755  int32_t currentHeight;
1756  glfwGetWindowSize(Application::glfwWindow, &currentWidth, &currentHeight);
1757  auto needsReshape =
1758  (currentWidth > 0 && currentHeight > 0 && (currentWidth != windowWidth || currentHeight != windowHeight)) ||
1760  if (needsReshape == true) reshape();
1761  }
1762 
1763  //
1764  VkResult err;
1765  VkSemaphoreCreateInfo semaphoreCreateInfo = {
1766  .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1767  .pNext = nullptr,
1768  .flags = 0
1769  };
1770 
1771  err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAcquiredSemaphore);
1772  assert(!err);
1773 
1774  err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &drawCompleteSemaphore);
1775  assert(!err);
1776 
1777  //
1779 
1780  // get the index of the next available swapchain image:
1782 
1783  //
1784  if (err == VK_ERROR_OUT_OF_DATE_KHR) {
1785  // TODO: a.drewke
1786  //
1788  for (auto i = 0; i < Engine::getThreadCount(); i++) endRenderPass(i);
1789  vkDestroySemaphore(device, imageAcquiredSemaphore, nullptr);
1790  vkDestroySemaphore(device, drawCompleteSemaphore, nullptr);
1791 
1792  //
1794 
1795  // recreate semaphores
1796  err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &imageAcquiredSemaphore);
1797  assert(!err);
1798 
1799  err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &drawCompleteSemaphore);
1800  assert(!err);
1801  } else
1802  if (err == VK_SUBOPTIMAL_KHR) {
1803  // demo->swapchain is not as optimal as it could be, but the platform's
1804  // presentation engine will still present the image correctly.
1805  } else {
1806  assert(!err);
1807  }
1808 
1809  //
1810  for (auto i = 0; i < contexts.size(); i++) {
1811  contexts[i].commandCount = 0;
1812  }
1813 }
1814 
1816  // delete desc2 bound texture caches from programs with removed texture
1817  for (auto& context: contexts) {
1818  for (auto program: programVector) {
1819  if (program == nullptr || program->contexts[context.idx].texturesDescriptorSetsCacheTextureIds.empty() == true) continue;
1820  auto& programContext = program->contexts[context.idx];
1821  auto& descriptorSets2CacheTextureIds = programContext.texturesDescriptorSetsCacheTextureIds;
1822  auto descriptorSets2CacheTextureIdsIt = descriptorSets2CacheTextureIds.find(textureId);
1823  if (descriptorSets2CacheTextureIdsIt != descriptorSets2CacheTextureIds.end()) {
1824  auto& descriptorSets2Cache = programContext.texturesDescriptorSetsCache;
1825  for (auto& descriptorSets2CacheHash: descriptorSets2CacheTextureIdsIt->second) {
1826  auto descriptorSets2CacheHashIt = descriptorSets2Cache.find(descriptorSets2CacheHash);
1827  if (descriptorSets2CacheHashIt != descriptorSets2Cache.end()) {
1828  auto desc_sets2_idx = descriptorSets2CacheHashIt->second;
1829  programContext.freeTextureDescriptorSetsIds.push_back(desc_sets2_idx);
1830  descriptorSets2Cache.erase(descriptorSets2CacheHashIt);
1831  }
1832  }
1833  descriptorSets2CacheTextureIds.erase(descriptorSets2CacheTextureIdsIt);
1834  }
1835  }
1836  }
1837 }
1838 
1840  //
1841  auto clearedPipelinesParents = 0;
1842  auto clearedPipelines = 0;
1843 
1844  // caches
1845  framebufferPipelinesCache = nullptr;
1846 
1847  //
1848  disposeMutex.lock();
1849  for (auto i = 0; i < framebuffersPipelines.size(); i++) {
1850  // skip on compute
1851  if (framebuffersPipelines[i]->id == ID_NONE) continue;
1852  //
1853  auto framebufferPipelines = unique_ptr<framebuffer_pipelines_type>(framebuffersPipelines[i]);
1854  //
1855  for (auto pipeline: framebufferPipelines->pipelines) {
1856  if (pipeline != VK_NULL_HANDLE) {
1857  disposePipelines.push_back(pipeline);
1858  clearedPipelines++;
1859  }
1860  }
1861  framebuffersPipelines.erase(framebuffersPipelines.begin() + i);
1862  i--;
1863  clearedPipelinesParents++;
1864  }
1865  disposeMutex.unlock();
1866 
1867  //
1868  Console::println(
1869  "VKRenderer::" + string(__FUNCTION__) + "(): " +
1870  "cleared pipelines parents: " + to_string(clearedPipelinesParents) + ", " +
1871  "cleared pipelines: " + to_string(clearedPipelines)
1872  );
1873 }
1874 
1876 {
1877  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
1878 
1879  //
1880  finishRendering();
1881 
1882  // flush command buffers
1883  for (auto& context: contexts) {
1884  unsetPipeline(context.idx);
1885  context.program = nullptr;
1886  }
1887 
1888  // cache
1889  framebufferPipelinesCache = nullptr;
1890 
1891  //
1892  array<ThsvsAccessType, 2> nextAccessTypes { THSVS_ACCESS_PRESENT, THSVS_ACCESS_NONE };
1893  ThsvsImageLayout nextLayout { THSVS_IMAGE_LAYOUT_OPTIMAL };
1894 
1895  // check if we need a change at all
1896  if (windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes != nextAccessTypes || windowFramebufferBuffers[currentWindowFramebufferIdx].svsLayout != nextLayout) {
1897  ThsvsImageBarrier svsImageBarrier = {
1898  .prevAccessCount = static_cast<uint32_t>(windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes[1] != THSVS_ACCESS_NONE?2:1),
1899  .pPrevAccesses = windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes.data(),
1900  .nextAccessCount = static_cast<uint32_t>(nextAccessTypes[1] != THSVS_ACCESS_NONE?2:1),
1901  .pNextAccesses = nextAccessTypes.data(),
1902  .prevLayout = windowFramebufferBuffers[currentWindowFramebufferIdx].svsLayout,
1903  .nextLayout = nextLayout,
1904  .discardContents = false,
1905  .srcQueueFamilyIndex = 0,
1906  .dstQueueFamilyIndex = 0,
1908  .subresourceRange = {
1909  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1910  .baseMipLevel = 0,
1911  .levelCount = 1,
1912  .baseArrayLayer = 0,
1913  .layerCount = 1
1914  }
1915  };
1916  VkImageMemoryBarrier vkImageMemoryBarrier;
1917  VkPipelineStageFlags srcStages;
1918  VkPipelineStageFlags dstStages;
1919  thsvsGetVulkanImageMemoryBarrier(
1920  svsImageBarrier,
1921  &srcStages,
1922  &dstStages,
1923  &vkImageMemoryBarrier
1924  );
1925 
1926  //
1927  VkResult err;
1928 
1929  //
1931  vkCmdPipelineBarrier(contexts[0].setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1, &vkImageMemoryBarrier);
1933 
1934  //
1935  windowFramebufferBuffers[currentWindowFramebufferIdx].accessTypes = nextAccessTypes;
1936  windowFramebufferBuffers[currentWindowFramebufferIdx].svsLayout = nextLayout;
1937  }
1938 
1939  //
1940  VkResult presentResult = VK_SUCCESS;
1941  VkPresentInfoKHR presentInfoKHR = {
1942  .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1943  .pNext = nullptr,
1944  .waitSemaphoreCount = 0,
1945  .pWaitSemaphores = nullptr,
1946  .swapchainCount = 1,
1947  .pSwapchains = &windowSwapchain,
1948  .pImageIndices = &currentWindowFramebufferIdx,
1949  .pResults = &presentResult
1950  };
1951 
1952  //
1953  VkResult err;
1954  err = fpQueuePresentKHR(queue, &presentInfoKHR);
1955  auto needsReshape = false;
1956  if (err == VK_ERROR_OUT_OF_DATE_KHR) {
1957  needsReshape = true;
1958  } else
1959  if (err == VK_SUBOPTIMAL_KHR) {
1960  // swapchain is not as optimal as it could be, but the platform's
1961  // presentation engine will still present the image correctly.
1962  needsReshape = true;
1963  } else {
1964  assert(!err);
1965  }
1966 
1967  //
1968  vkDestroySemaphore(device, imageAcquiredSemaphore, nullptr);
1969  vkDestroySemaphore(device, drawCompleteSemaphore, nullptr);
1970 
1971  // dispose renderer mapped resources
1972  if (disposeTextures.empty() == false ||
1973  disposeBuffers.empty() == false ||
1974  deleteBuffers.empty() == false ||
1975  deleteImages.empty() == false) {
1976  deleteMutex.lock();
1977  disposeMutex.lock();
1978  // disposing textures
1979  texturesMutex.lock();
1980  for (auto textureId: disposeTextures) {
1981  auto texture = unique_ptr<texture_type>(getTextureInternal(textureId));
1982  if (texture == nullptr) {
1983  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): disposing texture: texture not found: " + to_string(textureId));
1984  continue;
1985  }
1986  // mark for deletion
1987  deleteImages.emplace_back(
1988  texture->image,
1989  texture->allocation,
1990  texture->view,
1991  texture->sampler
1992  );
1993  if (texture->cubemapColorBuffer != nullptr) {
1994  deleteImages.emplace_back(
1995  texture->cubemapColorBuffer->image,
1996  texture->cubemapColorBuffer->allocation,
1997  texture->cubemapColorBuffer->view,
1998  texture->cubemapColorBuffer->sampler
1999  );
2000  }
2001  if (texture->cubemapDepthBuffer != nullptr) {
2002  deleteImages.emplace_back(
2003  texture->cubemapDepthBuffer->image,
2004  texture->cubemapDepthBuffer->allocation,
2005  texture->cubemapDepthBuffer->view,
2006  texture->cubemapDepthBuffer->sampler
2007  );
2008  }
2009  //
2010  textures[textureId] = nullptr;
2012  freeTextureIds.push_back(textureId);
2013  }
2015  disposeTextures.clear();
2016  // disposing buffer objects
2017  buffersMutex.lock();
2018  for (auto bufferObjectId: disposeBuffers) {
2019  auto buffer = unique_ptr<buffer_object_type>(getBufferObjectInternal(bufferObjectId));
2020  if (buffer == nullptr) {
2021  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): disposing buffer object: buffer with id " + to_string(bufferObjectId) + " does not exist");
2022  continue;
2023  }
2024  for (auto& reusableBufferIt: buffer->buffers) {
2025  auto& reusableBuffer = reusableBufferIt;
2026  if (reusableBuffer.size == 0) continue;
2027  // mark staging buffer for deletion when finishing frame
2028  deleteBuffers.emplace_back(
2029  reusableBuffer.buffer,
2030  reusableBuffer.allocation
2031  );
2032  }
2033  buffers[bufferObjectId] = nullptr;
2034  freeBufferIds.push_back(bufferObjectId);
2035  }
2036  buffersMutex.unlock();
2037  disposeBuffers.clear();
2038  // disposing pipelines
2039  for (auto pipeline: disposePipelines) {
2040  vkDestroyPipeline(device, pipeline, nullptr);
2041  }
2042  disposePipelines.clear();
2043  disposeMutex.unlock();
2044 
2045  // remove marked vulkan resources
2046  // buffers
2047  for (const auto& deleteBuffer: deleteBuffers) {
2048  vmaUnmapMemory(vmaAllocator, deleteBuffer.allocation);
2049  vmaDestroyBuffer(vmaAllocator, deleteBuffer.buffer, deleteBuffer.allocation);
2050  }
2051  AtomicOperations::increment(statistics.disposedBuffers, deleteBuffers.size());
2052  deleteBuffers.clear();
2053  // textures
2054  for (const auto& deleteImage: deleteImages) {
2055  if (deleteImage.imageView != VK_NULL_HANDLE) vkDestroyImageView(device, deleteImage.imageView, nullptr);
2056  if (deleteImage.sampler != VK_NULL_HANDLE) vkDestroySampler(device, deleteImage.sampler, nullptr);
2057  if (deleteImage.image != VK_NULL_HANDLE) vmaDestroyImage(vmaAllocator, deleteImage.image, deleteImage.allocation);
2058  }
2059  AtomicOperations::increment(statistics.disposedTextures, deleteImages.size());
2060  deleteImages.clear();
2061 
2062  //
2063  deleteMutex.unlock();
2064  }
2065 
2066  // unbind bound resources
2067  uint32_t bufferSize = 0;
2068  for (auto& context: contexts) {
2069  context.boundIndicesBuffer = VK_NULL_HANDLE;
2070  context.boundBuffers.fill(getBindBufferObjectInternal(emptyVertexBufferId, bufferSize));
2071  context.boundBufferSizes.fill(bufferSize);
2072  context.boundTextures.fill(context_type::bound_texture());
2073  for (auto textureId: context.uploadedTextureIds) invalidateTextureDescriptorCaches(textureId);
2074  context.uploadedTextureIds.clear();
2075  }
2076 
2077  //
2078  frame++;
2079 }
2080 
2082 {
2084 }
2085 
2087 {
2088  return false;
2089 }
2090 
2092  return true;
2093 }
2094 
2095 
2097 {
2098  return true;
2099 }
2100 
2102 {
2103  return true;
2104 }
2105 
2107  return true;
2108 }
2109 
2111 {
2112  return true;
2113 }
2114 
2116  return true;
2117 }
2118 
2120  return false;
2121 }
2122 
2124  return false;
2125 }
2126 
2128  return deferredShadingAvailable;
2129 }
2130 
2132 {
2133  return TEXTUREUNITS_MAX;
2134 }
2135 
2136 
2137 int32_t VKRenderer::loadShader(int32_t type, const string& pathName, const string& fileName, const string& definitions, const string& functions)
2138 {
2139  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): INIT: " + pathName + "/" + fileName + ": " + definitions);
2140 
2141  auto shaderPtr = new shader_type();
2142  shaders[shaderIdx] = shaderPtr;
2143  auto& shader = *shaderPtr;
2144  shader.id = shaderIdx++;
2145 
2146  //
2147  VKGL3CoreShaderProgram::loadShader(shader, type, pathName, fileName, definitions, functions);
2148 
2149  //
2150  return shader.id;
2151 }
2152 
2153 inline void VKRenderer::unsetPipeline(int contextIdx) {
2154  auto& currentContext = contexts[contextIdx];
2155 
2156  //
2157  currentContext.pipelineIdx = ID_NONE;
2158  currentContext.pipeline = VK_NULL_HANDLE;
2159 }
2160 
2161 inline void VKRenderer::createRasterizationStateCreateInfo(int contextIdx, VkPipelineRasterizationStateCreateInfo& rasterizationStateCreateInfo) {
2162  rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
2163  rasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
2164  rasterizationStateCreateInfo.cullMode = contexts[contextIdx].cullingEnabled == true?cullMode:VK_CULL_MODE_NONE;
2165  rasterizationStateCreateInfo.frontFace = (VkFrontFace)(contexts[contextIdx].frontFace - 1);
2166  rasterizationStateCreateInfo.depthClampEnable = VK_FALSE;
2167  rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE;
2168  rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE;
2169  rasterizationStateCreateInfo.lineWidth = 1.0f;
2170 }
2171 
2172 inline void VKRenderer::createColorBlendAttachmentState(VkPipelineColorBlendAttachmentState& blendAttachmentState) {
2173  blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
2174  blendAttachmentState.blendEnable = blendingMode != BLENDING_NONE?VK_TRUE:VK_FALSE;
2175  blendAttachmentState.srcColorBlendFactor = blendingMode == BLENDING_NORMAL?VK_BLEND_FACTOR_SRC_ALPHA:VK_BLEND_FACTOR_ONE;
2176  blendAttachmentState.dstColorBlendFactor = blendingMode == BLENDING_NORMAL?VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:VK_BLEND_FACTOR_ONE;
2177  blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
2178  blendAttachmentState.srcAlphaBlendFactor = blendingMode == BLENDING_NORMAL?VK_BLEND_FACTOR_ONE:VK_BLEND_FACTOR_ONE;
2179  blendAttachmentState.dstAlphaBlendFactor = blendingMode == BLENDING_NORMAL?VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:VK_BLEND_FACTOR_ONE;
2180  blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
2181 }
2182 
2183 inline void VKRenderer::createDepthStencilStateCreateInfo(VkPipelineDepthStencilStateCreateInfo& depthStencilStateCreateInfo) {
2184  depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
2185  depthStencilStateCreateInfo.depthTestEnable = depthBufferTesting == true?VK_TRUE:VK_FALSE;
2186  depthStencilStateCreateInfo.depthWriteEnable = depthBufferWriting == true?VK_TRUE:VK_FALSE;
2187  depthStencilStateCreateInfo.depthCompareOp = (VkCompareOp)depthFunction;
2188  depthStencilStateCreateInfo.back.failOp = VK_STENCIL_OP_KEEP;
2189  depthStencilStateCreateInfo.back.passOp = VK_STENCIL_OP_KEEP;
2190  depthStencilStateCreateInfo.back.compareOp = VK_COMPARE_OP_ALWAYS;
2191  depthStencilStateCreateInfo.stencilTestEnable = VK_FALSE;
2192  depthStencilStateCreateInfo.front = depthStencilStateCreateInfo.back;
2193  depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE;
2194  depthStencilStateCreateInfo.minDepthBounds = 0.0f;
2195  depthStencilStateCreateInfo.maxDepthBounds = 1.0f;
2196 }
2197 
2199  return
2200  (static_cast<uint64_t>(viewPortWidth) & 0xffff) +
2201  ((static_cast<uint64_t>(viewPortHeight) & 0xffff) << 16) +
2202  ((static_cast<uint64_t>(boundFrameBufferId) & 0xffff) << 32);
2203 }
2204 
2205 inline uint16_t VKRenderer::createPipelineIndex(program_type* program, int contextIdx) {
2206  return
2207  (program->id & 0x7f) +
2208  ((contexts[contextIdx].cullingEnabled == true?cullMode:VK_CULL_MODE_NONE & 0x3) << 7) +
2209  ((contexts[contextIdx].frontFaceIndex & 0x3) << 9) +
2210  ((blendingMode & 0x3) << 11) +
2211  ((depthBufferTesting & 0x1) << 13) +
2212  ((depthBufferWriting & 0x1) << 14);
2213  // TODO: not yet in use, but later maybe: ((depthFunction & 0x7) << 15);
2214 }
2215 
2217  VkResult err;
2218  vector<VkDescriptorSetLayoutBinding> layoutBindings1(program->layoutBindings);
2219  vector<VkDescriptorSetLayoutBinding> layoutBindings2(program->layoutBindings);
2220 
2221  // ubos, samplers
2222  auto samplerIdx = 0;
2223  auto uboIdx = 0;
2224  for (auto shader: program->shaders) {
2225  if (shader->uboBindingIdx != -1) {
2226  layoutBindings1[uboIdx++] = {
2227  .binding = static_cast<uint32_t>(shader->uboBindingIdx),
2228  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
2229  .descriptorCount = 1,
2230  .stageFlags = static_cast<VkShaderStageFlags>(shader->type),
2231  .pImmutableSamplers = nullptr
2232  };
2233  }
2234  // sampler2D + samplerCube
2235  for (auto uniform: shader->samplerUniformList) {
2236  layoutBindings2[samplerIdx++] = {
2237  .binding = static_cast<uint32_t>(uniform->position),
2238  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2239  .descriptorCount = 1,
2240  .stageFlags = static_cast<VkShaderStageFlags>(shader->type),
2241  .pImmutableSamplers = nullptr
2242  };
2243  }
2244  }
2245 
2246  {
2247  const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
2248  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2249  .pNext = nullptr,
2250  .flags = 0,
2251  .bindingCount = static_cast<uint32_t>(uboIdx),
2252  .pBindings = layoutBindings1.data(),
2253  };
2254  err = vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &program->uboDescriptorSetLayout);
2255  assert(!err);
2256  }
2257  {
2258  const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
2259  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2260  .pNext = nullptr,
2261  .flags = 0,
2262  .bindingCount = static_cast<uint32_t>(samplerIdx),
2263  .pBindings = layoutBindings2.data(),
2264  };
2265  err = vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &program->texturesDescriptorSetLayout);
2266  assert(!err);
2267  }
2268 
2269  //
2270  array<VkDescriptorSetLayout, 2> descriptorSetLayouts { program->uboDescriptorSetLayout, program->texturesDescriptorSetLayout };
2271  const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
2272  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2273  .pNext = nullptr,
2274  .flags = 0,
2275  .setLayoutCount = descriptorSetLayouts.size(),
2276  .pSetLayouts = descriptorSetLayouts.data()
2277  };
2278 
2279  //
2280  for (auto i = 0; i < DRAW_COMMANDBUFFER_MAX; i++) {
2281  array<VkDescriptorSetLayout, DESC_MAX_UNCACHED> descriptorSetLayouts1;
2282  descriptorSetLayouts1.fill(program->uboDescriptorSetLayout);
2283  //
2284  VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
2285  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2286  .pNext = nullptr,
2287  .descriptorPool = descriptorPool1,
2288  .descriptorSetCount = DESC_MAX_UNCACHED,
2289  .pSetLayouts = descriptorSetLayouts1.data()
2290  };
2291  for (auto& context: contexts) {
2292  err = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, program->contexts[context.idx].commandBuffers[i].uboDescriptorSets.data());
2293  assert(!err);
2294  }
2295  }
2296 
2297  //
2298  if (program->type == PROGRAM_OBJECTS || PROGRAM_GUI) {
2299  array<VkDescriptorSetLayout, DESC_MAX_CACHED> descriptorSetLayouts2;
2300  descriptorSetLayouts2.fill(program->texturesDescriptorSetLayout);
2301  //
2302  VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
2303  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2304  .pNext = nullptr,
2305  .descriptorPool = descriptorPool2,
2306  .descriptorSetCount = DESC_MAX_CACHED,
2307  .pSetLayouts = descriptorSetLayouts2.data()
2308  };
2309  for (auto& context: contexts) {
2310  err = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, program->contexts[context.idx].descriptorSets2.data());
2311  assert(!err);
2312  }
2313  }
2314 
2315  //
2316  for (auto i = 0; i < DRAW_COMMANDBUFFER_MAX; i++) {
2317  array<VkDescriptorSetLayout, DESC_MAX_UNCACHED> descriptorSetLayouts2;
2318  descriptorSetLayouts2.fill(program->texturesDescriptorSetLayout);
2319  //
2320  VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
2321  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2322  .pNext = nullptr,
2323  .descriptorPool = descriptorPool2,
2324  .descriptorSetCount = DESC_MAX_UNCACHED,
2325  .pSetLayouts = descriptorSetLayouts2.data()
2326  };
2327  for (auto& context: contexts) {
2328  err = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, program->contexts[context.idx].commandBuffers[i].texturesDescriptorSetsUncached.data());
2329  assert(!err);
2330  }
2331  }
2332 
2333  //
2334  err = vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &program->pipelineLayout);
2335  assert(!err);
2336 }
2337 
2339  auto& currentContext = contexts[contextIdx];
2340 
2341  //
2342  auto framebufferPipelines = getFramebufferPipelines(framebufferPipelinesId);
2343  if (framebufferPipelines == nullptr) {
2344  framebufferPipelines = createFramebufferPipelines(framebufferPipelinesId);
2345  }
2346 
2347  //
2348  VkRenderPass usedRenderPass = renderPass;
2349  auto haveDepthBuffer = true;
2350  auto haveColorBuffer = true;
2351  auto haveGeometryBuffer = false;
2352  if (boundFrameBufferId != ID_NONE) {
2353  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
2354  if (frameBuffer != nullptr) {
2355  haveDepthBuffer = frameBuffer->depthTextureId != ID_NONE;
2356  haveColorBuffer = frameBuffer->colorTextureId != ID_NONE;
2357  haveGeometryBuffer = frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER;
2358  usedRenderPass = frameBuffer->renderPass;
2359  } else {
2360  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer with id: " + to_string(boundFrameBufferId) + " not found!");
2361  }
2362  }
2363 
2364  //
2365  VkResult err;
2366 
2367  //
2368  VkGraphicsPipelineCreateInfo pipeline {};
2369 
2370  // create pipepine
2371  VkPipelineCacheCreateInfo pipelineCacheCreateInfo {};
2372  VkPipelineCache pipelineCache = VK_NULL_HANDLE;
2373 
2374  VkPipelineVertexInputStateCreateInfo vi {};
2375  VkPipelineInputAssemblyStateCreateInfo ia {};
2376  VkPipelineRasterizationStateCreateInfo rs {};
2377  VkPipelineColorBlendStateCreateInfo cb {};
2378  VkPipelineDepthStencilStateCreateInfo ds {};
2379  VkPipelineViewportStateCreateInfo vp {};
2380  VkPipelineMultisampleStateCreateInfo ms {};
2381 
2382  createRasterizationStateCreateInfo(contextIdx, rs);
2384 
2385  array<VkPipelineShaderStageCreateInfo, 2> shaderStages {};
2386 
2387  // shader stages
2388  auto shaderIdx = 0;
2389  for (auto shader: program->shaders) {
2390  shaderStages[shaderIdx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2391  shaderStages[shaderIdx].stage = shader->type;
2392  shaderStages[shaderIdx].module = shader->module;
2393  shaderStages[shaderIdx].pName = "main";
2394  shaderIdx++;
2395  }
2396 
2397  pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
2398  pipeline.stageCount = shaderIdx;
2399  pipeline.layout = program->pipelineLayout;
2400 
2401  ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
2402  ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
2403 
2404  array<VkPipelineColorBlendAttachmentState, 8> bas;
2405  if (haveColorBuffer == true) {
2407  } else
2408  if (haveGeometryBuffer == true) {
2409  for (auto i = 0; i < 8; i++) {
2411  }
2412  }
2413 
2414  cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
2415  cb.logicOpEnable = VK_FALSE;
2416  cb.attachmentCount = haveColorBuffer == true?1:(haveGeometryBuffer == true?8:0);
2417  cb.pAttachments = haveColorBuffer == true || haveGeometryBuffer == true?bas.data():nullptr;
2418 
2419  vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
2420  vp.viewportCount = 1;
2421  vp.pViewports = &viewport;
2422  vp.scissorCount = 1;
2423  vp.pScissors = &scissor;
2424 
2425  ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
2426  ms.pSampleMask = nullptr;
2427  ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
2428 
2429  array<VkVertexInputBindingDescription, 4> vb {};
2430  array<VkVertexInputAttributeDescription, 4> va {};
2431 
2432  // vertices
2433  vb[0].binding = 0;
2434  vb[0].stride = sizeof(float) * 2;
2435  vb[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2436  va[0].binding = 0;
2437  va[0].location = 0;
2438  va[0].format = VK_FORMAT_R32G32_SFLOAT;
2439  va[0].offset = 0;
2440 
2441  // solid colors
2442  vb[1].binding = 1;
2443  vb[1].stride = sizeof(float) * 1;
2444  vb[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2445  va[1].binding = 1;
2446  va[1].location = 1;
2447  va[1].format = VK_FORMAT_R32_SFLOAT;
2448  va[1].offset = 0;
2449 
2450  // texture coordinates
2451  vb[2].binding = 2;
2452  vb[2].stride = sizeof(float) * 2;
2453  vb[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2454  va[2].binding = 2;
2455  va[2].location = 2;
2456  va[2].format = VK_FORMAT_R32G32_SFLOAT;
2457  va[2].offset = 0;
2458 
2459  // colors
2460  vb[3].binding = 3;
2461  vb[3].stride = sizeof(float) * 4;
2462  vb[3].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2463  va[3].binding = 3;
2464  va[3].location = 3;
2465  va[3].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2466  va[3].offset = 0;
2467 
2468  //
2469  vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
2470  vi.pNext = nullptr;
2471  vi.vertexBindingDescriptionCount = vb.size();
2472  vi.pVertexBindingDescriptions = vb.data();
2473  vi.vertexAttributeDescriptionCount = va.size();
2474  vi.pVertexAttributeDescriptions = va.data();
2475 
2476  pipeline.pVertexInputState = &vi;
2477  pipeline.pInputAssemblyState = &ia;
2478  pipeline.pRasterizationState = &rs;
2479  pipeline.pColorBlendState = haveColorBuffer == true || haveGeometryBuffer == true?&cb:nullptr;
2480  pipeline.pMultisampleState = &ms;
2481  pipeline.pViewportState = &vp;
2482  pipeline.pDepthStencilState = haveDepthBuffer == true?&ds:nullptr;
2483  pipeline.pStages = shaderStages.data();
2484  pipeline.renderPass = usedRenderPass;
2485  pipeline.pDynamicState = nullptr;
2486 
2487  pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
2488  err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
2489  assert(!err);
2490 
2491  err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipeline, nullptr, &framebufferPipelines->pipelines[currentContext.pipelineIdx]);
2492  assert(!err);
2493 
2494  //
2495  vkDestroyPipelineCache(device, pipelineCache, nullptr);
2496 }
2497 
2498 inline void VKRenderer::setupGUIRenderingPipeline(int contextIdx, program_type* program) {
2499  auto& currentContext = contexts[contextIdx];
2500  if (currentContext.pipelineIdx == ID_NONE || currentContext.pipeline == VK_NULL_HANDLE) {
2501  if (currentContext.pipelineIdx == ID_NONE) currentContext.pipelineIdx = createPipelineIndex(program, contextIdx);
2503  auto pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2504  if (pipeline == VK_NULL_HANDLE) {
2505  createGUIRenderingPipeline(contextIdx, program);
2506  pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2507  }
2509  //
2510  auto& commandBuffer = currentContext.commandBuffers[currentContext.currentCommandBuffer];
2511  vkCmdBindPipeline(commandBuffer.drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
2512  currentContext.pipeline = pipeline;
2513  }
2514 }
2515 
2517  auto& currentContext = contexts[contextIdx];
2518 
2519  //
2520  auto framebufferPipelines = getFramebufferPipelines(framebufferPipelinesId);
2521  if (framebufferPipelines == nullptr) {
2522  framebufferPipelines = createFramebufferPipelines(framebufferPipelinesId);
2523  }
2524 
2525  //
2526  VkRenderPass usedRenderPass = renderPass;
2527  auto haveDepthBuffer = true;
2528  auto haveColorBuffer = true;
2529  auto haveGeometryBuffer = false;
2530  if (boundFrameBufferId != ID_NONE) {
2531  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
2532  if (frameBuffer != nullptr) {
2533  haveDepthBuffer = frameBuffer->depthTextureId != ID_NONE;
2534  haveColorBuffer = frameBuffer->colorTextureId != ID_NONE;
2535  haveGeometryBuffer = frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER;
2536  usedRenderPass = frameBuffer->renderPass;
2537  } else {
2538  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer with id: " + to_string(boundFrameBufferId) + " not found!");
2539  }
2540  }
2541 
2542  //
2543  VkResult err;
2544 
2545  //
2546  VkGraphicsPipelineCreateInfo pipeline {};
2547 
2548  // create pipepine
2549  VkPipelineCacheCreateInfo pipelineCacheCreateInfo {};
2550  VkPipelineCache pipelineCache = VK_NULL_HANDLE;
2551 
2552  VkPipelineVertexInputStateCreateInfo vi {};
2553  VkPipelineInputAssemblyStateCreateInfo ia {};
2554  VkPipelineRasterizationStateCreateInfo rs {};
2555  VkPipelineColorBlendStateCreateInfo cb {};
2556  VkPipelineDepthStencilStateCreateInfo ds {};
2557  VkPipelineViewportStateCreateInfo vp {};
2558  VkPipelineMultisampleStateCreateInfo ms {};
2559 
2560  createRasterizationStateCreateInfo(contextIdx, rs);
2562 
2563  array<VkPipelineShaderStageCreateInfo, 2> shaderStages {};
2564 
2565  // shader stages
2566  auto shaderIdx = 0;
2567  for (auto shader: program->shaders) {
2568  shaderStages[shaderIdx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2569  shaderStages[shaderIdx].stage = shader->type;
2570  shaderStages[shaderIdx].module = shader->module;
2571  shaderStages[shaderIdx].pName = "main";
2572  shaderIdx++;
2573  }
2574 
2575  pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
2576  pipeline.stageCount = shaderIdx;
2577  pipeline.layout = program->pipelineLayout;
2578 
2579  ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
2580  ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
2581 
2582  array<VkPipelineColorBlendAttachmentState, 8> bas;
2583  if (haveColorBuffer == true) {
2585  } else
2586  if (haveGeometryBuffer == true) {
2587  for (auto i = 0; i < 8; i++) {
2589  }
2590  }
2591 
2592  cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
2593  cb.logicOpEnable = VK_FALSE;
2594  cb.attachmentCount = haveColorBuffer == true?1:(haveGeometryBuffer == true?8:0);
2595  cb.pAttachments = haveColorBuffer == true || haveGeometryBuffer == true?bas.data():nullptr;
2596 
2597  vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
2598  vp.viewportCount = 1;
2599  vp.pViewports = &viewport;
2600  vp.scissorCount = 1;
2601  vp.pScissors = &scissor;
2602 
2603  ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
2604  ms.pSampleMask = nullptr;
2605  ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
2606 
2607  array<VkVertexInputBindingDescription, 10> vb {};
2608  array<VkVertexInputAttributeDescription, 13> va {};
2609 
2610  // vertices
2611  vb[0].binding = 0;
2612  vb[0].stride = sizeof(float) * 3;
2613  vb[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2614  va[0].binding = 0;
2615  va[0].location = 0;
2616  va[0].format = VK_FORMAT_R32G32B32_SFLOAT;
2617  va[0].offset = 0;
2618 
2619  // normals
2620  vb[1].binding = 1;
2621  vb[1].stride = sizeof(float) * 3;
2622  vb[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2623  va[1].binding = 1;
2624  va[1].location = 1;
2625  va[1].format = VK_FORMAT_R32G32B32_SFLOAT;
2626  va[1].offset = 0;
2627 
2628  // texture coordinates
2629  vb[2].binding = 2;
2630  vb[2].stride = sizeof(float) * 2;
2631  vb[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2632  va[2].binding = 2;
2633  va[2].location = 2;
2634  va[2].format = VK_FORMAT_R32G32_SFLOAT;
2635  va[2].offset = 0;
2636 
2637  // colors
2638  vb[3].binding = 3;
2639  vb[3].stride = sizeof(float) * 4;
2640  vb[3].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2641  va[3].binding = 3;
2642  va[3].location = 3;
2643  va[3].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2644  va[3].offset = 0;
2645 
2646  // tangents
2647  vb[4].binding = 4;
2648  vb[4].stride = sizeof(float) * 3;
2649  vb[4].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2650  va[4].binding = 4;
2651  va[4].location = 4;
2652  va[4].format = VK_FORMAT_R32G32B32_SFLOAT;
2653  va[4].offset = 0;
2654 
2655  // bitangents
2656  vb[5].binding = 5;
2657  vb[5].stride = sizeof(float) * 3;
2658  vb[5].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2659  va[5].binding = 5;
2660  va[5].location = 5;
2661  va[5].format = VK_FORMAT_R32G32B32_SFLOAT;
2662  va[5].offset = 0;
2663 
2664  // model matrices 1
2665  vb[6].binding = 6;
2666  vb[6].stride = sizeof(float) * 4 * 4;
2667  vb[6].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
2668  va[6].binding = 6;
2669  va[6].location = 6;
2670  va[6].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2671  va[6].offset = sizeof(float) * 4 * 0;
2672 
2673  // model matrices 2
2674  va[7].binding = 6;
2675  va[7].location = 7;
2676  va[7].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2677  va[7].offset = sizeof(float) * 4 * 1;
2678 
2679  // model matrices 3
2680  va[8].binding = 6;
2681  va[8].location = 8;
2682  va[8].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2683  va[8].offset = sizeof(float) * 4 * 2;
2684 
2685  // model matrices 4
2686  va[9].binding = 6;
2687  va[9].location = 9;
2688  va[9].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2689  va[9].offset = sizeof(float) * 4 * 3;
2690 
2691  // effect color mul
2692  vb[7].binding = 7;
2693  vb[7].stride = sizeof(float) * 4;
2694  vb[7].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
2695  va[10].binding = 7;
2696  va[10].location = 10;
2697  va[10].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2698  va[10].offset = 0;
2699 
2700  // effect color add
2701  vb[8].binding = 8;
2702  vb[8].stride = sizeof(float) * 4;
2703  vb[8].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
2704  va[11].binding = 8;
2705  va[11].location = 11;
2706  va[11].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2707  va[11].offset = 0;
2708 
2709  // origins
2710  vb[9].binding = 9;
2711  vb[9].stride = sizeof(float) * 3;
2712  vb[9].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2713  va[12].binding = 9;
2714  va[12].location = 12;
2715  va[12].format = VK_FORMAT_R32G32B32_SFLOAT;
2716  va[12].offset = 0;
2717 
2718  vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
2719  vi.pNext = nullptr;
2720  vi.vertexBindingDescriptionCount = vb.size();
2721  vi.pVertexBindingDescriptions = vb.data();
2722  vi.vertexAttributeDescriptionCount = va.size();
2723  vi.pVertexAttributeDescriptions = va.data();
2724 
2725  pipeline.pVertexInputState = &vi;
2726  pipeline.pInputAssemblyState = &ia;
2727  pipeline.pRasterizationState = &rs;
2728  pipeline.pColorBlendState = haveColorBuffer == true || haveGeometryBuffer == true?&cb:nullptr;
2729  pipeline.pMultisampleState = &ms;
2730  pipeline.pViewportState = &vp;
2731  pipeline.pDepthStencilState = haveDepthBuffer == true?&ds:nullptr;
2732  pipeline.pStages = shaderStages.data();
2733  pipeline.renderPass = usedRenderPass;
2734  pipeline.pDynamicState = nullptr;
2735 
2736  pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
2737  err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
2738  assert(!err);
2739 
2740  err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipeline, nullptr, &framebufferPipelines->pipelines[currentContext.pipelineIdx]);
2741  assert(!err);
2742 
2743  //
2744  vkDestroyPipelineCache(device, pipelineCache, nullptr);
2745 }
2746 
2747 inline void VKRenderer::setupObjectsRenderingPipeline(int contextIdx, program_type* program) {
2748  auto& currentContext = contexts[contextIdx];
2749  if (currentContext.pipelineIdx == ID_NONE || currentContext.pipeline == VK_NULL_HANDLE) {
2750  if (currentContext.pipelineIdx == ID_NONE) currentContext.pipelineIdx = createPipelineIndex(program, contextIdx);
2752  auto pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2753  if (pipeline == VK_NULL_HANDLE) {
2754  createObjectsRenderingPipeline(contextIdx, program);
2755  pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2756  }
2758  //
2759  auto& commandBuffer = currentContext.commandBuffers[currentContext.currentCommandBuffer];
2760  vkCmdBindPipeline(commandBuffer.drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
2761  currentContext.pipeline = pipeline;
2762  }
2763 }
2764 
2766  auto& currentContext = contexts[contextIdx];
2767 
2768  //
2769  auto framebufferPipelines = getFramebufferPipelines(framebufferPipelinesId);
2770  if (framebufferPipelines == nullptr) {
2771  framebufferPipelines = createFramebufferPipelines(framebufferPipelinesId);
2772  }
2773 
2774  //
2775  VkRenderPass usedRenderPass = renderPass;
2776  auto haveDepthBuffer = true;
2777  auto haveColorBuffer = true;
2778  auto haveGeometryBuffer = false;
2779  if (boundFrameBufferId != ID_NONE) {
2780  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
2781  if (frameBuffer != nullptr) {
2782  haveDepthBuffer = frameBuffer->depthTextureId != ID_NONE;
2783  haveColorBuffer = frameBuffer->colorTextureId != ID_NONE;
2784  haveGeometryBuffer = frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER;
2785  usedRenderPass = frameBuffer->renderPass;
2786  }
2787  }
2788 
2789  //
2790  VkResult err;
2791 
2792  //
2793  VkGraphicsPipelineCreateInfo pipeline {};
2794 
2795  // Stages
2796  array<VkPipelineShaderStageCreateInfo, 2> shaderStages {};
2797 
2798  // shader stages
2799  auto shaderIdx = 0;
2800  for (auto shader: program->shaders) {
2801  shaderStages[shaderIdx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2802  shaderStages[shaderIdx].stage = shader->type;
2803  shaderStages[shaderIdx].module = shader->module;
2804  shaderStages[shaderIdx].pName = "main";
2805  shaderIdx++;
2806  }
2807 
2808  // create pipepine
2809  VkPipelineCacheCreateInfo pipelineCacheCreateInfo {};
2810  VkPipelineCache pipelineCache = VK_NULL_HANDLE;
2811 
2812  VkPipelineVertexInputStateCreateInfo vi {};
2813  VkPipelineInputAssemblyStateCreateInfo ia {};
2814  VkPipelineRasterizationStateCreateInfo rs {};
2815  VkPipelineColorBlendStateCreateInfo cb {};
2816  VkPipelineDepthStencilStateCreateInfo ds {};
2817  VkPipelineViewportStateCreateInfo vp {};
2818  VkPipelineMultisampleStateCreateInfo ms {};
2819 
2820  createRasterizationStateCreateInfo(contextIdx, rs);
2822 
2823  pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
2824  pipeline.stageCount = shaderIdx;
2825  pipeline.layout = program->pipelineLayout;
2826 
2827  ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
2828  ia.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
2829 
2830  array<VkPipelineColorBlendAttachmentState, 8> bas;
2831  if (haveColorBuffer == true) {
2833  } else
2834  if (haveGeometryBuffer == true) {
2835  for (auto i = 0; i < 8; i++) {
2837  }
2838  }
2839  cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
2840  cb.logicOpEnable = VK_FALSE;
2841  cb.attachmentCount = haveColorBuffer == true?1:(haveGeometryBuffer == true?8:0);
2842  cb.pAttachments = haveColorBuffer == true || haveGeometryBuffer == true?bas.data():nullptr;
2843 
2844  vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
2845  vp.viewportCount = 1;
2846  vp.pViewports = &viewport;
2847  vp.scissorCount = 1;
2848  vp.pScissors = &scissor;
2849 
2850  ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
2851  ms.pSampleMask = nullptr;
2852  ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
2853 
2854  array<VkVertexInputBindingDescription, 9> vb {};
2855  array<VkVertexInputAttributeDescription, 9> va {};
2856 
2857  // vertices
2858  vb[0].binding = 0;
2859  vb[0].stride = sizeof(float) * 3;
2860  vb[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2861  va[0].binding = 0;
2862  va[0].location = 0;
2863  va[0].format = VK_FORMAT_R32G32B32_SFLOAT;
2864  va[0].offset = 0;
2865 
2866  // texture + sprite indices
2867  vb[1].binding = 1;
2868  vb[1].stride = sizeof(uint16_t) * 2;
2869  vb[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2870  va[1].binding = 1;
2871  va[1].location = 1;
2872  va[1].format = VK_FORMAT_R16G16_UINT;
2873  va[1].offset = 0;
2874 
2875  // not in use
2876  vb[2].binding = 2;
2877  vb[2].stride = sizeof(float);
2878  vb[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2879  va[2].binding = 2;
2880  va[2].location = 2;
2881  va[2].format = VK_FORMAT_R32_SFLOAT;
2882  va[2].offset = 0;
2883 
2884  // colors
2885  vb[3].binding = 3;
2886  vb[3].stride = sizeof(float) * 4;
2887  vb[3].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2888  va[3].binding = 3;
2889  va[3].location = 3;
2890  va[3].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2891  va[3].offset = 0;
2892 
2893  // not in use
2894  vb[4].binding = 4;
2895  vb[4].stride = sizeof(float);
2896  vb[4].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2897  va[4].binding = 4;
2898  va[4].location = 4;
2899  va[4].format = VK_FORMAT_R32_SFLOAT;
2900  va[4].offset = 0;
2901 
2902  // point size
2903  vb[5].binding = 5;
2904  vb[5].stride = sizeof(float);
2905  vb[5].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2906  va[5].binding = 5;
2907  va[5].location = 5;
2908  va[5].format = VK_FORMAT_R32_SFLOAT;
2909  va[5].offset = 0;
2910 
2911  // sprite sheet dimension
2912  vb[6].binding = 6;
2913  vb[6].stride = sizeof(uint16_t) * 2;
2914  vb[6].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2915  va[6].binding = 6;
2916  va[6].location = 6;
2917  va[6].format = VK_FORMAT_R16G16_UINT;
2918  va[6].offset = 0;
2919 
2920  // effect color mul
2921  vb[7].binding = 7;
2922  vb[7].stride = sizeof(float) * 4;
2923  vb[7].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2924  va[7].binding = 7;
2925  va[7].location = 10;
2926  va[7].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2927  va[7].offset = 0;
2928 
2929  // effect color add
2930  vb[8].binding = 8;
2931  vb[8].stride = sizeof(float) * 4;
2932  vb[8].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
2933  va[8].binding = 8;
2934  va[8].location = 11;
2935  va[8].format = VK_FORMAT_R32G32B32A32_SFLOAT;
2936  va[8].offset = 0;
2937 
2938  //
2939  vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
2940  vi.pNext = nullptr;
2941  vi.vertexBindingDescriptionCount = vb.size();
2942  vi.pVertexBindingDescriptions = vb.data();
2943  vi.vertexAttributeDescriptionCount = va.size();
2944  vi.pVertexAttributeDescriptions = va.data();
2945 
2946  pipeline.pVertexInputState = &vi;
2947  pipeline.pInputAssemblyState = &ia;
2948  pipeline.pRasterizationState = &rs;
2949  pipeline.pColorBlendState = haveColorBuffer == true || haveGeometryBuffer == true?&cb:nullptr;
2950  pipeline.pMultisampleState = &ms;
2951  pipeline.pViewportState = &vp;
2952  pipeline.pDepthStencilState = haveDepthBuffer == true?&ds:nullptr;
2953  pipeline.pStages = shaderStages.data();
2954  pipeline.renderPass = usedRenderPass;
2955  pipeline.pDynamicState = nullptr;
2956 
2957  pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
2958  err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
2959  assert(!err);
2960 
2961  err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipeline, nullptr, &framebufferPipelines->pipelines[currentContext.pipelineIdx]);
2962  assert(!err);
2963 
2964  //
2965  vkDestroyPipelineCache(device, pipelineCache, nullptr);
2966 }
2967 
2968 inline void VKRenderer::setupPointsRenderingPipeline(int contextIdx, program_type* program) {
2969  auto& currentContext = contexts[contextIdx];
2970  if (currentContext.pipelineIdx == ID_NONE || currentContext.pipeline == VK_NULL_HANDLE) {
2971  if (currentContext.pipelineIdx == ID_NONE) currentContext.pipelineIdx = createPipelineIndex(program, contextIdx);
2973  auto pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2974  if (pipeline == VK_NULL_HANDLE) {
2975  createPointsRenderingPipeline(contextIdx, program);
2976  pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
2977  }
2979 
2980  //
2981  auto& commandBuffer = currentContext.commandBuffers[currentContext.currentCommandBuffer];
2982  vkCmdBindPipeline(commandBuffer.drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
2983  currentContext.pipeline = pipeline;
2984  }
2985 }
2986 
2988  auto& currentContext = contexts[contextIdx];
2989 
2990  //
2991  auto framebufferPipelines = getFramebufferPipelines(framebufferPipelinesId);
2992  if (framebufferPipelines == nullptr) {
2993  framebufferPipelines = createFramebufferPipelines(framebufferPipelinesId);
2994  }
2995 
2996  //
2997  VkRenderPass usedRenderPass = renderPass;
2998  auto haveDepthBuffer = true;
2999  auto haveColorBuffer = true;
3000  auto haveGeometryBuffer = false;
3001  if (boundFrameBufferId != ID_NONE) {
3002  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
3003  if (frameBuffer != nullptr) {
3004  haveDepthBuffer = frameBuffer->depthTextureId != ID_NONE;
3005  haveColorBuffer = frameBuffer->colorTextureId != ID_NONE;
3006  haveGeometryBuffer = frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER;
3007  usedRenderPass = frameBuffer->renderPass;
3008  }
3009  }
3010 
3011  //
3012  VkResult err;
3013 
3014  //
3015  VkGraphicsPipelineCreateInfo pipeline {};
3016  VkPipelineCache pipelineCache = VK_NULL_HANDLE;
3017 
3018  // Stages
3019  array<VkPipelineShaderStageCreateInfo, 2> shaderStages {};
3020 
3021  // shader stages
3022  auto shaderIdx = 0;
3023  for (auto shader: program->shaders) {
3024  shaderStages[shaderIdx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
3025  shaderStages[shaderIdx].stage = shader->type;
3026  shaderStages[shaderIdx].module = shader->module;
3027  shaderStages[shaderIdx].pName = "main";
3028  shaderIdx++;
3029  }
3030 
3031  // create pipepine
3032  VkPipelineCacheCreateInfo pipelineCacheCreateInfo {};
3033 
3034  VkPipelineVertexInputStateCreateInfo vi {};
3035  VkPipelineInputAssemblyStateCreateInfo ia {};
3036  VkPipelineRasterizationStateCreateInfo rs {};
3037  VkPipelineColorBlendStateCreateInfo cb {};
3038  VkPipelineDepthStencilStateCreateInfo ds {};
3039  VkPipelineViewportStateCreateInfo vp {};
3040  VkPipelineMultisampleStateCreateInfo ms {};
3041  array<VkDynamicState, 1> dse {};
3042  VkPipelineDynamicStateCreateInfo dsc {};
3043 
3044  createRasterizationStateCreateInfo(contextIdx, rs);
3046 
3047  dse[dsc.dynamicStateCount++] = VK_DYNAMIC_STATE_LINE_WIDTH;
3048  dsc.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
3049  dsc.pDynamicStates = dse.data();
3050 
3051  pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
3052  pipeline.stageCount = shaderIdx;
3053  pipeline.layout = program->pipelineLayout;
3054 
3055  ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
3056  ia.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
3057 
3058  array<VkPipelineColorBlendAttachmentState, 8> bas;
3059  if (haveColorBuffer == true) {
3061  } else
3062  if (haveGeometryBuffer == true) {
3063  for (auto i = 0; i < 8; i++) {
3065  }
3066  }
3067 
3068  cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
3069  cb.logicOpEnable = VK_FALSE;
3070  cb.attachmentCount = haveColorBuffer == true?1:(haveGeometryBuffer == true?8:0);
3071  cb.pAttachments = haveColorBuffer == true || haveGeometryBuffer == true?bas.data():nullptr;
3072 
3073  vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
3074  vp.viewportCount = 1;
3075  vp.pViewports = &viewport;
3076  vp.scissorCount = 1;
3077  vp.pScissors = &scissor;
3078 
3079  ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
3080  ms.pSampleMask = nullptr;
3081  ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
3082 
3083  array<VkVertexInputBindingDescription, 4> vb {};
3084  array<VkVertexInputAttributeDescription, 4> va {};
3085 
3086  // vertices
3087  vb[0].binding = 0;
3088  vb[0].stride = sizeof(float) * 3;
3089  vb[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
3090  va[0].binding = 0;
3091  va[0].location = 0;
3092  va[0].format = VK_FORMAT_R32G32B32_SFLOAT;
3093  va[0].offset = 0;
3094 
3095  // normals
3096  vb[1].binding = 1;
3097  vb[1].stride = sizeof(float) * 3;
3098  vb[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
3099  va[1].binding = 1;
3100  va[1].location = 1;
3101  va[1].format = VK_FORMAT_R32G32B32_SFLOAT;
3102  va[1].offset = 0;
3103 
3104  // texture coordinates
3105  vb[2].binding = 2;
3106  vb[2].stride = sizeof(float) * 2;
3107  vb[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
3108  va[2].binding = 2;
3109  va[2].location = 2;
3110  va[2].format = VK_FORMAT_R32G32_SFLOAT;
3111  va[2].offset = 0;
3112 
3113  // colors
3114  vb[3].binding = 3;
3115  vb[3].stride = sizeof(float) * 4;
3116  vb[3].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
3117  va[3].binding = 3;
3118  va[3].location = 3;
3119  va[3].format = VK_FORMAT_R32G32B32A32_SFLOAT;
3120  va[3].offset = 0;
3121 
3122  vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
3123  vi.pNext = nullptr;
3124  vi.vertexBindingDescriptionCount = vb.size();
3125  vi.pVertexBindingDescriptions = vb.data();
3126  vi.vertexAttributeDescriptionCount = va.size();
3127  vi.pVertexAttributeDescriptions = va.data();
3128 
3129  pipeline.pVertexInputState = &vi;
3130  pipeline.pInputAssemblyState = &ia;
3131  pipeline.pRasterizationState = &rs;
3132  pipeline.pColorBlendState = haveColorBuffer == true || haveGeometryBuffer == true?&cb:nullptr;
3133  pipeline.pMultisampleState = &ms;
3134  pipeline.pViewportState = &vp;
3135  pipeline.pDepthStencilState = haveDepthBuffer == true?&ds:nullptr;
3136  pipeline.pStages = shaderStages.data();
3137  pipeline.renderPass = usedRenderPass;
3138  pipeline.pDynamicState = &dsc;
3139 
3140  pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
3141  err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
3142  assert(!err);
3143 
3144  err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipeline, nullptr, &framebufferPipelines->pipelines[currentContext.pipelineIdx]);
3145  assert(!err);
3146 
3147  //
3148  vkDestroyPipelineCache(device, pipelineCache, nullptr);
3149 }
3150 
3151 inline void VKRenderer::setupLinesRenderingPipeline(int contextIdx, program_type* program) {
3152  auto& currentContext = contexts[contextIdx];
3153  if (currentContext.pipelineIdx == ID_NONE || currentContext.pipeline == VK_NULL_HANDLE) {
3154  if (currentContext.pipelineIdx == ID_NONE) currentContext.pipelineIdx = createPipelineIndex(program, contextIdx);
3156  auto pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
3157  if (pipeline == VK_NULL_HANDLE) {
3158  createLinesRenderingPipeline(contextIdx, program);
3159  pipeline = getPipelineInternal(contextIdx, program, framebufferPipelinesId, currentContext.pipelineIdx);
3160  }
3162 
3163  //
3164  auto& commandBuffer = currentContext.commandBuffers[currentContext.currentCommandBuffer];
3165  vkCmdBindPipeline(commandBuffer.drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
3166  currentContext.pipeline = pipeline;
3167  }
3168 }
3169 
3171  //
3173 
3174  //
3175  auto framebufferPipelines = getFramebufferPipelines(ID_NONE);
3176  if (framebufferPipelines == nullptr) {
3177  framebufferPipelines = createFramebufferPipelines(ID_NONE);
3178  }
3179 
3180  //
3181  VkResult err;
3182 
3183  //
3184  vector<VkDescriptorSetLayoutBinding> layoutBindings1(program->layoutBindings);
3185 
3186  // Stages
3187  vector<VkPipelineShaderStageCreateInfo> shaderStages(program->shaders.size());
3188 
3189  auto shaderIdx = 0;
3190  for (auto shader: program->shaders) {
3191  shaderStages[shaderIdx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
3192  shaderStages[shaderIdx].stage = shader->type;
3193  shaderStages[shaderIdx].module = shader->module;
3194  shaderStages[shaderIdx].pName = "main";
3195 
3196  for (int i = 0; i <= shader->maxBindings; i++) {
3197  layoutBindings1[i] = {
3198  .binding = static_cast<uint32_t>(i),
3199  .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
3200  .descriptorCount = 1,
3201  .stageFlags = static_cast<VkShaderStageFlags>(shader->type),
3202  .pImmutableSamplers = nullptr
3203  };
3204  }
3205 
3206  if (shader->uboBindingIdx != -1) {
3207  layoutBindings1[shader->uboBindingIdx] = {
3208  .binding = static_cast<uint32_t>(shader->uboBindingIdx),
3209  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
3210  .descriptorCount = 1,
3211  .stageFlags = static_cast<VkShaderStageFlags>(shader->type),
3212  .pImmutableSamplers = nullptr
3213  };
3214  }
3215  shaderIdx++;
3216  }
3217  const VkDescriptorSetLayoutCreateInfo descriptorSetlayoutCreateInfo = {
3218  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
3219  .pNext = nullptr,
3220  .flags = 0,
3221  .bindingCount = program->layoutBindings,
3222  .pBindings = layoutBindings1.data(),
3223  };
3224 
3225  err = vkCreateDescriptorSetLayout(device, &descriptorSetlayoutCreateInfo, nullptr, &program->uboDescriptorSetLayout);
3226  assert(!err);
3227 
3228  //
3229  const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
3230  .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
3231  .pNext = nullptr,
3232  .flags = 0,
3233  .setLayoutCount = 1,
3234  .pSetLayouts = &program->uboDescriptorSetLayout
3235  };
3236 
3237  //
3238  for (auto i = 0; i < DRAW_COMMANDBUFFER_MAX; i++) {
3239  array<VkDescriptorSetLayout, DESC_MAX_UNCACHED> descriptorSetLayouts1;
3240  descriptorSetLayouts1.fill(program->uboDescriptorSetLayout);
3241  //
3242  VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
3243  .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
3244  .pNext = nullptr,
3245  .descriptorPool = descriptorPool1,
3246  .descriptorSetCount = DESC_MAX_UNCACHED,
3247  .pSetLayouts = descriptorSetLayouts1.data()
3248  };
3249  for (auto& context: contexts) {
3250  err = vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, program->contexts[context.idx].commandBuffers[i].uboDescriptorSets.data());
3251  assert(!err);
3252  }
3253  }
3254 
3255  //
3256  err = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &program->pipelineLayout);
3257  assert(!err);
3258 
3259  // create pipepine
3260  VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {
3261  .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
3262  .pNext = nullptr,
3263  .flags = 0,
3264  .initialDataSize = 0,
3265  .pInitialData = nullptr
3266  };
3267  VkPipelineCache pipelineCache = VK_NULL_HANDLE;
3268 
3269  err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
3270  assert(!err);
3271 
3272  // create pipepine
3273  VkComputePipelineCreateInfo pipeline = {
3274  .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
3275  .pNext = nullptr,
3276  .flags = 0,
3277  .stage = shaderStages[0],
3278  .layout = program->pipelineLayout,
3279  .basePipelineHandle = nullptr,
3280  .basePipelineIndex = 0
3281  };
3282 
3283  //
3284  err = vkCreateComputePipelines(device, pipelineCache, 1, &pipeline, nullptr, &framebufferPipelines->pipelines[ID_NONE]);
3285  assert(!err);
3286 
3287  //
3288  vkDestroyPipelineCache(device, pipelineCache, nullptr);
3289 
3290  //
3292 }
3293 
3294 inline void VKRenderer::setupSkinningComputingPipeline(int contextIdx, program_type* program) {
3295  auto& currentContext = contexts[contextIdx];
3296  if (currentContext.pipelineIdx == ID_NONE || currentContext.pipeline == VK_NULL_HANDLE) {
3298  auto pipeline = getPipelineInternal(contextIdx, program, ID_NONE, ID_NONE);
3300 
3301  //
3302  vkCmdBindPipeline(currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
3303  currentContext.pipeline = pipeline;
3304  }
3305 }
3306 
3307 void VKRenderer::useProgram(int contextIdx, int32_t programId)
3308 {
3309  auto& currentContext = contexts[contextIdx];
3310 
3311  //
3312  if (currentContext.program != nullptr && currentContext.program->id == programId) return;
3313 
3314  //
3315  unsetPipeline(currentContext.idx);
3316 
3317  //
3318  currentContext.program = nullptr;
3319 
3320  //
3321  if (programId == ID_NONE) return;
3322 
3323  //
3324  if (programId < ID_NONE || programId >= programVector.size()) {
3325  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): program does not exist: " + to_string(programId));
3326  return;
3327  }
3328 
3329  //
3330  auto program = programVector[programId];
3331  currentContext.program = program;
3332 }
3333 
3334 int32_t VKRenderer::createProgram(int type)
3335 {
3336  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
3337  if (programVector.size() >= PROGRAMS_MAX) {
3338  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not create program, maximum is " + to_string(PROGRAMS_MAX));
3339  return ID_NONE;
3340  }
3341  auto programPtr = new program_type();
3342  auto& program = *programPtr;
3343  program.type = type;
3344  program.id = programVector.size();
3345  program.contexts.resize(Engine::getThreadCount());
3346  for (auto& programContext: program.contexts) {
3347  programContext.descriptorSets2Idx = 0;
3348  programContext.descriptorSets2.fill(VK_NULL_HANDLE);
3349  for (auto& programContextCommandBuffer: programContext.commandBuffers) {
3350  programContextCommandBuffer.uboDescriptorSetsIdx = 0;
3351  programContextCommandBuffer.texturesDescriptorSetsIdxUncached = 0;
3352  programContextCommandBuffer.uboDescriptorSets.fill(VK_NULL_HANDLE);
3353  programContextCommandBuffer.texturesDescriptorSetsUncached.fill(VK_NULL_HANDLE);
3354  }
3355  }
3356  programVector.push_back(programPtr);
3357  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): program id: " + to_string(program.id));
3358  return program.id;
3359 }
3360 
3361 void VKRenderer::attachShaderToProgram(int32_t programId, int32_t shaderId)
3362 {
3363  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
3364  auto shaderIt = shaders.find(shaderId);
3365  if (shaderIt == shaders.end()) {
3366  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): shader does not exist");
3367  return;
3368  }
3369  if (programId < 0 || programId >= programVector.size()) {
3370  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): program does not exist");
3371  return;
3372  }
3373  auto program = programVector[programId];
3374  program->shaderIds.push_back(shaderId);
3375  program->shaders.push_back(shaderIt->second);
3376 }
3377 
3378 bool VKRenderer::linkProgram(int32_t programId)
3379 {
3380  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(programId));
3381  if (programId < 0 || programId >= programVector.size()) {
3382  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): program does not exist");
3383  return false;
3384  }
3385 
3386  //
3387  auto& program = *programVector[programId];
3388 
3389  //
3391 
3392  // create uniform buffers
3393  for (auto shader: program.shaders) {
3394  // do we need a uniform buffer object for this shader stage?
3395  if (shader->uboSize > 0) {
3396  shader->uniformBuffers.resize(Engine::getThreadCount());
3397  for (auto& context: contexts) {
3398  auto& uniformBuffer = shader->uniformBuffers[context.idx];
3399  uniformBuffer.size = shader->uboSize;
3400  uniformBuffer.uniformBufferData.resize(shader->uboSize);
3401  for (auto& uniformBufferBuffer: uniformBuffer.buffers) {
3402  VmaAllocationInfo allocationInfo = {};
3403  createBuffer(
3404  uniformBuffer.size,
3405  VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
3406  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
3407  uniformBufferBuffer.buffer,
3408  uniformBufferBuffer.allocation,
3409  allocationInfo
3410  );
3411  VkMemoryPropertyFlags memoryFlags;
3412  vmaGetMemoryTypeProperties(vmaAllocator, allocationInfo.memoryType, &memoryFlags);
3413  auto memoryMapped = (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
3414  if (memoryMapped == true) {
3415  void* mmData;
3416  vmaMapMemory(vmaAllocator, uniformBufferBuffer.allocation, &mmData);
3417  } else {
3418  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): Could not create memory mappable uniform buffer");
3419  }
3420  }
3421  };
3422  }
3423  }
3424 
3425  // bind samplers, set up ingoing attribute layout indices, compile shaders
3426  shader_type* shaderLast = nullptr;
3427  for (auto shader: program.shaders) {
3428  // create shader module
3429  {
3430  VkResult err;
3431  VkShaderModuleCreateInfo shaderModuleCreateInfo;
3432  shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
3433  shaderModuleCreateInfo.pNext = nullptr;
3434  shaderModuleCreateInfo.codeSize = shader->spirv.size() * sizeof(uint32_t);
3435  shaderModuleCreateInfo.pCode = shader->spirv.data();
3436  shaderModuleCreateInfo.flags = 0;
3437  err = vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &shader->module);
3438  if (err == VK_SUCCESS) {
3439  if (VERBOSE == true) {
3440  Console::println(
3441  string(
3442  string("VKRenderer::") +
3443  string(__FUNCTION__) +
3444  string("[") +
3445  to_string(shader->id) +
3446  string("]") +
3447  string(": SUCCESS")
3448  )
3449  );
3450  }
3451  } else {
3452  Console::println(
3453  string(
3454  string("VKRenderer::") +
3455  string(__FUNCTION__) +
3456  string("[") +
3457  to_string(shader->id) +
3458  string("]") +
3459  string(": FAILED")
3460  )
3461  );
3462  Console::println(shader->source);
3463  return false;
3464  }
3465  }
3466 
3467  //
3468  shaderLast = shader;
3469  }
3470 
3471  // create programs in terms of ubos and so on
3472  if (program.type == PROGRAM_GUI || program.type == PROGRAM_OBJECTS || program.type == PROGRAM_POINTS || program.type == PROGRAM_LINES) {
3473  createRenderProgram(&program);
3474  } else
3475  if (program.type == PROGRAM_COMPUTE) {
3477  } else {
3478  Console::println(
3479  string("VKRenderer::") +
3480  string(__FUNCTION__) +
3481  string("[") +
3482  to_string(programId) +
3483  string("]") +
3484  string(": unknown program: ") +
3485  to_string(program.type)
3486  );
3487  }
3488 
3489  //
3490  return true;
3491 }
3492 
3493 int32_t VKRenderer::getProgramUniformLocation(int32_t programId, const string& name)
3494 {
3495  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + name);
3496  if (programId < 0 || programId >= programVector.size()) {
3497  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): program does not exist");
3498  return -1;
3499  }
3500  auto program = programVector[programId];
3501  for (const auto& [uniformLocation, uniformName]: program->uniformLocations) {
3502  if (uniformName == name) return uniformLocation;
3503  }
3504  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): uniform not found: '" + name + "'");
3505  return -1;
3506 }
3507 
3508 inline void VKRenderer::setProgramUniformInternal(int contextIdx, int32_t uniformId, uint8_t* data, int32_t size) {
3509  auto& currentContext = contexts[contextIdx];
3510 
3511  //
3512  auto shaderIdx = 0;
3513  for (auto shader: currentContext.program->shaders) {
3514  //
3515  if (uniformId < 0 || uniformId >= shader->uniformList.size()) {
3516  Console::println(
3517  "VKRenderer::" +
3518  string(__FUNCTION__) +
3519  "(): program: uniform id out of uniform list bounds: " +
3520  to_string(currentContext.idx) + ": " +
3521  to_string(currentContext.program->id) + ": " +
3522  to_string(uniformId) + " / " +
3523  to_string(shader->uniformList.size())
3524  );
3525  Console::println(
3526  string("\t") +
3527  to_string(currentContext.idx) + ": " +
3528  to_string(currentContext.program->id) + ": " +
3529  to_string(uniformId) + " / " +
3530  currentContext.program->uniformLocations[uniformId]
3531  );
3532  continue;
3533  }
3534  auto shaderUniformPtr = uniformId != -1?shader->uniformList[uniformId]:nullptr;
3535  if (shaderUniformPtr == nullptr) {
3536  shaderIdx++;
3537  continue;
3538  }
3539  auto& shaderUniform = *shaderUniformPtr;
3540  if (shaderUniform.type == shader_type::uniform_type::TYPE_UNIFORM) {
3541  /*
3542  if (currentContext.uniformBuffers[shaderIdx] == nullptr) {
3543  Console::println(
3544  "VKRenderer::" +
3545  string(__FUNCTION__) +
3546  "(): shader: no shader uniform buffer in context: " +
3547  to_string(currentContext.idx) + ": " +
3548  to_string(currentContext.programId) + ": " +
3549  to_string(uniformId) + "; " +
3550  to_string(shaderIdx) + ": " +
3551  shaderUniformPtr->name
3552  );
3553  shaderIdx++;
3554  continue;
3555  } else
3556  if (size != shaderUniform.size) {
3557  Console::println(
3558  "VKRenderer::" +
3559  string(__FUNCTION__) +
3560  "(): program: uniform size != given size: " +
3561  to_string(currentContext.idx) + ": " +
3562  to_string(currentContext.programId) + ": " +
3563  to_string(uniformId) + "; " +
3564  to_string(shaderIdx) + "; " +
3565  to_string(currentContext.uniformBuffers[shaderIdx]->size) + "; " +
3566  to_string(shaderUniform.position + size) + ": " +
3567  shaderUniform.name + ": " +
3568  to_string(size) + " / " +
3569  to_string(shaderUniform.size)
3570  );
3571  shaderIdx++;
3572  continue;
3573  }
3574  if (currentContext.uniformBuffers[shaderIdx]->size < shaderUniform.position + size) {
3575  Console::println(
3576  "VKRenderer::" +
3577  string(__FUNCTION__) +
3578  "(): program: uniform buffer is too small: " +
3579  to_string(currentContext.idx) + ": " +
3580  to_string(currentContext.programId) + ": " +
3581  to_string(uniformId) + "; " +
3582  to_string(shaderIdx) + "; " +
3583  to_string(currentContext.uniformBuffers[shaderIdx]->size) + "; " +
3584  to_string(shaderUniform.position + size) + ": " +
3585  shaderUniform.name + ": " +
3586  to_string(shaderUniform.position + size) + " / " +
3587  to_string(currentContext.uniformBuffers[shaderIdx]->size)
3588  );
3589  shaderIdx++;
3590  continue;
3591  }
3592  */
3593  auto& uniformBuffer = shader->uniformBuffers[contextIdx];
3594  auto remainingSize = size;
3595  auto offset = 0;
3596  auto src = data;
3597  auto dst = static_cast<uint8_t*>(&uniformBuffer.uniformBufferData[shaderUniform.position]);
3598  while (remainingSize >= 8) {
3599  *(uint64_t*)dst = *(uint64_t*)src;
3600  remainingSize-= 8;
3601  src+= 8;
3602  dst+= 8;
3603  }
3604  while (remainingSize >= 4) {
3605  *(uint32_t*)dst = *(uint32_t*)src;
3606  remainingSize-= 4;
3607  src+= 4;
3608  dst+= 4;
3609  }
3610  } else
3611  if (shaderUniform.type == shader_type::uniform_type::TYPE_SAMPLER2D) {
3612  shaderUniform.textureUnit = *((int32_t*)data);
3613  } else
3614  if (shaderUniform.type == shader_type::uniform_type::TYPE_SAMPLERCUBE) {
3615  shaderUniform.textureUnit = *((int32_t*)data);
3616  }
3617  shaderIdx++;
3618  }
3619 }
3620 
3621 void VKRenderer::setProgramUniformInteger(int contextIdx, int32_t uniformId, int32_t value)
3622 {
3623  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)&value, sizeof(int32_t));
3624 }
3625 
3626 void VKRenderer::setProgramUniformFloat(int contextIdx, int32_t uniformId, float value)
3627 {
3628  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)&value, sizeof(float));
3629 }
3630 
3631 void VKRenderer::setProgramUniformFloatMatrix3x3(int contextIdx, int32_t uniformId, const array<float, 9>& data)
3632 {
3633  array<float, 12> _data = {
3634  data[0],
3635  data[1],
3636  data[2],
3637  0.0f,
3638  data[3],
3639  data[4],
3640  data[5],
3641  0.0f,
3642  data[6],
3643  data[7],
3644  data[8],
3645  0.0f
3646  };
3647  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)_data.data(), _data.size() * sizeof(float));
3648 }
3649 
3650 void VKRenderer::setProgramUniformFloatMatrix4x4(int contextIdx, int32_t uniformId, const array<float, 16>& data)
3651 {
3652  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)data.data(), data.size() * sizeof(float));
3653 }
3654 
3655 void VKRenderer::setProgramUniformFloatMatrices4x4(int contextIdx, int32_t uniformId, int32_t count, FloatBuffer* data)
3656 {
3657  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)data->getBuffer(), count * sizeof(float) * 16);
3658 }
3659 
3660 void VKRenderer::setProgramUniformFloatVec4(int contextIdx, int32_t uniformId, const array<float, 4>& data)
3661 {
3662  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)data.data(), data.size() * sizeof(float));
3663 }
3664 
3665 void VKRenderer::setProgramUniformFloatVec3(int contextIdx, int32_t uniformId, const array<float, 3>& data)
3666 {
3667  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)data.data(), data.size() * sizeof(float));
3668 }
3669 
3670 void VKRenderer::setProgramUniformFloatVec2(int contextIdx, int32_t uniformId, const array<float, 2>& data)
3671 {
3672  setProgramUniformInternal(contextIdx, uniformId, (uint8_t*)data.data(), data.size() * sizeof(float));
3673 }
3674 
3675 void VKRenderer::setProgramAttributeLocation(int32_t programId, int32_t location, const string& name)
3676 {
3677 }
3678 
3679 void VKRenderer::setViewPort(int32_t width, int32_t height)
3680 {
3681  //
3682  this->viewPortWidth = width;
3683  this->viewPortHeight = height;
3684 }
3685 
3687 {
3688  //
3689  viewport.width = static_cast<float>(viewPortWidth);
3690  viewport.height = static_cast<float>(viewPortHeight);
3691 
3692  scissor.extent.width = viewPortWidth;
3693  scissor.extent.height = viewPortHeight;
3694 
3695  //
3697  framebufferPipelinesCache = nullptr;
3698 }
3699 
3700 void VKRenderer::setClearColor(float red, float green, float blue, float alpha)
3701 {
3702  //
3703  clearRed = red;
3704  clearGreen = green;
3705  clearBlue = blue;
3706  clearAlpha = alpha;
3707 }
3708 
3709 void VKRenderer::enableCulling(int contextIdx)
3710 {
3711  auto& currentContext = contexts[contextIdx];
3712  if (currentContext.cullingEnabled == true) return;
3713  unsetPipeline(currentContext.idx);
3714  currentContext.cullingEnabled = true;
3715  currentContext.frontFaceIndex = currentContext.frontFace;
3716 }
3717 
3718 void VKRenderer::disableCulling(int contextIdx)
3719 {
3720  auto& currentContext = contexts[contextIdx];
3721  if (currentContext.cullingEnabled == false) return;
3722  unsetPipeline(currentContext.idx);
3723  currentContext.cullingEnabled = false;
3724  currentContext.frontFaceIndex = 0;
3725 }
3726 
3727 void VKRenderer::setFrontFace(int contextIdx, int32_t frontFace)
3728 {
3729  auto& currentContext = contexts[contextIdx];
3730  if (currentContext.frontFace == frontFace) return;
3731  unsetPipeline(currentContext.idx);
3732  currentContext.frontFace = frontFace;
3733  currentContext.frontFaceIndex = currentContext.cullingEnabled == true?frontFace:0;
3734 }
3735 
3736 void VKRenderer::setCullFace(int32_t cullFace)
3737 {
3738  if (cullMode == cullFace) return;
3740  cullMode = (VkCullModeFlagBits)cullFace;
3741 }
3742 
3744 {
3745  if (blendingMode == BLENDING_NORMAL) return;
3748 }
3749 
3751  if (blendingMode == BLENDING_ADDITIVE) return;
3754 }
3755 
3757 {
3758  if (blendingMode == BLENDING_NONE) return;
3761 }
3762 
3764 {
3765  if (depthBufferWriting == true) return;
3767  depthBufferWriting = true;
3768 }
3769 
3771 {
3772  if (depthBufferWriting == false) return;
3774  depthBufferWriting = false;
3775 }
3776 
3778 {
3779  if (depthBufferTesting == false) return;
3781  depthBufferTesting = false;
3782 }
3783 
3785 {
3786  if (depthBufferTesting == true) return;
3788  depthBufferTesting = true;
3789 }
3790 
3791 void VKRenderer::setDepthFunction(int32_t depthFunction)
3792 {
3793  if (this->depthFunction == depthFunction) return;
3795  this->depthFunction = depthFunction;
3796 }
3797 
3798 void VKRenderer::setColorMask(bool red, bool green, bool blue, bool alpha)
3799 {
3800 }
3801 
3802 void VKRenderer::clear(int32_t mask)
3803 {
3804  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
3805 
3806  //
3808  startRenderPass(0);
3810  auto attachmentIdx = 0;
3811  array<VkClearAttachment, 9> attachments;
3813  if (frameBuffer != nullptr && frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER) {
3814  for (auto i = 0; i < 8; i++) {
3815  attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3816  attachments[attachmentIdx].colorAttachment = attachmentIdx;
3817  attachments[attachmentIdx].clearValue.color = { clearRed, clearGreen, clearBlue, clearAlpha };
3818  attachmentIdx++;
3819  }
3820  } else
3821  if (frameBuffer == nullptr || frameBuffer->colorTextureId != ID_NONE) {
3822  attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3823  attachments[attachmentIdx].colorAttachment = attachmentIdx;
3824  attachments[attachmentIdx].clearValue.color = { clearRed, clearGreen, clearBlue, clearAlpha };
3825  attachmentIdx++;
3826  }
3827  }
3829  (frameBuffer == nullptr || frameBuffer->depthTextureId != ID_NONE)) {
3830  attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
3831  attachments[attachmentIdx].colorAttachment = 0;
3832  attachments[attachmentIdx].clearValue.depthStencil = { 1.0f, 0 };
3833  attachmentIdx++;
3834  }
3835  VkClearRect clearRect = {
3836  .rect = scissor,
3837  .baseArrayLayer = 0,
3838  .layerCount = 1
3839  };
3840  vkCmdClearAttachments(
3841  contexts[0].commandBuffers[contexts[0].currentCommandBuffer].drawCommand,
3842  attachmentIdx,
3843  attachments.data(),
3844  1,
3845  &clearRect
3846  );
3847  endRenderPass(0);
3848  auto currentBufferIdx = contexts[0].currentCommandBuffer;
3849  auto commandBuffer = endDrawCommandBuffer(0, currentBufferIdx, true);
3850  if (commandBuffer != VK_NULL_HANDLE) {
3851  submitDrawCommandBuffers(1, &commandBuffer, contexts[0].commandBuffers[currentBufferIdx].drawFence);
3852  }
3853  AtomicOperations::increment(statistics.clearCalls);
3854 }
3855 
3857 {
3858  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
3859  texturesMutex.lock();
3860  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
3861  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
3863  return ID_NONE;
3864  }
3865  auto reuseTextureId = -1;
3866  if (freeTextureIds.empty() == false) {
3867  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
3868  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
3869  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
3870  }
3871  auto texturePtr = new texture_type();
3872  auto& texture = *texturePtr;
3873  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
3874  texture.bindTexture = whiteTextureSampler2dDefault;
3875  textures[texture.id] = texturePtr;
3877  return texture.id;
3878 }
3879 
3880 int32_t VKRenderer::createDepthBufferTexture(int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex) {
3881  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(width) + "x" + to_string(height));
3882 
3883  //
3884  if (width <= 0) {
3885  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
3886  width = 1;
3887  }
3888  if (height <= 0) {
3889  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
3890  height = 1;
3891  }
3892 
3893  //
3894  texturesMutex.lock();
3895  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
3896  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
3898  return ID_NONE;
3899  }
3900  auto reuseTextureId = -1;
3901  if (freeTextureIds.empty() == false) {
3902  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
3903  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
3904  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
3905  }
3906  auto texturePtr = new texture_type();
3907  auto& texture = *texturePtr;
3908  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
3909  texture.bindTexture = texturePtr;
3910  textures[texture.id] = texturePtr;
3912  createDepthBufferTexture(texture.id, width, height, cubeMapTextureId, cubeMapTextureIndex);
3913  return texture.id;
3914 }
3915 
3916 void VKRenderer::createDepthBufferTexture(int32_t textureId, int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex)
3917 {
3918  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height));
3919 
3920  //
3921  auto& depthBufferTexture = *getTextureInternal(textureId);
3922  depthBufferTexture.format = VK_FORMAT_D32_SFLOAT;
3923  depthBufferTexture.width = width;
3924  depthBufferTexture.height = height;
3925  depthBufferTexture.cubemapTextureIndex = cubeMapTextureId == ID_NONE?0:cubeMapTextureIndex;
3926 
3927  //
3928  auto cubeMapTexture = cubeMapTextureId == ID_NONE?nullptr:getTextureInternal(cubeMapTextureId);
3929  depthBufferTexture.cubemapBufferTexture = cubeMapTexture != nullptr?cubeMapTexture->cubemapDepthBuffer:nullptr;
3930 
3931  //
3932  VkResult err;
3933 
3934  // if depth buffer is not attached to cube map, create a ordinary depth buffer texture image
3935  if (cubeMapTexture == nullptr) {
3936  // mark for deletion
3937  deleteMutex.lock();
3938  deleteImages.emplace_back(
3939  depthBufferTexture.image,
3940  depthBufferTexture.allocation,
3941  depthBufferTexture.view,
3942  depthBufferTexture.sampler
3943  );
3944  deleteMutex.unlock();
3945 
3946  //
3947  const VkImageCreateInfo imageCreateInfo = {
3948  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3949  .pNext = nullptr,
3950  .flags = 0,
3951  .imageType = VK_IMAGE_TYPE_2D,
3952  .format = depthBufferTexture.format,
3953  .extent = {
3954  .width = depthBufferTexture.width,
3955  .height = depthBufferTexture.height,
3956  .depth = 1
3957  },
3958  .mipLevels = 1,
3959  .arrayLayers = 1,
3960  .samples = VK_SAMPLE_COUNT_1_BIT,
3961  .tiling = VK_IMAGE_TILING_OPTIMAL,
3962  .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
3963  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
3964  .queueFamilyIndexCount = 0,
3965  .pQueueFamilyIndices = 0,
3966  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
3967  };
3968 
3969  VmaAllocationCreateInfo allocationCreateInfo = {};
3970  allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
3971 
3972  VmaAllocationInfo allocationInfo = {};
3973  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &allocationCreateInfo, &depthBufferTexture.image, &depthBufferTexture.allocation, &allocationInfo);
3974  assert(!err);
3975 
3976  // type
3977  depthBufferTexture.type = texture_type::TYPE_DEPTHBUFFER;
3978  depthBufferTexture.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
3979  depthBufferTexture.accessTypes = { THSVS_ACCESS_NONE, THSVS_ACCESS_NONE };
3980  depthBufferTexture.svsLayout = THSVS_IMAGE_LAYOUT_OPTIMAL;
3981  depthBufferTexture.vkLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3982  }
3983 
3984  // create sampler
3985  const VkSamplerCreateInfo samplerCreateInfo = {
3986  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
3987  .pNext = nullptr,
3988  .flags = 0,
3989  .magFilter = VK_FILTER_NEAREST,
3990  .minFilter = VK_FILTER_NEAREST,
3991  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
3992  .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
3993  .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
3994  .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
3995  .mipLodBias = 0.0f,
3996  .anisotropyEnable = VK_FALSE,
3997  .maxAnisotropy = 1,
3998  .compareEnable = VK_FALSE,
3999  .compareOp = VK_COMPARE_OP_NEVER,
4000  .minLod = 0.0f,
4001  .maxLod = 0.0f,
4002  .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
4003  .unnormalizedCoordinates = VK_FALSE,
4004  };
4005  err = vkCreateSampler(device, &samplerCreateInfo, nullptr, &depthBufferTexture.sampler);
4006  assert(!err);
4007 
4008  // create image view
4009  // create ordinary image view if no cubemap depth buffer
4010  // if cubemap frame buffer depth buffer: create a view only of cubemap depth texture and given cube map texture index
4011  VkImageViewCreateInfo viewCreateInfo = {
4012  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
4013  .pNext = nullptr,
4014  .flags = 0,
4015  .image = cubeMapTexture != nullptr?cubeMapTexture->cubemapDepthBuffer->image:depthBufferTexture.image,
4016  .viewType = VK_IMAGE_VIEW_TYPE_2D,
4017  .format = depthBufferTexture.format,
4018  .components = VkComponentMapping(),
4019  .subresourceRange = {
4020  .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
4021  .baseMipLevel = 0,
4022  .levelCount = 1,
4023  .baseArrayLayer = cubeMapTexture != nullptr?static_cast<uint32_t>(cubeMapTextureIndex - CUBEMAPTEXTUREINDEX_MIN):0,
4024  .layerCount = 1
4025  },
4026  };
4027  err = vkCreateImageView(device, &viewCreateInfo, nullptr, &depthBufferTexture.view);
4028  assert(!err);
4029 
4030  // set initial layout
4032  0,
4033  &depthBufferTexture,
4034  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4035  THSVS_IMAGE_LAYOUT_OPTIMAL,
4036  false,
4037  0,
4038  1,
4039  true
4040  );
4041 }
4042 
4043 int32_t VKRenderer::createColorBufferTexture(int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex) {
4044  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(width) + "x" + to_string(height));
4045 
4046  //
4047  if (width <= 0) {
4048  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
4049  width = 1;
4050  }
4051  if (height <= 0) {
4052  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
4053  height = 1;
4054  }
4055 
4056  //
4057  texturesMutex.lock();
4058  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
4059  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
4061  return ID_NONE;
4062  }
4063  auto reuseTextureId = -1;
4064  if (freeTextureIds.empty() == false) {
4065  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
4066  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
4067  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
4068  }
4069  auto texturePtr = new texture_type();
4070  auto& texture = *texturePtr;
4071  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
4072  texture.bindTexture = texturePtr;
4073  textures[texture.id] = texturePtr;
4075  createBufferTexture(texture.id, width, height, cubeMapTextureId, cubeMapTextureIndex, windowFormat);
4076  return texture.id;
4077 }
4078 
4079 void VKRenderer::createBufferTexture(int32_t textureId, int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex, VkFormat format)
4080 {
4081  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height) + "(" + to_string(cubeMapTextureId) + " / " + to_string(cubeMapTextureIndex) + ")");
4082  auto& colorBufferTexture = *getTextureInternal(textureId);
4083  colorBufferTexture.format = format;
4084  colorBufferTexture.width = width;
4085  colorBufferTexture.height = height;
4086  colorBufferTexture.cubemapTextureIndex = cubeMapTextureId == ID_NONE?0:cubeMapTextureIndex;
4087 
4088  // if we have a cube map texture as argument fetch it from textures
4089  auto cubeMapTexture = cubeMapTextureId == ID_NONE?nullptr:getTextureInternal(cubeMapTextureId);
4090  // if we have a cube map texture fetched point colorBufferTexture.cubemapBufferTexture to the cube map color buffer to use its image for view
4091  colorBufferTexture.cubemapBufferTexture = cubeMapTexture != nullptr?cubeMapTexture->cubemapColorBuffer:nullptr;
4092 
4093  //
4094  VkResult err;
4095 
4096  // if color buffer is not attached to cube map, create a ordinary color buffer texture image
4097  if (cubeMapTexture == nullptr) {
4098  // mark for deletion
4099  deleteMutex.lock();
4100  deleteImages.emplace_back(
4101  colorBufferTexture.image,
4102  colorBufferTexture.allocation,
4103  colorBufferTexture.view,
4104  colorBufferTexture.sampler
4105  );
4106  deleteMutex.unlock();
4107 
4108  //
4109  const VkImageCreateInfo imageCreateInfo = {
4110  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
4111  .pNext = nullptr,
4112  .flags = 0,
4113  .imageType = VK_IMAGE_TYPE_2D,
4114  .format = colorBufferTexture.format,
4115  .extent = {
4116  .width = colorBufferTexture.width,
4117  .height = colorBufferTexture.height,
4118  .depth = 1
4119  },
4120  .mipLevels = 1,
4121  .arrayLayers = 1,
4122  .samples = VK_SAMPLE_COUNT_1_BIT,
4123  .tiling = VK_IMAGE_TILING_OPTIMAL,
4124  .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
4125  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
4126  .queueFamilyIndexCount = 0,
4127  .pQueueFamilyIndices = 0,
4128  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
4129  };
4130 
4131  VmaAllocationCreateInfo allocationCreateInfo = {};
4132  allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
4133 
4134  VmaAllocationInfo allocationInfo = {};
4135  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &allocationCreateInfo, &colorBufferTexture.image, &colorBufferTexture.allocation, &allocationInfo);
4136  assert(!err);
4137 
4138  // type
4139  colorBufferTexture.type = texture_type::TYPE_COLORBUFFER;
4140  colorBufferTexture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4141  colorBufferTexture.accessTypes = { THSVS_ACCESS_NONE, THSVS_ACCESS_NONE };
4142  colorBufferTexture.svsLayout = THSVS_IMAGE_LAYOUT_OPTIMAL;
4143  colorBufferTexture.vkLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4144  }
4145 
4146  // create sampler
4147  const VkSamplerCreateInfo samplerCreateInfo = {
4148  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
4149  .pNext = nullptr,
4150  .flags = 0,
4151  .magFilter = VK_FILTER_LINEAR,
4152  .minFilter = VK_FILTER_LINEAR,
4153  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
4154  .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4155  .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4156  .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4157  .mipLodBias = 0.0f,
4158  .anisotropyEnable = VK_FALSE,
4159  .maxAnisotropy = 1,
4160  .compareEnable = VK_FALSE,
4161  .compareOp = VK_COMPARE_OP_NEVER,
4162  .minLod = 0.0f,
4163  .maxLod = 0.0f,
4164  .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
4165  .unnormalizedCoordinates = VK_FALSE,
4166  };
4167  err = vkCreateSampler(device, &samplerCreateInfo, nullptr, &colorBufferTexture.sampler);
4168  assert(!err);
4169 
4170  // create image view
4171  // create ordinary image view if no cubemap color buffer
4172  // if cubemap frame buffer color buffer: create a view only of cubemap color texture and given cube map texture index
4173  VkImageViewCreateInfo viewCreateInfo = {
4174  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
4175  .pNext = nullptr,
4176  .flags = 0,
4177  .image = cubeMapTexture != nullptr?cubeMapTexture->cubemapColorBuffer->image:colorBufferTexture.image,
4178  .viewType = VK_IMAGE_VIEW_TYPE_2D,
4179  .format = colorBufferTexture.format,
4180  .components = {
4181  .r = VK_COMPONENT_SWIZZLE_R,
4182  .g = VK_COMPONENT_SWIZZLE_G,
4183  .b = VK_COMPONENT_SWIZZLE_B,
4184  .a = VK_COMPONENT_SWIZZLE_A,
4185  },
4186  .subresourceRange = {
4187  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4188  .baseMipLevel = 0,
4189  .levelCount = 1,
4190  .baseArrayLayer = cubeMapTexture != nullptr?static_cast<uint32_t>(cubeMapTextureIndex - CUBEMAPTEXTUREINDEX_MIN):0,
4191  .layerCount = 1
4192  }
4193  };
4194  err = vkCreateImageView(device, &viewCreateInfo, nullptr, &colorBufferTexture.view);
4195  assert(!err);
4196 
4197  // set initial color buffer texture layout
4199  0,
4200  &colorBufferTexture,
4201  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4202  THSVS_IMAGE_LAYOUT_OPTIMAL,
4203  false,
4204  0,
4205  1,
4206  true
4207  );
4208 }
4209 
4210 int32_t VKRenderer::createGBufferGeometryTexture(int32_t width, int32_t height) {
4211  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(width) + "x" + to_string(height));
4212 
4213  //
4214  if (width <= 0) {
4215  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
4216  width = 1;
4217  }
4218  if (height <= 0) {
4219  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
4220  height = 1;
4221  }
4222 
4223  //
4224  texturesMutex.lock();
4225  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
4226  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
4228  return ID_NONE;
4229  }
4230  auto reuseTextureId = -1;
4231  if (freeTextureIds.empty() == false) {
4232  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
4233  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
4234  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
4235  }
4236  auto texturePtr = new texture_type();
4237  auto& texture = *texturePtr;
4238  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
4239  texture.bindTexture = texturePtr;
4240  textures[texture.id] = texturePtr;
4242  createBufferTexture(texture.id, width, height, ID_NONE, ID_NONE, VK_FORMAT_R16G16B16A16_SFLOAT);
4243  return texture.id;
4244 }
4245 
4246 int32_t VKRenderer::createGBufferColorTexture(int32_t width, int32_t height) {
4247  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(width) + "x" + to_string(height));
4248 
4249  //
4250  if (width <= 0) {
4251  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
4252  width = 1;
4253  }
4254  if (height <= 0) {
4255  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
4256  height = 1;
4257  }
4258 
4259  //
4260  texturesMutex.lock();
4261  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
4262  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
4264  return ID_NONE;
4265  }
4266  auto reuseTextureId = -1;
4267  if (freeTextureIds.empty() == false) {
4268  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
4269  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
4270  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
4271  }
4272  auto texturePtr = new texture_type();
4273  auto& texture = *texturePtr;
4274  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
4275  texture.bindTexture = texturePtr;
4276  textures[texture.id] = texturePtr;
4278  createBufferTexture(texture.id, width, height, ID_NONE, ID_NONE, windowFormat);
4279  return texture.id;
4280 }
4281 
4282 void VKRenderer::uploadCubeMapTexture(int contextIdx, Texture* textureLeft, Texture* textureRight, Texture* textureTop, Texture* textureBottom, Texture* textureFront, Texture* textureBack) {
4283  if (VERBOSE == true) {
4284  Console::println(
4285  "VKRenderer::" + string(__FUNCTION__) + "(): " +
4286  textureLeft->getId() + " / " +
4287  textureRight->getId() + " / " +
4288  textureTop->getId() + " / " +
4289  textureBottom->getId() + " / " +
4290  textureFront->getId() + " / " +
4291  textureBack->getId()
4292  );
4293  }
4294 
4295  // have our context typed
4296  auto& currentContext = contexts[contextIdx];
4297  auto& boundTexture = currentContext.boundTextures[currentContext.activeTextureUnit];
4298 
4299  //
4300  auto textureObjectPtr = getTextureInternal(boundTexture.id);
4301  if (textureObjectPtr == nullptr) {
4302  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(boundTexture.id));
4303  return;
4304  }
4305  auto& texture = *textureObjectPtr;
4306 
4307  // already uploaded
4308  /*
4309  if (texture.uploaded == true) {
4310  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture already uploaded: " + to_string(boundTexture.id));
4311  return;
4312  }
4313  */
4314 
4315  //
4316  texture.type = texture_type::TYPE_CUBEMAP_TEXTURE;
4317  texture.width = textureLeft->getTextureWidth();
4318  texture.height = textureLeft->getTextureHeight();
4319  texture.format =
4320  textureCompressionAvailable == true &&
4321  textureLeft->isUseCompression() == true &&
4322  textureRight->isUseCompression() == true &&
4323  textureTop->isUseCompression() == true &&
4324  textureBottom->isUseCompression() == true &&
4325  textureFront->isUseCompression() == true &&
4326  textureBack->isUseCompression() == true?
4327  VK_FORMAT_BC7_UNORM_BLOCK:
4328  VK_FORMAT_R8G8B8A8_UNORM;
4329  texture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4330  texture.accessTypes = { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE };
4331  texture.vkLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
4332 
4333  // create color buffer texture including image it self with 6 array layers for each cube map side, sampler and view for binding as cube map texture
4334  const VkImageCreateInfo imageCreateInfo = {
4335  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
4336  .pNext = nullptr,
4337  .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
4338  .imageType = VK_IMAGE_TYPE_2D,
4339  .format = texture.format,
4340  .extent = {
4341  .width = texture.width,
4342  .height = texture.height,
4343  .depth = 1
4344  },
4345  .mipLevels = 1,
4346  .arrayLayers = 6,
4347  .samples = VK_SAMPLE_COUNT_1_BIT,
4348  .tiling = VK_IMAGE_TILING_OPTIMAL,
4349  .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
4350  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
4351  .queueFamilyIndexCount = 0,
4352  .pQueueFamilyIndices = 0,
4353  .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
4354  };
4355 
4356  //
4357  VkResult err;
4358 
4359  VmaAllocationCreateInfo allocationCreateInfo = {};
4360  allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
4361 
4362  VmaAllocationInfo allocationInfo = {};
4363  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &allocationCreateInfo, &texture.image, &texture.allocation, &allocationInfo);
4364  assert(!err);
4365 
4366  //
4367  uploadCubeMapSingleTexture(contextIdx, &texture, textureLeft, 0);
4368  uploadCubeMapSingleTexture(contextIdx, &texture, textureRight, 1);
4369  uploadCubeMapSingleTexture(contextIdx, &texture, textureTop, 2);
4370  uploadCubeMapSingleTexture(contextIdx, &texture, textureBottom, 3);
4371  uploadCubeMapSingleTexture(contextIdx, &texture, textureFront, 4);
4372  uploadCubeMapSingleTexture(contextIdx, &texture, textureBack, 5);
4373 
4374  //
4376  currentContext.idx,
4377  &texture,
4378  { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE },
4379  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4380  THSVS_IMAGE_LAYOUT_OPTIMAL,
4381  THSVS_IMAGE_LAYOUT_OPTIMAL,
4382  false,
4383  0,
4384  1,
4385  0,
4386  6,
4387  true
4388  );
4389  texture.accessTypes =
4390  {{
4391  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4392  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4393  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4394  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4395  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4396  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE }
4397  }};
4398 
4399  // create sampler
4400  const VkSamplerCreateInfo samplerCreateInfo = {
4401  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
4402  .pNext = nullptr,
4403  .flags = 0,
4404  .magFilter = VK_FILTER_LINEAR,
4405  .minFilter = VK_FILTER_LINEAR,
4406  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
4407  .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4408  .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4409  .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4410  .mipLodBias = 0.0f,
4411  .anisotropyEnable = VK_FALSE,
4412  .maxAnisotropy = 1,
4413  .compareEnable = VK_FALSE,
4414  .compareOp = VK_COMPARE_OP_NEVER,
4415  .minLod = 0.0f,
4416  .maxLod = 0.0f,
4417  .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
4418  .unnormalizedCoordinates = VK_FALSE,
4419  };
4420  err = vkCreateSampler(device, &samplerCreateInfo, nullptr, &texture.sampler);
4421  assert(!err);
4422 
4423  // create image view
4424  VkImageViewCreateInfo viewCreateInfo = {
4425  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
4426  .pNext = nullptr,
4427  .flags = 0,
4428  .image = texture.image,
4429  .viewType = VK_IMAGE_VIEW_TYPE_CUBE,
4430  .format = texture.format,
4431  .components = {
4432  .r = VK_COMPONENT_SWIZZLE_R,
4433  .g = VK_COMPONENT_SWIZZLE_G,
4434  .b = VK_COMPONENT_SWIZZLE_B,
4435  .a = VK_COMPONENT_SWIZZLE_A,
4436  },
4437  .subresourceRange = {
4438  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4439  .baseMipLevel = 0,
4440  .levelCount = 1,
4441  .baseArrayLayer = 0,
4442  .layerCount = 6
4443  }
4444  };
4445  err = vkCreateImageView(device, &viewCreateInfo, nullptr, &texture.view);
4446  assert(!err);
4447 
4448  //
4449  boundTexture.sampler = texture.sampler;
4450  boundTexture.view = texture.view;
4451  boundTexture.layout = texture.vkLayout;
4452 
4453  //
4454  texture.uploaded = true;
4455  texture.bindTexture = &texture;
4456 
4457  //
4458  currentContext.uploadedTextureIds.insert(texture.id);
4459 }
4460 
4461 int32_t VKRenderer::createCubeMapTexture(int contextIdx, int32_t width, int32_t height) {
4462  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(width) + "x" + to_string(height));
4463 
4464  // have our context typed
4465  auto& currentContext = contexts[contextIdx];
4466 
4467  //
4468  if (width <= 0) {
4469  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
4470  width = 1;
4471  }
4472  if (height <= 0) {
4473  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
4474  height = 1;
4475  }
4476 
4477  //
4478  texturesMutex.lock();
4479  if (textureIdx - freeTextureIds.size() > TEXTURES_MAX) {
4480  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): could not allocate texture, maximum is " + to_string(TEXTURES_MAX));
4482  return ID_NONE;
4483  }
4484  auto reuseTextureId = -1;
4485  if (freeTextureIds.empty() == false) {
4486  auto freeTextureIdsIdx = freeTextureIds.size() - 1;
4487  reuseTextureId = freeTextureIds[freeTextureIdsIdx];
4488  freeTextureIds.erase(freeTextureIds.begin() + freeTextureIdsIdx);
4489  }
4490  auto texturePtr = new texture_type();
4491  auto& texture = *texturePtr;
4492  texture.id = reuseTextureId != -1?reuseTextureId:textureIdx++;
4493  texture.type = texture_type::TYPE_CUBEMAPBUFFER;
4494  texture.format = windowFormat;
4495  texture.width = width;
4496  texture.height = height;
4497  texture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4498  texture.vkLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4499  texture.bindTexture = whiteTextureSamplerCubeDefault;
4500  textures[texture.id] = texturePtr;
4501 
4502  // create color buffer texture including image it self with 6 array layers for each cube map side, sampler and view for binding as cube map texture
4503  {
4504  texture.cubemapColorBuffer = new texture_type();
4505  texture.cubemapColorBuffer->id = -1;
4506  texture.cubemapColorBuffer->type = texture_type::TYPE_COLORBUFFER;
4507  texture.cubemapColorBuffer->format = windowFormat;
4508  texture.cubemapColorBuffer->width = width;
4509  texture.cubemapColorBuffer->height = height;
4510  texture.cubemapColorBuffer->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4511  texture.cubemapColorBuffer->vkLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4512  const VkImageCreateInfo imageCreateInfo = {
4513  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
4514  .pNext = nullptr,
4515  .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
4516  .imageType = VK_IMAGE_TYPE_2D,
4517  .format = texture.cubemapColorBuffer->format,
4518  .extent = {
4519  .width = texture.cubemapColorBuffer->width,
4520  .height = texture.cubemapColorBuffer->height,
4521  .depth = 1
4522  },
4523  .mipLevels = 1,
4524  .arrayLayers = 6,
4525  .samples = VK_SAMPLE_COUNT_1_BIT,
4526  .tiling = VK_IMAGE_TILING_OPTIMAL,
4527  .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
4528  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
4529  .queueFamilyIndexCount = 0,
4530  .pQueueFamilyIndices = 0,
4531  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
4532  };
4533 
4534  //
4535  VkResult err;
4536 
4537  VmaAllocationCreateInfo allocationCreateInfo = {};
4538  allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
4539 
4540  VmaAllocationInfo allocationInfo = {};
4541  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &allocationCreateInfo, &texture.cubemapColorBuffer->image, &texture.cubemapColorBuffer->allocation, &allocationInfo);
4542  assert(!err);
4543 
4544  // create sampler
4545  const VkSamplerCreateInfo samplerCreateInfo = {
4546  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
4547  .pNext = nullptr,
4548  .flags = 0,
4549  .magFilter = VK_FILTER_LINEAR,
4550  .minFilter = VK_FILTER_LINEAR,
4551  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
4552  .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4553  .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4554  .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
4555  .mipLodBias = 0.0f,
4556  .anisotropyEnable = VK_FALSE,
4557  .maxAnisotropy = 1,
4558  .compareEnable = VK_FALSE,
4559  .compareOp = VK_COMPARE_OP_NEVER,
4560  .minLod = 0.0f,
4561  .maxLod = 0.0f,
4562  .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
4563  .unnormalizedCoordinates = VK_FALSE,
4564  };
4565  err = vkCreateSampler(device, &samplerCreateInfo, nullptr, &texture.sampler);
4566  assert(!err);
4567 
4568  // create image view
4569  VkImageViewCreateInfo viewCreateInfo = {
4570  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
4571  .pNext = nullptr,
4572  .flags = 0,
4573  .image = texture.cubemapColorBuffer->image,
4574  .viewType = VK_IMAGE_VIEW_TYPE_CUBE,
4575  .format = texture.cubemapColorBuffer->format,
4576  .components = {
4577  .r = VK_COMPONENT_SWIZZLE_R,
4578  .g = VK_COMPONENT_SWIZZLE_G,
4579  .b = VK_COMPONENT_SWIZZLE_B,
4580  .a = VK_COMPONENT_SWIZZLE_A,
4581  },
4582  .subresourceRange = {
4583  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4584  .baseMipLevel = 0,
4585  .levelCount = 1,
4586  .baseArrayLayer = 0,
4587  .layerCount = 6
4588  }
4589  };
4590  err = vkCreateImageView(device, &viewCreateInfo, nullptr, &texture.view);
4591  assert(!err);
4592  }
4593 
4594  // set initial layout
4596  currentContext.idx,
4597  texture.cubemapColorBuffer,
4598  { THSVS_ACCESS_NONE, THSVS_ACCESS_NONE },
4599  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4600  THSVS_IMAGE_LAYOUT_OPTIMAL,
4601  THSVS_IMAGE_LAYOUT_OPTIMAL,
4602  false,
4603  0,
4604  1,
4605  0,
4606  6,
4607  true
4608  );
4609 
4610  // create depth buffer texture image it self with 6 array layers for each cube map side
4611  {
4612  texture.cubemapDepthBuffer = new texture_type();
4613  texture.cubemapDepthBuffer->id = -1;
4614  texture.cubemapDepthBuffer->format = VK_FORMAT_D32_SFLOAT;
4615  texture.cubemapDepthBuffer->width = width;
4616  texture.cubemapDepthBuffer->height = height;
4617  texture.cubemapDepthBuffer->type = texture_type::TYPE_DEPTHBUFFER;
4618  texture.cubemapDepthBuffer->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
4619  const VkImageCreateInfo imageCreateInfo = {
4620  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
4621  .pNext = nullptr,
4622  .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
4623  .imageType = VK_IMAGE_TYPE_2D,
4624  .format = texture.cubemapDepthBuffer->format,
4625  .extent = {
4626  .width = texture.cubemapDepthBuffer->width,
4627  .height = texture.cubemapDepthBuffer->height,
4628  .depth = 1
4629  },
4630  .mipLevels = 1,
4631  .arrayLayers = 6,
4632  .samples = VK_SAMPLE_COUNT_1_BIT,
4633  .tiling = VK_IMAGE_TILING_OPTIMAL,
4634  .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
4635  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
4636  .queueFamilyIndexCount = 0,
4637  .pQueueFamilyIndices = 0,
4638  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
4639  };
4640 
4641  //
4642  VkResult err;
4643 
4644  VmaAllocationCreateInfo allocationCreateInfo = {};
4645  allocationCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
4646 
4647  VmaAllocationInfo allocation_info = {};
4648  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &allocationCreateInfo, &texture.cubemapDepthBuffer->image, &texture.cubemapDepthBuffer->allocation, &allocation_info);
4649  assert(!err);
4650 
4651  // set initial layout
4653  currentContext.idx,
4654  texture.cubemapDepthBuffer,
4655  { THSVS_ACCESS_NONE, THSVS_ACCESS_NONE },
4656  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4657  THSVS_IMAGE_LAYOUT_OPTIMAL,
4658  THSVS_IMAGE_LAYOUT_OPTIMAL,
4659  false,
4660  0,
4661  1,
4662  0,
4663  6,
4664  true
4665  );
4666  }
4667 
4668  //
4669  texture.vkLayout = texture.cubemapColorBuffer->vkLayout;
4670 
4671  //
4673 
4674  //
4675  return texture.id;
4676 }
4677 
4678 void VKRenderer::uploadTexture(int contextIdx, Texture* texture)
4679 {
4680  // have our context typed
4681  auto& currentContext = contexts[contextIdx];
4682  auto& boundTexture = currentContext.boundTextures[currentContext.activeTextureUnit];
4683 
4684  //
4685  auto textureObjectPtr = getTextureInternal(boundTexture.id);
4686  if (textureObjectPtr == nullptr) {
4688  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(boundTexture.id));
4689  return;
4690  }
4691  auto& textureType = *textureObjectPtr;
4692 
4693  // already uploaded
4694  /*
4695  if (textureType.uploaded == true) {
4696  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture already uploaded: " + to_string(boundTexture.id));
4697  texturesMutex.unlock();
4698  return;
4699  }
4700  */
4701 
4702  //
4703  textureType.width = texture->getTextureWidth();
4704  textureType.height = texture->getTextureHeight();
4705  textureType.type = texture_type::TYPE_TEXTURE;
4706  textureType.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4707 
4708  //
4709  const VkFormat textureFormat = textureCompressionAvailable == true && texture->isUseCompression() == true?VK_FORMAT_BC7_UNORM_BLOCK:VK_FORMAT_R8G8B8A8_UNORM;
4710 
4711  //
4712  VkFormatProperties textureFormatProperties;
4713  VkResult err;
4714  vkGetPhysicalDeviceFormatProperties(physicalDevice, textureFormat, &textureFormatProperties);
4715 
4716  //
4717  vector<delete_image_type> deleteStagingImages;
4718 
4719  //
4720  auto mipLevels = texture->getMipLevels();
4721 
4722  //
4723  if (textureCompressionAvailable == true && texture->isUseCompression() == true) {
4724  // generate final texture
4726  currentContext.idx,
4727  &textureType,
4728  VK_IMAGE_TILING_OPTIMAL,
4729  VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
4730  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
4731  texture,
4732  { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE },
4733  THSVS_IMAGE_LAYOUT_OPTIMAL,
4734  false,
4735  0,
4736  mipLevels
4737  );
4738 
4739  {
4740  //
4741  auto bc7TextureData = texture->getBC7TextureData();
4742  VkBuffer buffer { VK_NULL_HANDLE };
4743  VmaAllocation allocation { VK_NULL_HANDLE };
4744  VmaAllocationInfo allocationInfo = {};
4745  createBuffer(bc7TextureData.getCapacity(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, buffer, allocation, allocationInfo);
4746  void* data;
4747  vmaMapMemory(vmaAllocator, allocation, &data);
4748  vmaMemCpy(allocation, bc7TextureData.getBuffer(), bc7TextureData.getCapacity());
4749  //
4750  VkBufferImageCopy bufferImageCopy = {
4751  .bufferOffset = 0,
4752  .bufferRowLength = 0,
4753  .bufferImageHeight = 0,
4754  .imageSubresource = {
4755  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4756  .mipLevel = 0,
4757  .baseArrayLayer = 0,
4758  .layerCount = 1
4759  },
4760  .imageOffset = {
4761  .x = 0,
4762  .y = 0,
4763  .z = 0
4764  },
4765  .imageExtent = {
4766  .width = textureType.width,
4767  .height = textureType.height,
4768  .depth = 1
4769  }
4770  };
4771 
4772  //
4773  prepareSetupCommandBuffer(contextIdx);
4774  // copy bc7 buffer to image
4775  vkCmdCopyBufferToImage(
4776  currentContext.setupCommandInUse,
4777  buffer,
4778  textureType.image,
4779  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4780  1,
4781  &bufferImageCopy
4782  );
4783  finishSetupCommandBuffer(contextIdx);
4784 
4785  //
4786  vmaFlushAllocation(vmaAllocator, allocation, 0, VK_WHOLE_SIZE);
4787  vmaUnmapMemory(vmaAllocator, allocation);
4788  vmaDestroyBuffer(vmaAllocator, buffer, allocation);
4789  }
4790 
4791 
4792  // mip maps
4793  if (texture->isUseMipMap() == true) {
4794  // mip levels
4795  auto textureMipMaps = texture->getMipMapTextures(true);
4796  auto level = 1;
4797  for (const auto& textureMipMap: textureMipMaps) {
4798  //
4799  auto& bc7TextureData = textureMipMap.textureData;
4800  VkBuffer buffer { VK_NULL_HANDLE };
4801  VmaAllocation allocation { VK_NULL_HANDLE };
4802  VmaAllocationInfo allocationInfo = {};
4803  createBuffer(bc7TextureData.getCapacity(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, buffer, allocation, allocationInfo);
4804  void* data;
4805  vmaMapMemory(vmaAllocator, allocation, &data);
4806  vmaMemCpy(allocation, bc7TextureData.getBuffer(), bc7TextureData.getCapacity());
4807  //
4808  VkBufferImageCopy bufferImageCopy = {
4809  .bufferOffset = 0,
4810  .bufferRowLength = 0,
4811  .bufferImageHeight = 0,
4812  .imageSubresource = {
4813  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4814  .mipLevel = static_cast<uint32_t>(level),
4815  .baseArrayLayer = 0,
4816  .layerCount = 1
4817  },
4818  .imageOffset = {
4819  .x = 0,
4820  .y = 0,
4821  .z = 0
4822  },
4823  .imageExtent = {
4824  .width = textureMipMap.width,
4825  .height = textureMipMap.height,
4826  .depth = 1
4827  }
4828  };
4829 
4830  //
4831  prepareSetupCommandBuffer(contextIdx);
4832  // copy mip level bc7 buffer to image
4833  vkCmdCopyBufferToImage(
4834  currentContext.setupCommandInUse,
4835  buffer,
4836  textureType.image,
4837  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4838  1,
4839  &bufferImageCopy
4840  );
4841  finishSetupCommandBuffer(contextIdx);
4842 
4843  //
4844  vmaFlushAllocation(vmaAllocator, allocation, 0, VK_WHOLE_SIZE);
4845  vmaUnmapMemory(vmaAllocator, allocation);
4846  vmaDestroyBuffer(vmaAllocator, buffer, allocation);
4847 
4848  //
4849  level++;
4850  }
4851  }
4852 
4853  //
4855  currentContext.idx,
4856  &textureType,
4857  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
4858  THSVS_IMAGE_LAYOUT_OPTIMAL,
4859  false,
4860  0,
4861  mipLevels,
4862  true
4863  );
4864  } else
4865  if ((textureFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
4866  //
4867  struct texture_type stagingTexture {};
4868  stagingTexture.width = texture->getTextureWidth();
4869  stagingTexture.height = texture->getTextureHeight();
4870  stagingTexture.type = texture_type::TYPE_TEXTURE;
4871  stagingTexture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4872 
4873  // upload staging texture
4875  currentContext.idx,
4876  &stagingTexture,
4877  VK_IMAGE_TILING_LINEAR,
4878  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
4879  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
4880  texture,
4881  { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE },
4882  THSVS_IMAGE_LAYOUT_OPTIMAL
4883  );
4884  // generate final texture
4886  currentContext.idx,
4887  &textureType,
4888  VK_IMAGE_TILING_OPTIMAL,
4889  VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
4890  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
4891  texture,
4892  { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE },
4893  THSVS_IMAGE_LAYOUT_OPTIMAL,
4894  false,
4895  0,
4896  mipLevels
4897  );
4898  // copy staging to final texture to mip base level = 0
4899  VkImageCopy imageCopy = {
4900  .srcSubresource = {
4901  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4902  .mipLevel = 0,
4903  .baseArrayLayer = 0,
4904  .layerCount = 1
4905  },
4906  .srcOffset = {
4907  .x = 0,
4908  .y = 0,
4909  .z = 0
4910  },
4911  .dstSubresource = {
4912  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4913  .mipLevel = 0,
4914  .baseArrayLayer = 0,
4915  .layerCount = 1
4916  },
4917  .dstOffset = {
4918  .x = 0,
4919  .y = 0,
4920  .z = 0
4921  },
4922  .extent = {
4923  .width = textureType.width,
4924  .height = textureType.height,
4925  .depth = 1
4926  }
4927  };
4928  //
4929  prepareSetupCommandBuffer(currentContext.idx);
4930  vkCmdCopyImage(
4931  currentContext.setupCommandInUse,
4932  stagingTexture.image,
4933  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4934  textureType.image,
4935  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
4936  1,
4937  &imageCopy
4938  );
4939  finishSetupCommandBuffer(currentContext.idx);
4940  //
4941  deleteStagingImages.emplace_back(
4942  stagingTexture.image,
4943  stagingTexture.allocation,
4944  VK_NULL_HANDLE,
4945  VK_NULL_HANDLE
4946  );
4947  // mip maps
4948  if (texture->isUseMipMap() == true) {
4949  // mip levels
4950  auto textureMipMaps = texture->getMipMapTextures(false);
4951  auto level = 1;
4952  for (const auto& textureMipMap: textureMipMaps) {
4953  //
4954  struct texture_type mipMapStagingTexture {};
4955  mipMapStagingTexture.width = textureMipMap.width;
4956  mipMapStagingTexture.height = textureMipMap.height;
4957  mipMapStagingTexture.type = texture_type::TYPE_TEXTURE;
4958  mipMapStagingTexture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
4959 
4960  // upload mip map texture
4962  currentContext.idx,
4963  &mipMapStagingTexture,
4964  VK_IMAGE_TILING_LINEAR,
4965  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
4966  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
4967  texture,
4968  textureMipMap,
4969  { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE },
4970  THSVS_IMAGE_LAYOUT_OPTIMAL
4971  );
4972 
4973  // copy mip map staging texture to final texture at current mip map level
4974  VkImageCopy imageCopy = {
4975  .srcSubresource = {
4976  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4977  .mipLevel = 0,
4978  .baseArrayLayer = 0,
4979  .layerCount = 1
4980  },
4981  .srcOffset = {
4982  .x = 0,
4983  .y = 0,
4984  .z = 0
4985  },
4986  .dstSubresource = {
4987  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4988  .mipLevel = static_cast<uint32_t>(level),
4989  .baseArrayLayer = 0,
4990  .layerCount = 1
4991  },
4992  .dstOffset = {
4993  .x = 0,
4994  .y = 0,
4995  .z = 0
4996  },
4997  .extent = {
4998  .width = mipMapStagingTexture.width,
4999  .height = mipMapStagingTexture.height,
5000  .depth = 1
5001  }
5002  };
5003  prepareSetupCommandBuffer(currentContext.idx);
5004  vkCmdCopyImage(
5005  currentContext.setupCommandInUse,
5006  mipMapStagingTexture.image,
5007  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5008  textureType.image,
5009  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5010  1,
5011  &imageCopy
5012  );
5013  finishSetupCommandBuffer(currentContext.idx);
5014  //
5015  deleteStagingImages.emplace_back(
5016  mipMapStagingTexture.image,
5017  mipMapStagingTexture.allocation,
5018  VK_NULL_HANDLE,
5019  VK_NULL_HANDLE
5020  );
5021  //
5022  level++;
5023  }
5024  }
5025 
5026  //
5028  currentContext.idx,
5029  &textureType,
5030  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
5031  THSVS_IMAGE_LAYOUT_OPTIMAL,
5032  false,
5033  0,
5034  mipLevels,
5035  true
5036  );
5037 
5038  // mark for deletion
5039  deleteMutex.lock();
5040  for (auto& deleteStagingImage: deleteStagingImages) {
5041  deleteImages.emplace_back(
5042  deleteStagingImage.image,
5043  deleteStagingImage.allocation,
5044  VK_NULL_HANDLE,
5045  VK_NULL_HANDLE
5046  );
5047  }
5048  deleteMutex.unlock();
5049  } else
5050  if ((textureFormatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
5051  // TODO: not sure if I should support this path
5052  // Device can texture using linear textures
5054  currentContext.idx,
5055  &textureType,
5056  VK_IMAGE_TILING_LINEAR,
5057  VK_IMAGE_USAGE_SAMPLED_BIT,
5058  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
5059  texture,
5060  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
5061  THSVS_IMAGE_LAYOUT_OPTIMAL
5062  );
5063  }
5064 
5065  //
5066  VkSamplerMipmapMode mipmapMode;
5067  VkFilter minFilter;
5068  switch (texture->getMinFilter()) {
5069  case Texture::TEXTUREFILTER_NEAREST: minFilter = VK_FILTER_NEAREST; mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
5070  case Texture::TEXTUREFILTER_LINEAR: minFilter = VK_FILTER_LINEAR; mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
5071  case Texture::TEXTUREFILTER_NEAREST_MIPMAP_NEAREST: minFilter = VK_FILTER_NEAREST; mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
5072  case Texture::TEXTUREFILTER_LINEAR_MIPMAP_NEAREST: minFilter = VK_FILTER_NEAREST; mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; break;
5073  case Texture::TEXTUREFILTER_NEAREST_MIPMAP_LINEAR: minFilter = VK_FILTER_LINEAR; mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
5074  case Texture::TEXTUREFILTER_LINEAR_MIPMAP_LINEAR: minFilter = VK_FILTER_LINEAR; mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; break;
5075  }
5076  VkFilter magFilter;
5077  switch (texture->getMagFilter()) {
5078  case Texture::TEXTUREFILTER_NEAREST: magFilter = VK_FILTER_NEAREST; break;
5079  case Texture::TEXTUREFILTER_LINEAR: magFilter = VK_FILTER_LINEAR; break;
5080  case Texture::TEXTUREFILTER_NEAREST_MIPMAP_NEAREST: magFilter = VK_FILTER_NEAREST; break;
5081  case Texture::TEXTUREFILTER_LINEAR_MIPMAP_NEAREST: magFilter = VK_FILTER_NEAREST; break;
5082  case Texture::TEXTUREFILTER_NEAREST_MIPMAP_LINEAR: magFilter = VK_FILTER_LINEAR; break;
5083  case Texture::TEXTUREFILTER_LINEAR_MIPMAP_LINEAR: magFilter = VK_FILTER_LINEAR; break;
5084  }
5085 
5086  //
5087  const VkSamplerCreateInfo samplerCreateInfo = {
5088  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
5089  .pNext = nullptr,
5090  .flags = 0,
5091  .magFilter = minFilter,
5092  .minFilter = magFilter,
5093  .mipmapMode = mipmapMode,
5094  .addressModeU = texture->isRepeat() == true?VK_SAMPLER_ADDRESS_MODE_REPEAT:(texture->getClampMode() == Texture::CLAMPMODE_EDGE?VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER),
5095  .addressModeV = texture->isRepeat() == true?VK_SAMPLER_ADDRESS_MODE_REPEAT:(texture->getClampMode() == Texture::CLAMPMODE_EDGE?VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER),
5096  .addressModeW = texture->isRepeat() == true?VK_SAMPLER_ADDRESS_MODE_REPEAT:(texture->getClampMode() == Texture::CLAMPMODE_EDGE?VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER),
5097  .mipLodBias = 0.0f,
5098  .anisotropyEnable = VK_FALSE,
5099  .maxAnisotropy = 1,
5100  .compareEnable = VK_FALSE,
5101  .compareOp = VK_COMPARE_OP_NEVER,
5102  .minLod = 0.0f,
5103  .maxLod = texture->isUseMipMap() == true?static_cast<float>(mipLevels):0.0f,
5104  .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
5105  .unnormalizedCoordinates = VK_FALSE,
5106  };
5107  VkImageViewCreateInfo viewCreateInfo = {
5108  .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
5109  .pNext = nullptr,
5110  .flags = 0,
5111  .image = textureType.image,
5112  .viewType = VK_IMAGE_VIEW_TYPE_2D,
5113  .format = textureFormat,
5114  .components = {
5115  .r = VK_COMPONENT_SWIZZLE_R,
5116  .g = VK_COMPONENT_SWIZZLE_G,
5117  .b = VK_COMPONENT_SWIZZLE_B,
5118  .a = VK_COMPONENT_SWIZZLE_A,
5119  },
5120  .subresourceRange = {
5121  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5122  .baseMipLevel = 0,
5123  .levelCount = static_cast<uint32_t>(mipLevels),
5124  .baseArrayLayer = 0,
5125  .layerCount = 1
5126  }
5127  };
5128 
5129  // create sampler
5130  err = vkCreateSampler(device, &samplerCreateInfo, nullptr, &textureType.sampler);
5131  assert(!err);
5132 
5133  // create image view
5134  err = vkCreateImageView(device, &viewCreateInfo, nullptr, &textureType.view);
5135  assert(!err);
5136 
5137  //
5138  boundTexture.sampler = textureType.sampler;
5139  boundTexture.view = textureType.view;
5140  boundTexture.layout = textureType.vkLayout;
5141 
5142  //
5143  textureType.uploaded = true;
5144  textureType.bindTexture = textureObjectPtr;
5145 
5146  //
5147  currentContext.uploadedTextureIds.insert(textureType.id);
5148 
5149  //
5150  AtomicOperations::increment(statistics.textureUploads);
5151 }
5152 
5153 void VKRenderer::uploadCubeMapSingleTexture(int contextIdx, texture_type* cubemapTextureType, Texture* texture, uint32_t baseArrayLayer)
5154 {
5155  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + texture->getId());
5156 
5157  // have our context typed
5158  auto& currentContext = contexts[contextIdx];
5159  auto& cubemapTextureTypeRef = *cubemapTextureType;
5160 
5161  //
5162  const VkFormat textureFormat = textureCompressionAvailable == true && texture->isUseCompression() == true?VK_FORMAT_BC7_UNORM_BLOCK:VK_FORMAT_R8G8B8A8_UNORM;
5163 
5164  //
5165  VkFormatProperties textureFormatProperties;
5166  VkResult err;
5167  vkGetPhysicalDeviceFormatProperties(physicalDevice, textureFormat, &textureFormatProperties);
5168 
5169  //
5170  if (textureCompressionAvailable == true && texture->isUseCompression() == true) {
5171  //
5173  currentContext.idx,
5174  &cubemapTextureTypeRef,
5175  { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE },
5176  { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE },
5177  THSVS_IMAGE_LAYOUT_OPTIMAL,
5178  THSVS_IMAGE_LAYOUT_OPTIMAL,
5179  true,
5180  0,
5181  1,
5182  baseArrayLayer,
5183  1,
5184  false
5185  );
5186 
5187  //
5188  auto bc7TextureData = texture->getBC7TextureData();
5189  VkBuffer buffer { VK_NULL_HANDLE };
5190  VmaAllocation allocation { VK_NULL_HANDLE };
5191  VmaAllocationInfo allocationInfo = {};
5192  createBuffer(bc7TextureData.getCapacity(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, buffer, allocation, allocationInfo);
5193  void* data;
5194  vmaMapMemory(vmaAllocator, allocation, &data);
5195  vmaMemCpy(allocation, bc7TextureData.getBuffer(), bc7TextureData.getCapacity());
5196  //
5197  VkBufferImageCopy bufferImageCopy = {
5198  .bufferOffset = 0,
5199  .bufferRowLength = 0,
5200  .bufferImageHeight = 0,
5201  .imageSubresource = {
5202  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5203  .mipLevel = 0,
5204  .baseArrayLayer = baseArrayLayer,
5205  .layerCount = 1
5206  },
5207  .imageOffset = {
5208  .x = 0,
5209  .y = 0,
5210  .z = 0
5211  },
5212  .imageExtent = {
5213  .width = cubemapTextureTypeRef.width,
5214  .height = cubemapTextureTypeRef.height,
5215  .depth = 1
5216  }
5217  };
5218 
5219  //
5220  prepareSetupCommandBuffer(contextIdx);
5221  // copy bc7 buffer to image
5222  vkCmdCopyBufferToImage(
5223  currentContext.setupCommandInUse,
5224  buffer,
5225  cubemapTextureTypeRef.image,
5226  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5227  1,
5228  &bufferImageCopy
5229  );
5230  finishSetupCommandBuffer(contextIdx);
5231 
5232  //
5233  vmaFlushAllocation(vmaAllocator, allocation, 0, VK_WHOLE_SIZE);
5234  vmaUnmapMemory(vmaAllocator, allocation);
5235  vmaDestroyBuffer(vmaAllocator, buffer, allocation);
5236  } else
5237  if ((textureFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
5238  //
5239  struct texture_type staging_texture {};
5240  staging_texture.width = texture->getTextureWidth();
5241  staging_texture.height = texture->getTextureHeight();
5242  staging_texture.type = texture_type::TYPE_TEXTURE;
5243  staging_texture.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
5244 
5245  //
5247  currentContext.idx,
5248  &staging_texture,
5249  VK_IMAGE_TILING_LINEAR,
5250  VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
5251  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
5252  texture,
5253  { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE },
5254  THSVS_IMAGE_LAYOUT_OPTIMAL
5255  );
5256 
5257  //
5259  currentContext.idx,
5260  &cubemapTextureTypeRef,
5261  { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE },
5262  { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE },
5263  THSVS_IMAGE_LAYOUT_OPTIMAL,
5264  THSVS_IMAGE_LAYOUT_OPTIMAL,
5265  true,
5266  0,
5267  1,
5268  baseArrayLayer,
5269  1,
5270  false
5271  );
5272 
5273  //
5274  VkImageCopy imageCopy = {
5275  .srcSubresource = {
5276  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5277  .mipLevel = 0,
5278  .baseArrayLayer = 0,
5279  .layerCount = 1
5280  },
5281  .srcOffset = {
5282  .x = 0,
5283  .y = 0,
5284  .z = 0
5285  },
5286  .dstSubresource = {
5287  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
5288  .mipLevel = 0,
5289  .baseArrayLayer = baseArrayLayer,
5290  .layerCount = 1
5291  },
5292  .dstOffset = {
5293  .x = 0,
5294  .y = 0,
5295  .z = 0
5296  },
5297  .extent = {
5298  .width = cubemapTextureTypeRef.width,
5299  .height = cubemapTextureTypeRef.height,
5300  .depth = 1
5301  }
5302  };
5303 
5304  //
5305  prepareSetupCommandBuffer(currentContext.idx);
5306  vkCmdCopyImage(
5307  currentContext.setupCommandInUse,
5308  staging_texture.image,
5309  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5310  cubemapTextureTypeRef.image,
5311  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5312  1,
5313  &imageCopy
5314  );
5315  //
5316  finishSetupCommandBuffer(currentContext.idx);
5317 
5318  // mark for deletion
5319  deleteMutex.lock();
5320  deleteImages.emplace_back(
5321  staging_texture.image,
5322  staging_texture.allocation,
5323  VK_NULL_HANDLE,
5324  VK_NULL_HANDLE
5325  );
5326  deleteMutex.unlock();
5327  } else
5328  if ((textureFormatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
5329  // TODO: not sure if I should ever support this
5330  }
5331 
5332  //
5333  AtomicOperations::increment(statistics.textureUploads);
5334 }
5335 
5336 void VKRenderer::resizeDepthBufferTexture(int32_t textureId, int32_t width, int32_t height)
5337 {
5338  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height));
5339 
5340  // end render passes
5341  for (auto i = 0; i < Engine::getThreadCount(); i++) {
5342  endRenderPass(i);
5343  }
5344 
5345  //
5346  if (width <= 0) {
5347  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
5348  width = 1;
5349  }
5350  if (height <= 0) {
5351  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
5352  height = 1;
5353  }
5354 
5355  //
5356  auto texturePtr = getTextureInternal(textureId);
5357  if (texturePtr == nullptr) {
5358  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(textureId));
5359  return;
5360  }
5361 
5362  //
5363  auto& texture = *texturePtr;
5364  if (texture.width == width && texture.height == height) return;
5365 
5366  //
5368 
5369  //
5371 
5372  //
5373  createDepthBufferTexture(textureId, width, height, ID_NONE, ID_NONE);
5374  if (texture.frameBufferObjectId != ID_NONE) createFramebufferObject(texture.frameBufferObjectId);
5375 }
5376 
5377 void VKRenderer::resizeColorBufferTexture(int32_t textureId, int32_t width, int32_t height)
5378 {
5379  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height));
5380 
5381  // end render passes
5382  for (auto i = 0; i < Engine::getThreadCount(); i++) {
5383  endRenderPass(i);
5384  }
5385 
5386  //
5387  if (width <= 0) {
5388  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
5389  width = 1;
5390  }
5391  if (height <= 0) {
5392  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
5393  height = 1;
5394  }
5395 
5396  //
5397  auto texturePtr = getTextureInternal(textureId);
5398  if (texturePtr == nullptr) {
5399  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(textureId));
5400  return;
5401  }
5402 
5403  //
5404  auto& texture = *texturePtr;
5405  if (texture.width == width && texture.height == height) return;
5406 
5407  //
5409 
5410  //
5412 
5413  //
5414  createBufferTexture(textureId, width, height, ID_NONE, ID_NONE, windowFormat);
5415  if (texture.frameBufferObjectId != ID_NONE) createFramebufferObject(texture.frameBufferObjectId);
5416 }
5417 
5418 void VKRenderer::resizeGBufferGeometryTexture(int32_t textureId, int32_t width, int32_t height) {
5419  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height));
5420 
5421  // end render passes
5422  for (auto i = 0; i < Engine::getThreadCount(); i++) {
5423  endRenderPass(i);
5424  }
5425 
5426  //
5427  if (width <= 0) {
5428  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
5429  width = 1;
5430  }
5431  if (height <= 0) {
5432  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
5433  height = 1;
5434  }
5435 
5436  //
5437  auto texturePtr = getTextureInternal(textureId);
5438  if (texturePtr == nullptr) {
5439  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(textureId));
5440  return;
5441  }
5442 
5443  //
5444  auto& texture = *texturePtr;
5445  if (texture.width == width && texture.height == height) return;
5446 
5447  //
5449 
5450  //
5452 
5453  //
5454  createBufferTexture(textureId, width, height, ID_NONE, ID_NONE, VK_FORMAT_R16G16B16A16_SFLOAT);
5455  if (texture.frameBufferObjectId != ID_NONE) createFramebufferObject(texture.frameBufferObjectId);
5456 }
5457 
5458 void VKRenderer::resizeGBufferColorTexture(int32_t textureId, int32_t width, int32_t height) {
5459  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(textureId) + " / " + to_string(width) + "x" + to_string(height));
5460 
5461  // end render passes
5462  for (auto i = 0; i < Engine::getThreadCount(); i++) {
5463  endRenderPass(i);
5464  }
5465 
5466  //
5467  if (width <= 0) {
5468  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): width: " + to_string(width) + " <= 0, using 1");
5469  width = 1;
5470  }
5471  if (height <= 0) {
5472  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): height: " + to_string(height) + " <= 0, using 1");
5473  height = 1;
5474  }
5475 
5476  //
5477  auto texturePtr = getTextureInternal(textureId);
5478  if (texturePtr == nullptr) {
5479  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): texture not found: " + to_string(textureId));
5480  return;
5481  }
5482 
5483  //
5484  auto& texture = *texturePtr;
5485  if (texture.width == width && texture.height == height) return;
5486 
5487  //
5489 
5490  //
5492 
5493  //
5494  createBufferTexture(textureId, width, height, ID_NONE, ID_NONE, windowFormat);
5495  if (texture.frameBufferObjectId != ID_NONE) createFramebufferObject(texture.frameBufferObjectId);
5496 }
5497 
5498 void VKRenderer::bindCubeMapTexture(int contextIdx, int32_t textureId) {
5499  //
5500  bindTexture(contextIdx, textureId);
5501 }
5502 
5503 void VKRenderer::bindTexture(int contextIdx, int32_t textureId)
5504 {
5505  // have our context typed
5506  auto& currentContext = contexts[contextIdx];
5507  auto& boundTexture = currentContext.boundTextures[currentContext.activeTextureUnit];
5508 
5509  //
5510  auto textureObject = getBindTextureInternal(textureId);
5511 
5512  //
5513  boundTexture.id = textureId;
5514  if (textureObject != nullptr) {
5515  boundTexture.sampler = textureObject->sampler;
5516  boundTexture.view = textureObject->view;
5517  boundTexture.layout = textureObject->vkLayout;
5518  } else {
5519  boundTexture.sampler = VK_NULL_HANDLE;
5520  boundTexture.view = VK_NULL_HANDLE;
5521  boundTexture.layout = VK_IMAGE_LAYOUT_UNDEFINED;
5522  }
5523 
5524  // done
5525  onBindTexture(contextIdx, textureId);
5526 }
5527 
5528 void VKRenderer::disposeTexture(int32_t textureId)
5529 {
5530  // mark for deletion
5531  disposeMutex.lock();
5532  disposeTextures.push_back(textureId);
5533  disposeMutex.unlock();
5534 }
5535 
5536 void VKRenderer::createFramebufferObject(int32_t frameBufferId) {
5537  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(frameBufferId));
5538  auto frameBuffer = frameBufferId < 1 || frameBufferId >= framebuffers.size()?nullptr:framebuffers[frameBufferId];
5539  if (frameBuffer == nullptr) {
5540  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): frame buffer not found: " + to_string(frameBufferId));
5541  return;
5542  }
5543  auto& frameBufferStruct = *frameBuffer;
5544 
5545  // color buffer
5546  if (frameBuffer->type == framebuffer_object_type::TYPE_COLORBUFFER) {
5547  texture_type* depthBufferTexture = getTextureInternal(frameBufferStruct.depthTextureId);
5548  texture_type* colorBufferTexture = getTextureInternal(frameBufferStruct.colorTextureId);
5549 
5550  if (depthBufferTexture == nullptr) {
5551  if (frameBufferStruct.depthTextureId != ID_NONE) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): color buffer: depth buffer texture not found: " + to_string(frameBufferStruct.depthTextureId));
5552  }
5553  if (colorBufferTexture == nullptr) {
5554  if (frameBufferStruct.colorTextureId != ID_NONE) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): color buffer: color buffer texture not found: " + to_string(frameBufferStruct.colorTextureId));
5555  }
5556 
5557  //
5558  if (depthBufferTexture != nullptr) {
5559  depthBufferTexture->frameBufferObjectId = frameBufferStruct.id;
5560  depthBufferTexture->frameBufferBindImageLayoutChange.valid = false;
5561  depthBufferTexture->frameBufferUnbindImageLayoutChange.valid = false;
5562  }
5563  if (colorBufferTexture != nullptr) {
5564  colorBufferTexture->frameBufferObjectId = frameBufferStruct.id;
5565  colorBufferTexture->frameBufferBindImageLayoutChange.valid = false;
5566  colorBufferTexture->frameBufferUnbindImageLayoutChange.valid = false;
5567  }
5568 
5569  //
5570  if (depthBufferTexture != nullptr && colorBufferTexture != nullptr &&
5571  (depthBufferTexture->width != colorBufferTexture->width ||
5572  depthBufferTexture->height != colorBufferTexture->height)) {
5573  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): color buffer: attachments with different dimension found: Not creating!");
5574  return;
5575  }
5576 
5577  //
5578  VkResult err;
5579 
5580  //
5581  {
5582  if (frameBufferStruct.renderPass != VK_NULL_HANDLE) vkDestroyRenderPass(device, frameBufferStruct.renderPass, nullptr);
5583 
5584  auto attachmentIdx = 0;
5585  array<VkAttachmentDescription, 2> attachments;
5586  if (colorBufferTexture != nullptr) {
5587  attachments[attachmentIdx++] = {
5588  .flags = 0,
5589  .format = colorBufferTexture->format,
5590  .samples = VK_SAMPLE_COUNT_1_BIT,
5591  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5592  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
5593  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5594  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
5595  .initialLayout = colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
5596  .finalLayout = colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
5597  };
5598  }
5599  if (depthBufferTexture != nullptr) {
5600  attachments[attachmentIdx++] = {
5601  .flags = 0,
5602  .format = depthBufferTexture->format,
5603  .samples = VK_SAMPLE_COUNT_1_BIT,
5604  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5605  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
5606  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5607  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
5608  .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
5609  .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
5610  };
5611  }
5612  const VkAttachmentReference colorReference = {
5613  .attachment = 0,
5614  .layout = colorBufferTexture != nullptr?(colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL):VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
5615  };
5616  const VkAttachmentReference depthReference = {
5617  .attachment = static_cast<uint32_t>(colorBufferTexture != nullptr?1:0),
5618  .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
5619  };
5620  const VkSubpassDescription subpassDescription = {
5621  .flags = 0,
5622  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
5623  .inputAttachmentCount = 0,
5624  .pInputAttachments = nullptr,
5625  .colorAttachmentCount = static_cast<uint32_t>(colorBufferTexture != nullptr?1:0),
5626  .pColorAttachments = colorBufferTexture != nullptr?&colorReference:nullptr,
5627  .pResolveAttachments = nullptr,
5628  .pDepthStencilAttachment = depthBufferTexture != nullptr?&depthReference:nullptr,
5629  .preserveAttachmentCount = 0,
5630  .pPreserveAttachments = nullptr
5631  };
5632  const VkRenderPassCreateInfo renderPassCreateInfo = {
5633  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
5634  .pNext = nullptr,
5635  .flags = 0,
5636  .attachmentCount = static_cast<uint32_t>(attachmentIdx),
5637  .pAttachments = attachments.data(),
5638  .subpassCount = 1,
5639  .pSubpasses = &subpassDescription,
5640  .dependencyCount = 0,
5641  .pDependencies = nullptr
5642  };
5643  err = vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &frameBufferStruct.renderPass);
5644  assert(!err);
5645  }
5646 
5647  //
5648  {
5649  if (frameBufferStruct.frameBuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(device, frameBufferStruct.frameBuffer, nullptr);
5650  auto attachmentIdx = 0;
5651  array<VkImageView, 2> attachments;
5652  if (colorBufferTexture != nullptr) attachments[attachmentIdx++] = colorBufferTexture->view;
5653  if (depthBufferTexture != nullptr) attachments[attachmentIdx++] = depthBufferTexture->view;
5654  const VkFramebufferCreateInfo fb_info = {
5655  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
5656  .pNext = nullptr,
5657  .flags = 0,
5658  .renderPass = frameBufferStruct.renderPass,
5659  .attachmentCount = static_cast<uint32_t>(attachmentIdx),
5660  .pAttachments = attachments.data(),
5661  .width = colorBufferTexture != nullptr?colorBufferTexture->width:depthBufferTexture->width,
5662  .height = colorBufferTexture != nullptr?colorBufferTexture->height:depthBufferTexture->height,
5663  .layers = 1
5664  };
5665  err = vkCreateFramebuffer(device, &fb_info, nullptr, &frameBufferStruct.frameBuffer);
5666  assert(!err);
5667  }
5668  } else
5669  if (frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER) {
5670  auto depthBufferTexture = getTextureInternal(frameBufferStruct.depthTextureId);
5671  auto geometryBufferTexture1 = getTextureInternal(frameBufferStruct.gbufferGeometryBufferTextureId1);
5672  auto geometryBufferTexture2 = getTextureInternal(frameBufferStruct.gbufferGeometryBufferTextureId2);
5673  auto geometryBufferTexture3 = getTextureInternal(frameBufferStruct.gbufferGeometryBufferTextureId3);
5674  auto colorBufferTexture1 = getTextureInternal(frameBufferStruct.gbufferColorBufferTextureId1);
5675  auto colorBufferTexture2 = getTextureInternal(frameBufferStruct.gbufferColorBufferTextureId2);
5676  auto colorBufferTexture3 = getTextureInternal(frameBufferStruct.gbufferColorBufferTextureId3);
5677  auto colorBufferTexture4 = getTextureInternal(frameBufferStruct.gbufferColorBufferTextureId4);
5678  auto colorBufferTexture5 = getTextureInternal(frameBufferStruct.gbufferColorBufferTextureId5);
5679 
5680  depthBufferTexture->frameBufferBindImageLayoutChange.valid = false;
5681  depthBufferTexture->frameBufferUnbindImageLayoutChange.valid = false;
5682  geometryBufferTexture1->frameBufferBindImageLayoutChange.valid = false;
5683  geometryBufferTexture1->frameBufferUnbindImageLayoutChange.valid = false;
5684  geometryBufferTexture2->frameBufferBindImageLayoutChange.valid = false;
5685  geometryBufferTexture2->frameBufferUnbindImageLayoutChange.valid = false;
5686  geometryBufferTexture3->frameBufferBindImageLayoutChange.valid = false;
5687  geometryBufferTexture3->frameBufferUnbindImageLayoutChange.valid = false;
5688  colorBufferTexture1->frameBufferBindImageLayoutChange.valid = false;
5689  colorBufferTexture1->frameBufferUnbindImageLayoutChange.valid = false;
5690  colorBufferTexture2->frameBufferBindImageLayoutChange.valid = false;
5691  colorBufferTexture2->frameBufferUnbindImageLayoutChange.valid = false;
5692  colorBufferTexture3->frameBufferBindImageLayoutChange.valid = false;
5693  colorBufferTexture3->frameBufferUnbindImageLayoutChange.valid = false;
5694  colorBufferTexture4->frameBufferBindImageLayoutChange.valid = false;
5695  colorBufferTexture4->frameBufferUnbindImageLayoutChange.valid = false;
5696  colorBufferTexture5->frameBufferBindImageLayoutChange.valid = false;
5697  colorBufferTexture5->frameBufferUnbindImageLayoutChange.valid = false;
5698 
5699  //
5700  depthBufferTexture->frameBufferObjectId = frameBufferStruct.id;
5701  geometryBufferTexture1->frameBufferObjectId = frameBufferStruct.id;
5702  geometryBufferTexture2->frameBufferObjectId = frameBufferStruct.id;
5703  geometryBufferTexture3->frameBufferObjectId = frameBufferStruct.id;
5704  colorBufferTexture1->frameBufferObjectId = frameBufferStruct.id;
5705  colorBufferTexture2->frameBufferObjectId = frameBufferStruct.id;
5706  colorBufferTexture3->frameBufferObjectId = frameBufferStruct.id;
5707  colorBufferTexture4->frameBufferObjectId = frameBufferStruct.id;
5708  colorBufferTexture5->frameBufferObjectId = frameBufferStruct.id;
5709 
5710  //
5711  if (depthBufferTexture->width == 0 || depthBufferTexture->height == 0 ||
5712  depthBufferTexture->width != geometryBufferTexture1->width || depthBufferTexture->height != geometryBufferTexture1->height ||
5713  depthBufferTexture->width != geometryBufferTexture2->width || depthBufferTexture->height != geometryBufferTexture2->height ||
5714  depthBufferTexture->width != geometryBufferTexture3->width || depthBufferTexture->height != geometryBufferTexture3->height ||
5715  depthBufferTexture->width != colorBufferTexture1->width || depthBufferTexture->height != colorBufferTexture1->height ||
5716  depthBufferTexture->width != colorBufferTexture2->width || depthBufferTexture->height != colorBufferTexture2->height ||
5717  depthBufferTexture->width != colorBufferTexture3->width || depthBufferTexture->height != colorBufferTexture3->height ||
5718  depthBufferTexture->width != colorBufferTexture4->width || depthBufferTexture->height != colorBufferTexture4->height ||
5719  depthBufferTexture->width != colorBufferTexture5->width || depthBufferTexture->height != colorBufferTexture5->height) {
5720  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): geometry buffer: attachments with different dimension found: Not creating!");
5721  return;
5722  }
5723 
5724  //
5725  array<texture_type*, 8> colorBufferTextures = {
5726  geometryBufferTexture1,
5727  geometryBufferTexture2,
5728  geometryBufferTexture3,
5729  colorBufferTexture1,
5730  colorBufferTexture2,
5731  colorBufferTexture3,
5732  colorBufferTexture4,
5733  colorBufferTexture5
5734  };
5735 
5736  //
5737  VkResult err;
5738 
5739  //
5740  {
5741  if (frameBufferStruct.renderPass != VK_NULL_HANDLE) vkDestroyRenderPass(device, frameBufferStruct.renderPass, nullptr);
5742 
5743  //
5744  auto attachmentIdx = 0;
5745  array<VkAttachmentDescription, 9> attachments;
5746  for (auto colorBufferTexture: colorBufferTextures) {
5747  attachments[attachmentIdx++] = {
5748  .flags = 0,
5749  .format = colorBufferTexture->format,
5750  .samples = VK_SAMPLE_COUNT_1_BIT,
5751  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5752  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
5753  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5754  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
5755  .initialLayout = colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
5756  .finalLayout = colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
5757  };
5758  }
5759  attachments[attachmentIdx++] = {
5760  .flags = 0,
5761  .format = depthBufferTexture->format,
5762  .samples = VK_SAMPLE_COUNT_1_BIT,
5763  .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5764  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
5765  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
5766  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
5767  .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
5768  .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
5769  };
5770  array<VkAttachmentReference, 8> colorReferences;
5771  {
5772  auto i = 0;
5773  for (auto colorBufferTexture: colorBufferTextures) {
5774  colorReferences[i] = {
5775  .attachment = static_cast<uint32_t>(i),
5776  .layout = colorBufferTexture->vkLayout == VK_IMAGE_LAYOUT_GENERAL?VK_IMAGE_LAYOUT_GENERAL:VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
5777  };
5778  i++;
5779  }
5780  }
5781  const VkAttachmentReference depthReference = {
5782  .attachment = 8,
5783  .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
5784  };
5785  const VkSubpassDescription subpassDescription = {
5786  .flags = 0,
5787  .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
5788  .inputAttachmentCount = 0,
5789  .pInputAttachments = nullptr,
5790  .colorAttachmentCount = 8,
5791  .pColorAttachments = colorReferences.data(),
5792  .pResolveAttachments = nullptr,
5793  .pDepthStencilAttachment = &depthReference,
5794  .preserveAttachmentCount = 0,
5795  .pPreserveAttachments = nullptr
5796  };
5797  const VkRenderPassCreateInfo renderPassCreateInfo = {
5798  .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
5799  .pNext = nullptr,
5800  .flags = 0,
5801  .attachmentCount = static_cast<uint32_t>(attachmentIdx),
5802  .pAttachments = attachments.data(),
5803  .subpassCount = 1,
5804  .pSubpasses = &subpassDescription,
5805  .dependencyCount = 0,
5806  .pDependencies = nullptr
5807  };
5808  err = vkCreateRenderPass(device, &renderPassCreateInfo, nullptr, &frameBufferStruct.renderPass);
5809  assert(!err);
5810  }
5811 
5812  //
5813  {
5814  if (frameBufferStruct.frameBuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(device, frameBufferStruct.frameBuffer, nullptr);
5815  auto attachmentIdx = 0;
5816  array<VkImageView, 9> attachments;
5817  for (auto colorBufferTexture: colorBufferTextures) {
5818  attachments[attachmentIdx++] = colorBufferTexture->view;
5819  }
5820  attachments[attachmentIdx++] = depthBufferTexture->view;
5821  const VkFramebufferCreateInfo frameBufferCreateInfo = {
5822  .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
5823  .pNext = nullptr,
5824  .flags = 0,
5825  .renderPass = frameBufferStruct.renderPass,
5826  .attachmentCount = static_cast<uint32_t>(attachmentIdx),
5827  .pAttachments = attachments.data(),
5828  .width = depthBufferTexture->width,
5829  .height = depthBufferTexture->height,
5830  .layers = 1
5831  };
5832  err = vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &frameBufferStruct.frameBuffer);
5833  assert(!err);
5834  }
5835  }
5836 }
5837 
5838 int32_t VKRenderer::createFramebufferObject(int32_t depthBufferTextureId, int32_t colorBufferTextureId, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex)
5839 {
5840  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(depthBufferTextureId) + ", " + to_string(colorBufferTextureId) + " / " + to_string(cubeMapTextureId) + " / " + to_string(cubeMapTextureIndex));
5841 
5842  // try to reuse a frame buffer id
5843  auto reuseIndex = -1;
5844  for (auto i = 1; i < framebuffers.size(); i++) {
5845  if (framebuffers[i] == nullptr) {
5846  reuseIndex = i;
5847  break;
5848  }
5849  }
5850 
5851  //
5852  auto frameBufferPtr = new framebuffer_object_type();
5853  auto& frameBuffer = *frameBufferPtr;
5854  frameBuffer.id = reuseIndex != -1?reuseIndex:framebuffers.size();
5855  frameBuffer.type = framebuffer_object_type::TYPE_COLORBUFFER;
5856  frameBuffer.depthTextureId = depthBufferTextureId;
5857  frameBuffer.colorTextureId = colorBufferTextureId;
5858  frameBuffer.cubemapTextureId = cubeMapTextureId;
5859  frameBuffer.cubemapTextureIndex = cubeMapTextureIndex;
5860  if (cubeMapTextureId != ID_NONE) {
5861  auto cubeMapTexture = getTextureInternal(cubeMapTextureId);
5862  if (cubeMapTexture == nullptr) {
5863  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): missing cube map texture with id: " + to_string(cubeMapTextureId));
5864  } else {
5865  cubeMapTexture->bindTexture = cubeMapTexture;
5866  }
5867  }
5868 
5869  //
5870  if (reuseIndex != -1) {
5871  framebuffers[reuseIndex] = frameBufferPtr;
5872  } else {
5873  framebuffers.push_back(frameBufferPtr);
5874  }
5875 
5876  //
5877  createFramebufferObject(frameBuffer.id);
5878  return frameBuffer.id;
5879 }
5880 
5882  int32_t depthBufferTextureId,
5883  int32_t geometryBufferTextureId1,
5884  int32_t geometryBufferTextureId2,
5885  int32_t geometryBufferTextureId3,
5886  int32_t colorBufferTextureId1,
5887  int32_t colorBufferTextureId2,
5888  int32_t colorBufferTextureId3,
5889  int32_t colorBufferTextureId4,
5890  int32_t colorBufferTextureId5
5891 ) {
5892  if (VERBOSE == true) {
5893  Console::println(
5894  "VKRenderer::" + string(__FUNCTION__) + "(): " +
5895  to_string(depthBufferTextureId) + ", " +
5896  to_string(geometryBufferTextureId1) + ", " +
5897  to_string(geometryBufferTextureId2) + ", " +
5898  to_string(geometryBufferTextureId3) + ", " +
5899  to_string(colorBufferTextureId1) + ", " +
5900  to_string(colorBufferTextureId2) + ", " +
5901  to_string(colorBufferTextureId3) + ", " +
5902  to_string(colorBufferTextureId4) + ", " +
5903  to_string(colorBufferTextureId5)
5904  );
5905  }
5906 
5907  // try to reuse a frame buffer id
5908  auto reuseIndex = -1;
5909  for (auto i = 1; i < framebuffers.size(); i++) {
5910  if (framebuffers[i] == nullptr) {
5911  reuseIndex = i;
5912  break;
5913  }
5914  }
5915 
5916  //
5917  auto frameBufferPtr = new framebuffer_object_type();
5918  auto& frameBuffer = *frameBufferPtr;
5919  frameBuffer.id = reuseIndex != -1?reuseIndex:framebuffers.size();
5921  frameBuffer.depthTextureId = depthBufferTextureId;
5922  frameBuffer.gbufferGeometryBufferTextureId1 = geometryBufferTextureId1;
5923  frameBuffer.gbufferGeometryBufferTextureId2 = geometryBufferTextureId2;
5924  frameBuffer.gbufferGeometryBufferTextureId3 = geometryBufferTextureId3;
5925  frameBuffer.gbufferColorBufferTextureId1 = colorBufferTextureId1;
5926  frameBuffer.gbufferColorBufferTextureId2 = colorBufferTextureId2;
5927  frameBuffer.gbufferColorBufferTextureId3 = colorBufferTextureId3;
5928  frameBuffer.gbufferColorBufferTextureId4 = colorBufferTextureId4;
5929  frameBuffer.gbufferColorBufferTextureId5 = colorBufferTextureId5;
5930 
5931  //
5932  if (reuseIndex != -1) {
5933  framebuffers[reuseIndex] = frameBufferPtr;
5934  } else {
5935  framebuffers.push_back(frameBufferPtr);
5936  }
5937 
5938  //
5939  createFramebufferObject(frameBuffer.id);
5940  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): new geometry frame buffer: " + to_string(frameBuffer.id));
5941  return frameBuffer.id;
5942 }
5943 
5944 void VKRenderer::bindFrameBuffer(int32_t frameBufferId)
5945 {
5946  //
5947  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(boundFrameBufferId) + " --> " + to_string(frameBufferId));
5948 
5949  //
5950  if (frameBufferId == boundFrameBufferId) return;
5951 
5952  // if unsetting program flush command buffers
5954 
5955  //
5956  framebufferPipelinesCache = nullptr;
5957 
5958  //
5959  if (boundFrameBufferId != ID_NONE) {
5960  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
5961  if (frameBuffer == nullptr) {
5962  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer not found: " + to_string(boundFrameBufferId));
5963  } else {
5964  if (frameBuffer->type == framebuffer_object_type::TYPE_COLORBUFFER) {
5965  auto depthBufferTextureId = frameBuffer->depthTextureId;
5966  if (depthBufferTextureId != ID_NONE) {
5967  auto& depthBufferTexture = *textures[depthBufferTextureId];
5968  if (depthBufferTexture.frameBufferUnbindImageLayoutChange.valid == false) {
5970  depthBufferTexture.frameBufferUnbindImageLayoutChange,
5971  &depthBufferTexture,
5972  { THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE },
5973  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
5974  THSVS_IMAGE_LAYOUT_OPTIMAL,
5975  THSVS_IMAGE_LAYOUT_OPTIMAL,
5976  false,
5977  0,
5978  1
5979  );
5980  }
5981  applyImageLayoutChange(0, depthBufferTexture.frameBufferUnbindImageLayoutChange, &depthBufferTexture, false);
5982  }
5983  auto colorBufferTextureId = frameBuffer->colorTextureId;
5984  if (colorBufferTextureId != ID_NONE) {
5985  auto& colorBufferTexture = *textures[colorBufferTextureId];
5986  if (colorBufferTexture.frameBufferUnbindImageLayoutChange.valid == false) {
5988  colorBufferTexture.frameBufferUnbindImageLayoutChange,
5989  &colorBufferTexture,
5990  { THSVS_ACCESS_COLOR_ATTACHMENT_READ, THSVS_ACCESS_COLOR_ATTACHMENT_WRITE},
5991  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
5992  THSVS_IMAGE_LAYOUT_OPTIMAL,
5993  THSVS_IMAGE_LAYOUT_OPTIMAL,
5994  false,
5995  0,
5996  1
5997  );
5998  }
5999  applyImageLayoutChange(0, colorBufferTexture.frameBufferUnbindImageLayoutChange, &colorBufferTexture, false);
6000  }
6001  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(frameBufferId) + ": color buffer: unbinding: " + to_string(colorBufferTextureId) + " / " + to_string(depthBufferTextureId));
6002  } else
6003  if (frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER) {
6004  auto depthBufferTextureId = frameBuffer->depthTextureId;
6005  auto colorBufferTextureId1 = frameBuffer->gbufferColorBufferTextureId1;
6006  auto colorBufferTextureId2 = frameBuffer->gbufferColorBufferTextureId2;
6007  auto colorBufferTextureId3 = frameBuffer->gbufferColorBufferTextureId3;
6008  auto colorBufferTextureId4 = frameBuffer->gbufferColorBufferTextureId4;
6009  auto colorBufferTextureId5 = frameBuffer->gbufferColorBufferTextureId5;
6010  if (depthBufferTextureId != ID_NONE) {
6011  auto& depthBufferTexture = *textures[depthBufferTextureId];
6012  if (depthBufferTexture.frameBufferUnbindImageLayoutChange.valid == false) {
6014  depthBufferTexture.frameBufferUnbindImageLayoutChange,
6015  &depthBufferTexture,
6016  { THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE },
6017  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6018  THSVS_IMAGE_LAYOUT_OPTIMAL,
6019  THSVS_IMAGE_LAYOUT_OPTIMAL,
6020  false,
6021  0,
6022  1
6023  );
6024  }
6025  applyImageLayoutChange(0, depthBufferTexture.frameBufferUnbindImageLayoutChange, &depthBufferTexture, false);
6026  }
6027  array<texture_type*, 8> colorBufferTextures = {
6028  textures[frameBuffer->gbufferGeometryBufferTextureId1],
6029  textures[frameBuffer->gbufferGeometryBufferTextureId2],
6030  textures[frameBuffer->gbufferGeometryBufferTextureId3],
6031  textures[frameBuffer->gbufferColorBufferTextureId1],
6032  textures[frameBuffer->gbufferColorBufferTextureId2],
6033  textures[frameBuffer->gbufferColorBufferTextureId3],
6034  textures[frameBuffer->gbufferColorBufferTextureId4],
6035  textures[frameBuffer->gbufferColorBufferTextureId5]
6036  };
6037  array<image_layout_change, 8> colorBufferTexturesImageLayoutChanges;
6038  auto i = 0;
6039  for (auto colorBufferTexture: colorBufferTextures) {
6040  if (colorBufferTexture->frameBufferUnbindImageLayoutChange.valid == false) {
6042  colorBufferTexture->frameBufferUnbindImageLayoutChange,
6043  colorBufferTexture,
6044  { THSVS_ACCESS_COLOR_ATTACHMENT_READ, THSVS_ACCESS_COLOR_ATTACHMENT_WRITE},
6045  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6046  THSVS_IMAGE_LAYOUT_OPTIMAL,
6047  THSVS_IMAGE_LAYOUT_OPTIMAL,
6048  false,
6049  0,
6050  1
6051  );
6052  }
6053  colorBufferTexturesImageLayoutChanges[i++] = colorBufferTexture->frameBufferUnbindImageLayoutChange;
6054  }
6055  applyImageLayoutChanges(0, colorBufferTexturesImageLayoutChanges, colorBufferTextures, false);
6056  if (VERBOSE == true) Console::println(
6057  "VKRenderer::" + string(__FUNCTION__) + "(): " +
6058  to_string(frameBufferId) +
6059  ": geometry buffer: unbinding: " +
6060  to_string(depthBufferTextureId) + ", " +
6061  to_string(colorBufferTextures[0]->id) + ", " +
6062  to_string(colorBufferTextures[1]->id) + ", " +
6063  to_string(colorBufferTextures[2]->id) + ", " +
6064  to_string(colorBufferTextures[3]->id) + ", " +
6065  to_string(colorBufferTextures[4]->id) + ", " +
6066  to_string(colorBufferTextures[5]->id) + ", " +
6067  to_string(colorBufferTextures[6]->id) + ", " +
6068  to_string(colorBufferTextures[7]->id)
6069  );
6070  }
6071  }
6072  }
6073 
6074  //
6075  if (frameBufferId != ID_NONE) {
6076  auto frameBuffer = frameBufferId < 0 || frameBufferId >= framebuffers.size()?nullptr:framebuffers[frameBufferId];
6077  if (frameBuffer == nullptr) {
6078  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer not found: " + to_string(frameBufferId));
6079  frameBufferId = ID_NONE;
6080  }
6081  }
6082 
6083  //
6084  boundFrameBufferId = frameBufferId;
6085  if (boundFrameBufferId != ID_NONE) {
6086  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
6087  if (frameBuffer == nullptr) {
6088  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer not found: " + to_string(boundFrameBufferId));
6089  } else {
6090  if (frameBuffer->type == framebuffer_object_type::TYPE_COLORBUFFER) {
6091  auto depthBufferTextureId = frameBuffer->depthTextureId;
6092  auto colorBufferTextureId = frameBuffer->colorTextureId;
6093  if (depthBufferTextureId != ID_NONE) {
6094  auto& depthBufferTexture = *textures[depthBufferTextureId];
6095  if (depthBufferTexture.frameBufferBindImageLayoutChange.valid == false) {
6097  depthBufferTexture.frameBufferBindImageLayoutChange,
6098  &depthBufferTexture,
6099  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6100  { THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE },
6101  THSVS_IMAGE_LAYOUT_OPTIMAL,
6102  THSVS_IMAGE_LAYOUT_OPTIMAL,
6103  false,
6104  0,
6105  1
6106  );
6107  }
6108  applyImageLayoutChange(0, depthBufferTexture.frameBufferBindImageLayoutChange, &depthBufferTexture, false);
6109  }
6110  if (colorBufferTextureId != ID_NONE) {
6111  auto& colorBufferTexture = *textures[colorBufferTextureId];
6112  if (colorBufferTexture.frameBufferBindImageLayoutChange.valid == false) {
6114  colorBufferTexture.frameBufferBindImageLayoutChange,
6115  &colorBufferTexture,
6116  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6117  { THSVS_ACCESS_COLOR_ATTACHMENT_READ, THSVS_ACCESS_COLOR_ATTACHMENT_WRITE},
6118  THSVS_IMAGE_LAYOUT_OPTIMAL,
6119  THSVS_IMAGE_LAYOUT_OPTIMAL,
6120  false,
6121  0,
6122  1
6123  );
6124  }
6125  applyImageLayoutChange(0, colorBufferTexture.frameBufferBindImageLayoutChange, &colorBufferTexture, false);
6126  }
6127  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(frameBufferId) + ": binding: " + to_string(colorBufferTextureId) + " / " + to_string(depthBufferTextureId));
6128  } else
6129  if (frameBuffer->type == framebuffer_object_type::TYPE_GEOMETRYBUFFER) {
6130  auto depthBufferTextureId = frameBuffer->depthTextureId;
6131  auto colorBufferTextureId1 = frameBuffer->gbufferColorBufferTextureId1;
6132  auto colorBufferTextureId2 = frameBuffer->gbufferColorBufferTextureId2;
6133  auto colorBufferTextureId3 = frameBuffer->gbufferColorBufferTextureId3;
6134  auto colorBufferTextureId4 = frameBuffer->gbufferColorBufferTextureId4;
6135  auto colorBufferTextureId5 = frameBuffer->gbufferColorBufferTextureId5;
6136  if (depthBufferTextureId != ID_NONE) {
6137  auto& depthBufferTexture = *textures[depthBufferTextureId];
6138  if (depthBufferTexture.frameBufferBindImageLayoutChange.valid == false) {
6140  depthBufferTexture.frameBufferBindImageLayoutChange,
6141  &depthBufferTexture,
6142  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6143  { THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE },
6144  THSVS_IMAGE_LAYOUT_OPTIMAL,
6145  THSVS_IMAGE_LAYOUT_OPTIMAL,
6146  false,
6147  0,
6148  1
6149  );
6150  }
6151  applyImageLayoutChange(0, depthBufferTexture.frameBufferBindImageLayoutChange, &depthBufferTexture, false);
6152  }
6153  array<texture_type*, 8> colorBufferTextures = {
6154  textures[frameBuffer->gbufferGeometryBufferTextureId1],
6155  textures[frameBuffer->gbufferGeometryBufferTextureId2],
6156  textures[frameBuffer->gbufferGeometryBufferTextureId3],
6157  textures[frameBuffer->gbufferColorBufferTextureId1],
6158  textures[frameBuffer->gbufferColorBufferTextureId2],
6159  textures[frameBuffer->gbufferColorBufferTextureId3],
6160  textures[frameBuffer->gbufferColorBufferTextureId4],
6161  textures[frameBuffer->gbufferColorBufferTextureId5]
6162  };
6163  array<image_layout_change, 8> colorBufferTexturesImageLayoutChanges;
6164  auto i = 0;
6165  for (auto colorBufferTexture: colorBufferTextures) {
6166  if (colorBufferTexture->frameBufferBindImageLayoutChange.valid == false) {
6168  colorBufferTexture->frameBufferBindImageLayoutChange,
6169  colorBufferTexture,
6170  { THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, THSVS_ACCESS_NONE },
6171  { THSVS_ACCESS_COLOR_ATTACHMENT_READ, THSVS_ACCESS_COLOR_ATTACHMENT_WRITE },
6172  THSVS_IMAGE_LAYOUT_OPTIMAL,
6173  THSVS_IMAGE_LAYOUT_OPTIMAL,
6174  false,
6175  0,
6176  1
6177  );
6178  }
6179  colorBufferTexturesImageLayoutChanges[i++] = colorBufferTexture->frameBufferBindImageLayoutChange;
6180  }
6181  applyImageLayoutChanges(0, colorBufferTexturesImageLayoutChanges, colorBufferTextures, false);
6182  if (VERBOSE == true) Console::println(
6183  "VKRenderer::" + string(__FUNCTION__) + "(): " +
6184  to_string(frameBufferId) +
6185  ": geometry buffer: binding: " +
6186  to_string(depthBufferTextureId) + ", " +
6187  to_string(colorBufferTextures[0]->id) + ", " +
6188  to_string(colorBufferTextures[1]->id) + ", " +
6189  to_string(colorBufferTextures[2]->id) + ", " +
6190  to_string(colorBufferTextures[3]->id) + ", " +
6191  to_string(colorBufferTextures[4]->id) + ", " +
6192  to_string(colorBufferTextures[5]->id) + ", " +
6193  to_string(colorBufferTextures[6]->id) + ", " +
6194  to_string(colorBufferTextures[7]->id)
6195  );
6196  }
6197  }
6198  }
6199 
6200  //
6202 }
6203 
6204 void VKRenderer::disposeFrameBufferObject(int32_t frameBufferId)
6205 {
6206  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(frameBufferId));
6207  auto frameBuffer = unique_ptr<framebuffer_object_type>(frameBufferId < 1 || frameBufferId >= framebuffers.size()?nullptr:framebuffers[frameBufferId]);
6208  if (frameBuffer == nullptr) {
6209  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): framebuffer not found: " + to_string(frameBufferId));
6210  return;
6211  }
6212  vkDestroyRenderPass(device, frameBuffer->renderPass, nullptr);
6213  vkDestroyFramebuffer(device, frameBuffer->frameBuffer, nullptr);
6214  framebuffers[frameBufferId] = nullptr;
6215  //
6217 }
6218 
6219 vector<int32_t> VKRenderer::createBufferObjects(int32_t bufferCount, bool useGPUMemory, bool shared)
6220 {
6221  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
6222  vector<int32_t> bufferIds;
6223  buffersMutex.lock();
6224  if (bufferIdx - freeBufferIds.size() > BUFFERS_MAX) {
6225  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): coud not allocate buffer object, maximum is " + to_string(BUFFERS_MAX));
6226  buffersMutex.unlock();
6227  return bufferIds;
6228  }
6229  for (auto i = 0; i < bufferCount; i++) {
6230  auto bufferPtr = new buffer_object_type();
6231  auto& buffer = *bufferPtr;
6232  auto reuseBufferId = -1;
6233  if (freeBufferIds.empty() == false) {
6234  auto reuseBufferIdIdx = freeBufferIds.size() - 1;
6235  reuseBufferId = freeBufferIds[reuseBufferIdIdx];
6236  freeBufferIds.erase(freeBufferIds.begin() + reuseBufferIdIdx);
6237  }
6238  buffer.id = reuseBufferId != -1?reuseBufferId:bufferIdx++;
6239  buffer.useGPUMemory = useGPUMemory;
6240  buffer.shared = shared;
6241  buffer.frameUsedLast = -1LL;
6242  buffer.frameCleanedLast = frame;
6243  buffer.bindBuffer = emptyVertexBuffer != nullptr?emptyVertexBuffer->bindBuffer:nullptr;
6244  buffers[buffer.id] = bufferPtr;
6245  bufferIds.push_back(buffer.id);
6246  }
6247  buffersMutex.unlock();
6248  return bufferIds;
6249 }
6250 
6251 inline VkBuffer VKRenderer::getBindBufferObjectInternal(int32_t bufferObjectId, uint32_t& size) {
6252  auto bufferObject = buffers[bufferObjectId > 0 && bufferObjectId <= BUFFERS_MAX?bufferObjectId:emptyVertexBufferId];
6253  if (bufferObject == nullptr) bufferObject = buffers[emptyVertexBufferId];
6254  auto buffer = bufferObject->bindBuffer;
6255  buffer->frameUsedLast = frame;
6256  size = buffer->size;
6257  return buffer->buffer;
6258 }
6259 
6261  return bufferObjectId > 0 && bufferObjectId <= BUFFERS_MAX?buffers[bufferObjectId]:nullptr;
6262 }
6263 
6264 inline void VKRenderer::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VmaAllocation& allocation, VmaAllocationInfo& allocationInfo) {
6265  //
6266  VkResult err;
6267 
6268  const VkBufferCreateInfo bufferCreateInfo = {
6269  .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
6270  .pNext = nullptr,
6271  .flags = 0,
6272  .size = static_cast<uint32_t>(size),
6273  .usage = usage,
6274  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
6275  .queueFamilyIndexCount = 0,
6276  .pQueueFamilyIndices = nullptr
6277  };
6278 
6279  VmaAllocationCreateInfo allocationCreateInfo = {};
6280  allocationCreateInfo.flags = (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT?VMA_ALLOCATION_CREATE_MAPPED_BIT:0;
6281  allocationCreateInfo.usage = VMA_MEMORY_USAGE_UNKNOWN;
6282  allocationCreateInfo.requiredFlags = properties;
6283 
6284  //
6285  err = vmaCreateBuffer(vmaAllocator, &bufferCreateInfo, &allocationCreateInfo, &buffer, &allocation, &allocationInfo);
6286  assert(!err);
6287 }
6288 
6289 inline void VKRenderer::uploadBufferObjectInternal(int contextIdx, int32_t bufferObjectId, int32_t size, const uint8_t* data, VkBufferUsageFlagBits usage) {
6290  if (size == 0) return;
6291 
6292  auto buffer = getBufferObjectInternal(bufferObjectId);
6293  if (buffer == nullptr) return;
6294 
6295  //
6296  if (buffer->shared == true) buffersMutex.lock();
6297 
6298  // do the work
6299  uploadBufferObjectInternal(contextIdx, buffer, size, data, usage);
6300 
6301  //
6302  if (buffer->shared == true) buffersMutex.unlock();
6303 }
6304 
6305 inline void VKRenderer::vmaMemCpy(VmaAllocation allocationDst, const uint8_t* _src, uint32_t size, uint32_t _offset) {
6306  vmaSpinlock.lock();
6307  VmaAllocationInfo dstAllocationInfo {};
6308  vmaGetAllocationInfo(vmaAllocator, allocationDst, &dstAllocationInfo);
6309 
6310  //
6311  auto remainingSize = size;
6312  auto offset = _offset;
6313  auto src = _src;
6314  auto dst = static_cast<uint8_t*>(dstAllocationInfo.pMappedData) + offset;
6315  while (remainingSize >= 8) {
6316  *(uint64_t*)dst = *(uint64_t*)src;
6317  remainingSize-= 8;
6318  src+= 8;
6319  dst+= 8;
6320  }
6321  while (remainingSize >= 4) {
6322  *(uint32_t*)dst = *(uint32_t*)src;
6323  remainingSize-= 4;
6324  src+= 4;
6325  dst+= 4;
6326  }
6327  //
6328  vmaSpinlock.unlock();
6329 }
6330 
6331 inline void VKRenderer::uploadBufferObjectInternal(int contextIdx, buffer_object_type* buffer, int32_t size, const uint8_t* data, VkBufferUsageFlagBits usage) {
6332  if (size == 0) return;
6333 
6334  //
6335  buffer->uploading = true;
6336 
6337  //
6338  VkResult err;
6339 
6340  //
6341  if (buffer->frameUsedLast != frame) {
6342  // clean up, not sure if this should be done on usage only
6343  vector<int> buffersToRemove;
6344  if (buffer->bufferCount > 1 && frame >= buffer->frameCleanedLast + 10) {
6345  int i = 0;
6346  vector<int32_t> buffersToRemove;
6347  for (const auto& reusableBufferCandidate: buffer->buffers) {
6348  if (frame >= reusableBufferCandidate.frameUsedLast + 10) {
6349  if (reusableBufferCandidate.memoryMappable == true) vmaUnmapMemory(vmaAllocator, reusableBufferCandidate.allocation);
6350  vmaDestroyBuffer(vmaAllocator, reusableBufferCandidate.buffer, reusableBufferCandidate.allocation);
6351  buffersToRemove.push_back(i - buffersToRemove.size());
6352  }
6353  i++;
6354  }
6355  for (auto bufferToRemove: buffersToRemove) {
6356  auto it = buffer->buffers.begin();
6357  for (auto i = 0; i < bufferToRemove; i++) ++it;
6358  buffer->buffers.erase(it);
6359  buffer->bufferCount--;
6360  }
6361  //
6362  buffer->frameCleanedLast = frame;
6363  //
6364  AtomicOperations::increment(statistics.disposedBuffers, buffersToRemove.size());
6365  }
6366 
6367  // create free list
6368  buffer->frameFreeBuffers.clear();
6369  for (auto& reusableBufferCandidate: buffer->buffers) {
6370  buffer->frameFreeBuffers.push_back(&reusableBufferCandidate);
6371  }
6372 
6373  //
6374  buffer->frameUsedLast = frame;
6375  }
6376 
6377  // find a reusable buffer
6378  buffer_object_type::reusable_buffer* reusableBuffer = nullptr;
6379  for (int i = buffer->frameFreeBuffers.size() - 1; i >= 0 ; i--) {
6380  buffer_object_type::reusable_buffer* reusableBufferCandidate = buffer->frameFreeBuffers[i];
6381  if (reusableBufferCandidate->size >= size &&
6382  reusableBufferCandidate->frameUsedLast < frame) {
6383  reusableBuffer = reusableBufferCandidate;
6384  // ok, remove it from free buffers for current frame
6385  buffer->frameFreeBuffers.erase(buffer->frameFreeBuffers.begin() + i);
6386  break;
6387  }
6388  }
6389 
6390  // nope, create one
6391  if (reusableBuffer == nullptr) {
6392  buffer->buffers.emplace_back();
6393  reusableBuffer = &buffer->buffers.back();
6394  buffer->bufferCount++;
6395  }
6396 
6397  // create buffer if not yet done
6398  if (reusableBuffer->size == 0) {
6399  VmaAllocationInfo allocationInfo = {};
6400  createBuffer(size, usage, buffer->useGPUMemory == true?VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, reusableBuffer->buffer, reusableBuffer->allocation, allocationInfo);
6401  reusableBuffer->size = size;
6402 
6403  VkMemoryPropertyFlags memoryFlags;
6404  vmaGetMemoryTypeProperties(vmaAllocator, allocationInfo.memoryType, &memoryFlags);
6405  reusableBuffer->memoryMappable = (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
6406  if (reusableBuffer->memoryMappable == true) {
6407  void* mmData;
6408  vmaMapMemory(vmaAllocator, reusableBuffer->allocation, &mmData);
6409  }
6410  }
6411 
6412  // create buffer
6413  if (reusableBuffer->memoryMappable == true) {
6414  // copy to buffer
6415  vmaMemCpy(reusableBuffer->allocation, data, size);
6416  } else {
6417  prepareSetupCommandBuffer(contextIdx);
6418 
6419  void* stagingData;
6420  VkBuffer stagingBuffer;
6421  VmaAllocation stagingBufferAllocation;
6422  VkDeviceSize stagingBufferAllocationSize;
6423  VmaAllocationInfo stagingBufferAllocationInfo = {};
6424  createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, stagingBuffer, stagingBufferAllocation, stagingBufferAllocationInfo);
6425  // mark staging buffer for deletion when finishing frame
6426  deleteMutex.lock();
6427  deleteBuffers.emplace_back(
6428  stagingBuffer,
6429  stagingBufferAllocation
6430  );
6431  deleteMutex.unlock();
6432 
6433  void* mmData;
6434  vmaMapMemory(vmaAllocator, stagingBufferAllocation, &mmData);
6435 
6436  //
6437  vmaMemCpy(stagingBufferAllocation, data, size);
6438 
6439  // copy to GPU buffer
6440  VkBufferCopy copyRegion = {
6441  .srcOffset = 0,
6442  .dstOffset = 0,
6443  .size = static_cast<VkDeviceSize>(size)
6444  };
6445  vkCmdCopyBuffer(contexts[contextIdx].setupCommandInUse, stagingBuffer, reusableBuffer->buffer, 1, &copyRegion);
6446 
6447  //
6448  finishSetupCommandBuffer(contextIdx);
6449  }
6450 
6451  // frame and current buffer
6452  reusableBuffer->frameUsedLast = frame;
6453  buffer->currentBuffer = reusableBuffer;
6454  buffer->bindBuffer = reusableBuffer;
6455 
6456  //
6457  buffer->uploading = false;
6458 
6459  //
6460  AtomicOperations::increment(statistics.bufferUploads);
6461 }
6462 
6463 void VKRenderer::uploadBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer* data)
6464 {
6465  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
6466 }
6467 
6468 void VKRenderer::uploadBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, ShortBuffer* data)
6469 {
6470  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
6471 }
6472 
6473 void VKRenderer::uploadBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, IntBuffer* data)
6474 {
6475  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
6476 }
6477 
6478 void VKRenderer::uploadIndicesBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, ShortBuffer* data)
6479 {
6480  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT));
6481 }
6482 
6483 void VKRenderer::uploadIndicesBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, IntBuffer* data)
6484 {
6485  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT));
6486 }
6487 
6489  return textureId > 0 && textureId <= TEXTURES_MAX?textures[textureId]:nullptr;
6490 }
6491 
6493  auto textureObject = textureId > 0 && textureId <= TEXTURES_MAX?textures[textureId]:nullptr;
6494  if (textureObject == nullptr) return nullptr;
6495  return textureObject->bindTexture;
6496 }
6497 
6500  framebuffer_pipelines_type* framebufferPipelinesCandidate = nullptr;
6501  for (auto i = 0; i < framebuffersPipelines.size(); i++) {
6502  framebufferPipelinesCandidate = framebuffersPipelines[i];
6503  if (framebufferPipelinesCandidate->id == framebufferPipelinesId) {
6504  framebufferPipelinesCache = framebufferPipelinesCandidate;
6505  return framebufferPipelinesCandidate;
6506  }
6507  }
6508  return nullptr;
6509 }
6510 
6512  auto framebufferPipelines = new framebuffer_pipelines_type();
6513  framebufferPipelines->id = framebufferPipelinesId;
6514  framebufferPipelines->width = viewPortWidth;
6515  framebufferPipelines->height = viewPortHeight;
6516  framebufferPipelines->frameBufferId = boundFrameBufferId;
6517  framebufferPipelines->pipelines.fill(VK_NULL_HANDLE);
6518  framebuffersPipelines.push_back(framebufferPipelines);
6519  return framebufferPipelines;
6520 }
6521 
6522 inline VkPipeline VKRenderer::getPipelineInternal(int contextIdx, program_type* program, uint64_t framebufferPipelineId, uint32_t pipelineIdx) {
6523  auto& currentContext = contexts[contextIdx];
6524 
6525  //
6526  auto framebufferPipelines = getFramebufferPipelines(framebufferPipelineId);
6527  if (framebufferPipelines == nullptr) return VK_NULL_HANDLE;
6528  return framebufferPipelines->pipelines[pipelineIdx];
6529 }
6530 
6531 void VKRenderer::bindIndicesBufferObject(int contextIdx, int32_t bufferObjectId)
6532 {
6533  auto& currentContext = contexts[contextIdx];
6534  uint32_t bufferSize = 0;
6535  currentContext.boundIndicesBuffer = getBindBufferObjectInternal(bufferObjectId, bufferSize);
6536 }
6537 
6538 void VKRenderer::bindSolidColorsBufferObject(int contextIdx, int32_t bufferObjectId)
6539 {
6540  auto& currentContext = contexts[contextIdx];
6541  currentContext.boundBuffers[1] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[1]);
6542 }
6543 
6544 void VKRenderer::bindTextureCoordinatesBufferObject(int contextIdx, int32_t bufferObjectId)
6545 {
6546  auto& currentContext = contexts[contextIdx];
6547  currentContext.boundBuffers[2] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[2]);
6548 }
6549 
6550 void VKRenderer::bindVerticesBufferObject(int contextIdx, int32_t bufferObjectId)
6551 {
6552  auto& currentContext = contexts[contextIdx];
6553  currentContext.boundBuffers[0] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[0]);
6554 }
6555 
6556 void VKRenderer::bindVertices2BufferObject(int contextIdx, int32_t bufferObjectId)
6557 {
6558  auto& currentContext = contexts[contextIdx];
6559  currentContext.boundBuffers[0] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[0]);
6560 }
6561 
6562 void VKRenderer::bindNormalsBufferObject(int contextIdx, int32_t bufferObjectId)
6563 {
6564  auto& currentContext = contexts[contextIdx];
6565  currentContext.boundBuffers[1] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[1]);
6566 }
6567 
6568 void VKRenderer::bindColorsBufferObject(int contextIdx, int32_t bufferObjectId)
6569 {
6570  auto& currentContext = contexts[contextIdx];
6571  currentContext.boundBuffers[3] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[3]);
6572 }
6573 
6574 void VKRenderer::bindTangentsBufferObject(int contextIdx, int32_t bufferObjectId)
6575 {
6576  auto& currentContext = contexts[contextIdx];
6577  currentContext.boundBuffers[4] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[4]);
6578 }
6579 
6580 void VKRenderer::bindBitangentsBufferObject(int contextIdx, int32_t bufferObjectId)
6581 {
6582  auto& currentContext = contexts[contextIdx];
6583  currentContext.boundBuffers[5] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[5]);
6584 }
6585 
6586 void VKRenderer::bindModelMatricesBufferObject(int contextIdx, int32_t bufferObjectId)
6587 {
6588  auto& currentContext = contexts[contextIdx];
6589  currentContext.boundBuffers[6] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[6]);
6590 }
6591 
6592 void VKRenderer::bindEffectColorMulsBufferObject(int contextIdx, int32_t bufferObjectId, int32_t divisor)
6593 {
6594  auto& currentContext = contexts[contextIdx];
6595  currentContext.boundBuffers[7] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[7]);
6596 }
6597 
6598 void VKRenderer::bindEffectColorAddsBufferObject(int contextIdx, int32_t bufferObjectId, int32_t divisor)
6599 {
6600  auto& currentContext = contexts[contextIdx];
6601  currentContext.boundBuffers[8] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[8]);
6602 }
6603 
6604 void VKRenderer::bindOriginsBufferObject(int contextIdx, int32_t bufferObjectId) {
6605  auto& currentContext = contexts[contextIdx];
6606  currentContext.boundBuffers[9] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[9]);
6607 }
6608 
6609 void VKRenderer::bindTextureSpriteIndicesBufferObject(int contextIdx, int32_t bufferObjectId) {
6610  auto& currentContext = contexts[contextIdx];
6611  currentContext.boundBuffers[1] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[1]);
6612 }
6613 
6614 void VKRenderer::bindPointSizesBufferObject(int contextIdx, int32_t bufferObjectId) {
6615  auto& currentContext = contexts[contextIdx];
6616  currentContext.boundBuffers[5] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[5]);
6617 }
6618 
6619 void VKRenderer::bindSpriteSheetDimensionBufferObject(int contextIdx, int32_t bufferObjectId) {
6620  auto& currentContext = contexts[contextIdx];
6621  currentContext.boundBuffers[6] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[6]);
6622 }
6623 
6624 void VKRenderer::drawInstancedIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, int32_t instances) {
6625  drawInstancedTrianglesFromBufferObjects(contextIdx, triangles, trianglesOffset, contexts[contextIdx].boundIndicesBuffer, instances);
6626 }
6627 
6628 inline void VKRenderer::drawInstancedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, VkBuffer indicesBuffer, int32_t instances)
6629 {
6630  auto& currentContext = contexts[contextIdx];
6631  auto& programContext = currentContext.program->contexts[currentContext.idx];
6632  auto& programCommandBuffer = programContext.commandBuffers[currentContext.currentCommandBuffer];
6633 
6634  //
6635  auto uboDescriptorSet = programCommandBuffer.uboDescriptorSets[programCommandBuffer.uboDescriptorSetsIdx];
6636  auto texturesDescriptorSetUncached = programCommandBuffer.texturesDescriptorSetsUncached[programCommandBuffer.texturesDescriptorSetsIdxUncached];
6637 
6638  // start draw command buffer, it not yet done
6639  beginDrawCommandBuffer(currentContext.idx);
6640 
6641  // start render pass
6642  startRenderPass(currentContext.idx);
6643 
6644  // pipeline
6645  if (currentContext.program->type == PROGRAM_OBJECTS) setupObjectsRenderingPipeline(currentContext.idx, currentContext.program); else
6646  if (currentContext.program->type == PROGRAM_GUI) setupGUIRenderingPipeline(currentContext.idx, currentContext.program); else
6647  return;
6648 
6649  //
6650  auto uboIdx = 0;
6651  array<uint16_t, 8> textureIds {
6652  static_cast<uint16_t>(ID_NONE),
6653  static_cast<uint16_t>(ID_NONE),
6654  static_cast<uint16_t>(ID_NONE),
6655  static_cast<uint16_t>(ID_NONE),
6656  static_cast<uint16_t>(ID_NONE),
6657  static_cast<uint16_t>(ID_NONE),
6658  static_cast<uint16_t>(ID_NONE),
6659  static_cast<uint16_t>(ID_NONE)
6660  };
6661  // get texture set cache id
6662  auto samplers = -1;
6663  {
6664  auto shaderIdx = 0;
6665  auto samplerIdx = 0;
6666  for (auto shader: currentContext.program->shaders) {
6667  // sampler2D + samplerCube
6668  for (auto uniform: shader->samplerUniformList) {
6669  if (samplerIdx < TEXTUREDESCRIPTORSET_MAX_TEXTURES) {
6670  if (uniform->textureUnit == -1) {
6671  textureIds[samplerIdx] = ID_NONE;
6672  } else {
6673  auto& boundTexture = currentContext.boundTextures[uniform->textureUnit];
6674  if (boundTexture.view == VK_NULL_HANDLE) {
6675  textureIds[samplerIdx] = ID_NONE;
6676  } else {
6677  textureIds[samplerIdx] = boundTexture.id;
6678  }
6679  }
6680  }
6681  samplerIdx++;
6682  }
6683 
6684  // uniform buffer
6685  if (shader->uboBindingIdx == -1) {
6686  shaderIdx++;
6687  continue;
6688  }
6689 
6690  //
6691  auto& uniformBuffer = shader->uniformBuffers[currentContext.idx];
6692  auto& src = uniformBuffer.buffers[uniformBuffer.bufferIdx];
6693  auto uboBuffer = src.buffer;
6694  uniformBuffer.bufferIdx = (uniformBuffer.bufferIdx + 1) % uniformBuffer.buffers.size();
6695  vmaMemCpy(src.allocation, uniformBuffer.uniformBufferData.data(), uniformBuffer.size);
6696 
6697  //
6698  currentContext.descriptorBufferInfos[shader->uboBindingIdx] = {
6699  .buffer = uboBuffer,
6700  .offset = 0,
6701  .range = shader->uboSize
6702  };
6703 
6704  //
6705  currentContext.descriptorWriteSets[shader->uboBindingIdx] = {
6706  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
6707  .pNext = nullptr,
6708  .dstSet = uboDescriptorSet,
6709  .dstBinding = static_cast<uint32_t>(shader->uboBindingIdx),
6710  .dstArrayElement = 0,
6711  .descriptorCount = 1,
6712  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
6713  .pImageInfo = nullptr,
6714  .pBufferInfo = &currentContext.descriptorBufferInfos[shader->uboBindingIdx],
6715  .pTexelBufferView = nullptr
6716  };
6717 
6718  //
6719  shaderIdx++;
6720  uboIdx++;
6721  }
6722  samplers = samplerIdx;
6723  }
6724 
6725  tuple<uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t> textureDescriptorSetCacheId = {
6726  textureIds[0], textureIds[1], textureIds[2], textureIds[3],
6727  textureIds[4], textureIds[5], textureIds[6], textureIds[7]
6728  };
6729  //
6730  auto& textureDescriptorSetCache = programContext.texturesDescriptorSetsCache;
6731  auto textureDescriptorSetCacheIt = samplers > TEXTUREDESCRIPTORSET_MAX_TEXTURES?textureDescriptorSetCache.end():textureDescriptorSetCache.find(textureDescriptorSetCacheId);
6732  auto textureDescriptorSetCacheHit = textureDescriptorSetCacheIt != textureDescriptorSetCache.end();
6733  if (textureDescriptorSetCacheHit == false) {
6734  if (samplers <= TEXTUREDESCRIPTORSET_MAX_TEXTURES) {
6735  auto textureDescriptorSetsIdx = -1;
6736  if (programContext.freeTextureDescriptorSetsIds.empty() == false) {
6737  auto freeTextureDescriptorSetsIdsIdx = programContext.freeTextureDescriptorSetsIds.size() - 1;
6738  textureDescriptorSetsIdx = programContext.freeTextureDescriptorSetsIds[freeTextureDescriptorSetsIdsIdx];
6739  programContext.freeTextureDescriptorSetsIds.erase(programContext.freeTextureDescriptorSetsIds.begin() + freeTextureDescriptorSetsIdsIdx);
6740  } else {
6741  textureDescriptorSetsIdx = programContext.descriptorSets2Idx++;
6742  }
6743  texturesDescriptorSetUncached = programContext.descriptorSets2[textureDescriptorSetsIdx];
6744  textureDescriptorSetCache[textureDescriptorSetCacheId] = textureDescriptorSetsIdx;
6745  for (auto textureId: textureIds) programContext.texturesDescriptorSetsCacheTextureIds[textureId].insert(textureDescriptorSetCacheId);
6746  } else {
6747  programCommandBuffer.texturesDescriptorSetsIdxUncached = (programCommandBuffer.texturesDescriptorSetsIdxUncached + 1) % programCommandBuffer.texturesDescriptorSetsUncached.size();
6748  }
6749  auto samplerIdx = 0;
6750  for (auto shader: currentContext.program->shaders) {
6751  // sampler2D + samplerCube
6752  for (auto uniform: shader->samplerUniformList) {
6753  if (uniform->textureUnit == -1) {
6754  switch(uniform->type) {
6756  currentContext.descriptorImageInfos[samplerIdx] = {
6758  .imageView = whiteTextureSampler2dDefault->view,
6759  .imageLayout = whiteTextureSampler2dDefault->vkLayout
6760  };
6761  break;
6763  currentContext.descriptorImageInfos[samplerIdx] = {
6765  .imageView = whiteTextureSamplerCubeDefault->view,
6767  };
6768  break;
6769  default:
6770  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
6771  break;
6772  }
6773  } else {
6774  auto& boundTexture = currentContext.boundTextures[uniform->textureUnit];
6775  if (boundTexture.view == VK_NULL_HANDLE) {
6776  switch(uniform->type) {
6778  currentContext.descriptorImageInfos[samplerIdx] = {
6780  .imageView = whiteTextureSampler2dDefault->view,
6781  .imageLayout = whiteTextureSampler2dDefault->vkLayout
6782  };
6783  break;
6785  currentContext.descriptorImageInfos[samplerIdx] = {
6787  .imageView = whiteTextureSamplerCubeDefault->view,
6789  };
6790  break;
6791  default:
6792  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
6793  break;
6794  }
6795  } else {
6796  currentContext.descriptorImageInfos[samplerIdx] = {
6797  .sampler = boundTexture.sampler,
6798  .imageView = boundTexture.view,
6799  .imageLayout = boundTexture.layout
6800  };
6801  }
6802  }
6803  currentContext.descriptorWriteSets[uniform->position] = {
6804  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
6805  .pNext = nullptr,
6806  .dstSet = texturesDescriptorSetUncached,
6807  .dstBinding = static_cast<uint32_t>(uniform->position),
6808  .dstArrayElement = 0,
6809  .descriptorCount = 1,
6810  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6811  .pImageInfo = &currentContext.descriptorImageInfos[samplerIdx],
6812  .pBufferInfo = VK_NULL_HANDLE,
6813  .pTexelBufferView = VK_NULL_HANDLE
6814  };
6815  samplerIdx++;
6816  }
6817  }
6818  } else {
6819  texturesDescriptorSetUncached = programContext.descriptorSets2[textureDescriptorSetCacheIt->second];
6820  }
6821 
6822  //
6823  vkUpdateDescriptorSets(device, textureDescriptorSetCacheHit == true?uboIdx:currentContext.program->layoutBindings, currentContext.descriptorWriteSets.data(), 0, nullptr);
6824 
6825  // descriptor sets
6826  array<VkDescriptorSet, 2> descSets { uboDescriptorSet, texturesDescriptorSetUncached };
6827 
6828  // draw cmd
6829  auto& drawCommand = currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand;
6830  vkCmdBindDescriptorSets(drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, currentContext.program->pipelineLayout, 0, descSets.size(), descSets.data(), 0, nullptr);
6831 
6832  // index buffer
6833  if (indicesBuffer != VK_NULL_HANDLE) {
6834  vkCmdBindIndexBuffer(drawCommand, indicesBuffer, 0, VK_INDEX_TYPE_UINT32);
6835  }
6836 
6837  // buffers
6838  vkCmdBindVertexBuffers(drawCommand, 0, currentContext.program->type == PROGRAM_GUI?GUI_VERTEX_BUFFER_COUNT:OBJECTS_VERTEX_BUFFER_COUNT, currentContext.boundBuffers.data(), currentContext.boundBufferOffsets.data());
6839 
6840  // draw
6841  if (indicesBuffer != VK_NULL_HANDLE) {
6842  vkCmdDrawIndexed(drawCommand, triangles * 3, instances, trianglesOffset * 3, 0, 0);
6843  } else {
6844  vkCmdDraw(drawCommand, triangles * 3, instances, trianglesOffset * 3, 0);
6845  }
6846 
6847  //
6848  programCommandBuffer.uboDescriptorSetsIdx = (programCommandBuffer.uboDescriptorSetsIdx + 1) % programCommandBuffer.uboDescriptorSets.size();
6849  currentContext.commandCount++;
6850 
6851  //
6852  requestSubmitDrawBuffers(currentContext.idx);
6853 
6854  //
6855  AtomicOperations::increment(statistics.renderCalls);
6856  AtomicOperations::increment(statistics.instances, instances);
6857  AtomicOperations::increment(statistics.triangles, triangles * instances);
6858 }
6859 
6860 void VKRenderer::drawIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset)
6861 {
6862  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
6863 
6864  //
6865  drawInstancedIndexedTrianglesFromBufferObjects(contextIdx, triangles, trianglesOffset, 1);
6866 }
6867 
6869  VkResult err;
6870 
6871  // end render passes
6872  for (auto i = 0; i < Engine::getThreadCount(); i++) {
6873  auto& context = contexts[i];
6874  endRenderPass(context.idx);
6875  auto currentBufferIdx = context.currentCommandBuffer;
6876  auto commandBuffer = endDrawCommandBuffer(context.idx, -1, true);
6877  if (commandBuffer != VK_NULL_HANDLE) {
6878  submitDrawCommandBuffers(1, &commandBuffer, context.commandBuffers[currentBufferIdx].drawFence);
6879  }
6880  unsetPipeline(context.idx);
6881  }
6882 }
6883 
6884 inline void VKRenderer::requestSubmitDrawBuffers(int contextIdx) {
6885  // have our context typed
6886  auto& currentContext = contexts[contextIdx];
6887 
6888  //
6889  auto commandsMax = COMMANDS_MAX_GRAPHICS; // TODO: could also be compute, ...
6890  if (currentContext.commandCount >= commandsMax) {
6891  endRenderPass(currentContext.idx);
6892  auto currentBufferIdx = currentContext.currentCommandBuffer;
6893  auto commandBuffer = endDrawCommandBuffer(currentContext.idx, -1, true);
6894  if (commandBuffer != VK_NULL_HANDLE) submitDrawCommandBuffers(1, &commandBuffer, currentContext.commandBuffers[currentBufferIdx].drawFence);
6895  currentContext.commandCount = 0;
6896  }
6897 }
6898 
6899 void VKRenderer::drawInstancedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, int32_t instances)
6900 {
6901  drawInstancedTrianglesFromBufferObjects(contextIdx, triangles, trianglesOffset, VK_NULL_HANDLE, instances);
6902 }
6903 
6904 void VKRenderer::drawTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset)
6905 {
6906  drawInstancedTrianglesFromBufferObjects(contextIdx, triangles, trianglesOffset, VK_NULL_HANDLE, 1);
6907 }
6908 
6909 void VKRenderer::drawPointsFromBufferObjects(int contextIdx, int32_t points, int32_t pointsOffset)
6910 {
6911  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
6912 
6913  // have our context typed
6914  auto& currentContext = contexts[contextIdx];
6915  auto& programContext = currentContext.program->contexts[currentContext.idx];
6916  auto& programCommandBuffer = programContext.commandBuffers[currentContext.currentCommandBuffer];
6917 
6918  //
6919  auto uboDescriptorSet = programCommandBuffer.uboDescriptorSets[programCommandBuffer.uboDescriptorSetsIdx];
6920  auto texturesDescriptorSet = programCommandBuffer.texturesDescriptorSetsUncached[programCommandBuffer.texturesDescriptorSetsIdxUncached];
6921 
6922  // start draw command buffer, it not yet done
6923  beginDrawCommandBuffer(currentContext.idx);
6924 
6925  // render pass
6926  startRenderPass(currentContext.idx);
6927 
6928  // pipeline
6929  setupPointsRenderingPipeline(currentContext.idx, currentContext.program);
6930 
6931  // do points render command
6932  auto shaderIdx = 0;
6933  auto uboIdx = 0;
6934  auto samplerIdx = 0;
6935  for (auto shader: currentContext.program->shaders) {
6936  // sampler2D + samplerCube
6937  for (auto uniform: shader->samplerUniformList) {
6938  if (uniform->textureUnit == -1) {
6939  switch(uniform->type) {
6941  currentContext.descriptorImageInfos[samplerIdx] = {
6943  .imageView = whiteTextureSampler2dDefault->view,
6944  .imageLayout = whiteTextureSampler2dDefault->vkLayout
6945  };
6946  break;
6948  currentContext.descriptorImageInfos[samplerIdx] = {
6950  .imageView = whiteTextureSamplerCubeDefault->view,
6952  };
6953  break;
6954  default:
6955  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
6956  break;
6957  }
6958  } else {
6959  auto& texture = currentContext.boundTextures[uniform->textureUnit];
6960  if (texture.view == VK_NULL_HANDLE) {
6961  switch(uniform->type) {
6963  currentContext.descriptorImageInfos[samplerIdx] = {
6965  .imageView = whiteTextureSampler2dDefault->view,
6966  .imageLayout = whiteTextureSampler2dDefault->vkLayout
6967  };
6968  break;
6970  currentContext.descriptorImageInfos[samplerIdx] = {
6972  .imageView = whiteTextureSamplerCubeDefault->view,
6974  };
6975  break;
6976  default:
6977  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
6978  break;
6979  }
6980  } else {
6981  currentContext.descriptorImageInfos[samplerIdx] = {
6982  .sampler = texture.sampler,
6983  .imageView = texture.view,
6984  .imageLayout = texture.layout
6985  };
6986  }
6987  }
6988  currentContext.descriptorWriteSets[uniform->position] = {
6989  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
6990  .pNext = nullptr,
6991  .dstSet = texturesDescriptorSet,
6992  .dstBinding = static_cast<uint32_t>(uniform->position),
6993  .dstArrayElement = 0,
6994  .descriptorCount = 1,
6995  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6996  .pImageInfo = &currentContext.descriptorImageInfos[samplerIdx],
6997  .pBufferInfo = VK_NULL_HANDLE,
6998  .pTexelBufferView = VK_NULL_HANDLE
6999  };
7000  samplerIdx++;
7001  }
7002 
7003  // uniform buffer
7004  if (shader->uboBindingIdx == -1) {
7005  shaderIdx++;
7006  continue;
7007  }
7008 
7009  //
7010  auto& uniformBuffer = shader->uniformBuffers[currentContext.idx];
7011  auto& src = uniformBuffer.buffers[uniformBuffer.bufferIdx];
7012  auto uboBuffer = src.buffer;
7013  uniformBuffer.bufferIdx = (uniformBuffer.bufferIdx + 1) % uniformBuffer.buffers.size();
7014  vmaMemCpy(src.allocation, uniformBuffer.uniformBufferData.data(), uniformBuffer.size);
7015 
7016  //
7017  currentContext.descriptorBufferInfos[shader->uboBindingIdx] = {
7018  .buffer = uboBuffer,
7019  .offset = 0,
7020  .range = shader->uboSize
7021  };
7022 
7023  //
7024  currentContext.descriptorWriteSets[shader->uboBindingIdx] = {
7025  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
7026  .pNext = nullptr,
7027  .dstSet = uboDescriptorSet,
7028  .dstBinding = static_cast<uint32_t>(shader->uboBindingIdx),
7029  .dstArrayElement = 0,
7030  .descriptorCount = 1,
7031  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
7032  .pImageInfo = nullptr,
7033  .pBufferInfo = &currentContext.descriptorBufferInfos[shader->uboBindingIdx],
7034  .pTexelBufferView = nullptr
7035  };
7036 
7037  //
7038  shaderIdx++;
7039  uboIdx++;
7040  }
7041 
7042  //
7043  vkUpdateDescriptorSets(device, currentContext.program->layoutBindings, currentContext.descriptorWriteSets.data(), 0, nullptr);
7044 
7045  //
7046  auto& drawCommand = currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand;
7047  array<VkDescriptorSet, 2> descriptorSets { uboDescriptorSet, texturesDescriptorSet };
7048  vkCmdBindDescriptorSets(drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, currentContext.program->pipelineLayout, 0, descriptorSets.size(), descriptorSets.data(), 0, nullptr);
7049  vkCmdBindVertexBuffers(drawCommand, 0, POINTS_VERTEX_BUFFER_COUNT, currentContext.boundBuffers.data(), currentContext.boundBufferOffsets.data());
7050  vkCmdDraw(drawCommand, points, 1, pointsOffset, 0);
7051 
7052  //
7053  programCommandBuffer.uboDescriptorSetsIdx = (programCommandBuffer.uboDescriptorSetsIdx + 1) % programCommandBuffer.uboDescriptorSets.size();
7054  programCommandBuffer.texturesDescriptorSetsIdxUncached = (programCommandBuffer.texturesDescriptorSetsIdxUncached + 1) % programCommandBuffer.texturesDescriptorSetsUncached.size();
7055  currentContext.commandCount++;
7056 
7057  //
7058  requestSubmitDrawBuffers(currentContext.idx);
7059 
7060  //
7061  AtomicOperations::increment(statistics.renderCalls);
7062  AtomicOperations::increment(statistics.points, points);
7063 }
7064 
7065 void VKRenderer::setLineWidth(float lineWidth)
7066 {
7067  this->lineWidth = lineWidth;
7068 }
7069 
7070 void VKRenderer::drawLinesFromBufferObjects(int contextIdx, int32_t points, int32_t pointsOffset)
7071 {
7072  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
7073 
7074  // have our context typed
7075  auto& currentContext = contexts[contextIdx];
7076  auto& programCommandBuffer = currentContext.program->contexts[currentContext.idx].commandBuffers[currentContext.currentCommandBuffer];
7077 
7078  //
7079  auto uboDescriptorSet = programCommandBuffer.uboDescriptorSets[programCommandBuffer.uboDescriptorSetsIdx];
7080  auto textureDescriptorSet = programCommandBuffer.texturesDescriptorSetsUncached[programCommandBuffer.texturesDescriptorSetsIdxUncached];
7081 
7082  // start draw command buffer, it not yet done
7083  beginDrawCommandBuffer(currentContext.idx);
7084 
7085  // render pass
7086  startRenderPass(currentContext.idx);
7087 
7088  // lines
7089  setupLinesRenderingPipeline(currentContext.idx, currentContext.program);
7090 
7091  // do lines render command
7092  auto shaderIdx = 0;
7093  auto uboIdx = 0;
7094  auto samplerIdx = 0;
7095  for (auto shader: currentContext.program->shaders) {
7096  // sampler2D + samplerCube
7097  for (auto uniform: shader->samplerUniformList) {
7098  if (uniform->textureUnit == -1) {
7099  switch(uniform->type) {
7101  currentContext.descriptorImageInfos[samplerIdx] = {
7103  .imageView = whiteTextureSampler2dDefault->view,
7104  .imageLayout = whiteTextureSampler2dDefault->vkLayout
7105  };
7106  break;
7108  currentContext.descriptorImageInfos[samplerIdx] = {
7110  .imageView = whiteTextureSamplerCubeDefault->view,
7112  };
7113  break;
7114  default:
7115  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
7116  break;
7117  }
7118  } else {
7119  auto& texture = currentContext.boundTextures[uniform->textureUnit];
7120  if (texture.view == VK_NULL_HANDLE) {
7121  switch(uniform->type) {
7123  currentContext.descriptorImageInfos[samplerIdx] = {
7125  .imageView = whiteTextureSampler2dDefault->view,
7126  .imageLayout = whiteTextureSampler2dDefault->vkLayout
7127  };
7128  break;
7130  currentContext.descriptorImageInfos[samplerIdx] = {
7132  .imageView = whiteTextureSamplerCubeDefault->view,
7134  };
7135  break;
7136  default:
7137  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): object command: unknown sampler: " + to_string(uniform->type));
7138  break;
7139  }
7140  } else {
7141  currentContext.descriptorImageInfos[samplerIdx] = {
7142  .sampler = texture.sampler,
7143  .imageView = texture.view,
7144  .imageLayout = texture.layout
7145  };
7146  }
7147  }
7148  currentContext.descriptorWriteSets[uniform->position] = {
7149  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
7150  .pNext = nullptr,
7151  .dstSet = textureDescriptorSet,
7152  .dstBinding = static_cast<uint32_t>(uniform->position),
7153  .dstArrayElement = 0,
7154  .descriptorCount = 1,
7155  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
7156  .pImageInfo = &currentContext.descriptorImageInfos[samplerIdx],
7157  .pBufferInfo = VK_NULL_HANDLE,
7158  .pTexelBufferView = VK_NULL_HANDLE
7159  };
7160  samplerIdx++;
7161  }
7162 
7163  // uniform buffer
7164  if (shader->uboBindingIdx == -1) {
7165  shaderIdx++;
7166  continue;
7167  }
7168 
7169  //
7170  auto& uniformBuffer = shader->uniformBuffers[currentContext.idx];
7171  auto& src = uniformBuffer.buffers[uniformBuffer.bufferIdx];
7172  auto uboBuffer = src.buffer;
7173  uniformBuffer.bufferIdx = (uniformBuffer.bufferIdx + 1) % uniformBuffer.buffers.size();
7174  vmaMemCpy(src.allocation, uniformBuffer.uniformBufferData.data(), uniformBuffer.size);
7175 
7176  //
7177  currentContext.descriptorBufferInfos[shader->uboBindingIdx] = {
7178  .buffer = uboBuffer,
7179  .offset = 0,
7180  .range = shader->uboSize
7181  };
7182 
7183  //
7184  currentContext.descriptorWriteSets[shader->uboBindingIdx] = {
7185  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
7186  .pNext = nullptr,
7187  .dstSet = uboDescriptorSet,
7188  .dstBinding = static_cast<uint32_t>(shader->uboBindingIdx),
7189  .dstArrayElement = 0,
7190  .descriptorCount = 1,
7191  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
7192  .pImageInfo = nullptr,
7193  .pBufferInfo = &currentContext.descriptorBufferInfos[shader->uboBindingIdx],
7194  .pTexelBufferView = nullptr
7195  };
7196 
7197  //
7198  shaderIdx++;
7199  uboIdx++;
7200  }
7201 
7202  //
7203  vkUpdateDescriptorSets(device, currentContext.program->layoutBindings, currentContext.descriptorWriteSets.data(), 0, nullptr);
7204 
7205  //
7206  auto& drawCommand = currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand;
7207  array<VkDescriptorSet, 2> descriptorSets { uboDescriptorSet, textureDescriptorSet };
7208  vkCmdBindDescriptorSets(drawCommand, VK_PIPELINE_BIND_POINT_GRAPHICS, currentContext.program->pipelineLayout, 0, descriptorSets.size(), descriptorSets.data(), 0, nullptr);
7209  vkCmdBindVertexBuffers(drawCommand, 0, LINES_VERTEX_BUFFER_COUNT, currentContext.boundBuffers.data(), currentContext.boundBufferOffsets.data());
7210  vkCmdSetLineWidth(drawCommand, lineWidth);
7211  vkCmdDraw(drawCommand, points, 1, pointsOffset, 0);
7212 
7213  //
7214  programCommandBuffer.uboDescriptorSetsIdx = (programCommandBuffer.uboDescriptorSetsIdx + 1) % programCommandBuffer.uboDescriptorSets.size();
7215  programCommandBuffer.texturesDescriptorSetsIdxUncached = (programCommandBuffer.texturesDescriptorSetsIdxUncached + 1) % programCommandBuffer.texturesDescriptorSetsUncached.size();
7216  currentContext.commandCount++;
7217 
7218  //
7219  requestSubmitDrawBuffers(currentContext.idx);
7220 
7221  //
7222  AtomicOperations::increment(statistics.renderCalls);
7223  AtomicOperations::increment(statistics.linePoints, points);
7224 }
7225 
7227 {
7228  auto& currentContext = contexts[contextIdx];
7229  uint32_t bufferSize = 0;
7230  auto defaultBuffer = getBindBufferObjectInternal(emptyVertexBufferId, bufferSize);
7231  currentContext.boundIndicesBuffer = VK_NULL_HANDLE;
7232  currentContext.boundBuffers.fill(defaultBuffer);
7233  currentContext.boundBufferSizes.fill(bufferSize);
7234 }
7235 
7236 void VKRenderer::disposeBufferObjects(vector<int32_t>& bufferObjectIds)
7237 {
7238  disposeMutex.lock();
7239  for (auto bufferObjectId: bufferObjectIds) {
7240  disposeBuffers.push_back(bufferObjectId);
7241  }
7242  disposeMutex.unlock();
7243 }
7244 
7245 int32_t VKRenderer::getTextureUnit(int contextIdx)
7246 {
7247  return contexts[contextIdx].activeTextureUnit;
7248 }
7249 
7250 void VKRenderer::setTextureUnit(int contextIdx, int32_t textureUnit)
7251 {
7252  contexts[contextIdx].activeTextureUnit = textureUnit;
7253 }
7254 
7255 float VKRenderer::readPixelDepth(int32_t x, int32_t y)
7256 {
7257  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
7258 
7259  //
7260  auto pixelDepth = -1.0f;
7261 
7262  // determine image to read
7263  VkFormat usedFormat = VK_FORMAT_UNDEFINED;
7264  VkImage usedImage = VK_NULL_HANDLE;
7265  uint32_t usedWidth = 0;
7266  uint32_t usedHeight = -1;
7267  array<ThsvsAccessType, 2> usedAccessTypes;
7268  ThsvsImageLayout usedImageLayout = THSVS_IMAGE_LAYOUT_OPTIMAL;
7269  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
7270  if (frameBuffer == nullptr) {
7271  auto depthBufferTexture = getTextureInternal(depthBufferDefault);
7272  if (depthBufferTexture == nullptr) {
7273  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): depth buffer: depth buffer texture not found: " + to_string(depthBufferDefault));
7274  return pixelDepth;
7275  }
7276  usedFormat = depthBufferTexture->format;
7277  usedImage = depthBufferTexture->image;
7278  usedWidth = depthBufferTexture->width;
7279  usedHeight = depthBufferTexture->height;
7280  usedAccessTypes = depthBufferTexture->accessTypes[0];
7281  usedImageLayout = depthBufferTexture->svsLayout;
7282  } else {
7283  auto depthBufferTexture = getTextureInternal(frameBuffer->depthBufferTextureId);
7284  if (depthBufferTexture == nullptr) {
7285  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): depth buffer: depth buffer texture not found: " + to_string(frameBuffer->depthBufferTextureId));
7286  return pixelDepth;
7287  } else {
7288  usedFormat = depthBufferTexture->format;
7289  usedImage = depthBufferTexture->image;
7290  usedWidth = depthBufferTexture->width;
7291  usedHeight = depthBufferTexture->height;
7292  usedAccessTypes = depthBufferTexture->accessTypes[0];
7293  usedImageLayout = depthBufferTexture->svsLayout;
7294  }
7295  }
7296 
7297  //
7298  vmaSpinlock.lock();
7299 
7300  //
7301  VmaAllocationInfo allocationInfo = {};
7302  VkBuffer buffer = VK_NULL_HANDLE;
7303  VmaAllocation allocation = VK_NULL_HANDLE;
7304  createBuffer(
7305  4,
7306  VK_BUFFER_USAGE_TRANSFER_DST_BIT,
7307  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
7308  buffer,
7309  allocation,
7310  allocationInfo
7311  );
7312  VkMemoryPropertyFlags memoryFlags;
7313  vmaGetMemoryTypeProperties(vmaAllocator, allocationInfo.memoryType, &memoryFlags);
7314  auto memoryMapped = (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
7315  if (memoryMapped == false) {
7316  vmaSpinlock.unlock();
7317  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): Could not create memory mappable buffer");
7318  return pixelDepth;
7319  }
7320 
7321  // set source image layout
7322  auto& currentContext = contexts[CONTEXTINDEX_DEFAULT];
7323  {
7324  // set SRC
7325  array<ThsvsAccessType, 2> nextAccessTypes = { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE };
7326  setImageLayout3(currentContext.idx, usedImage, VK_IMAGE_ASPECT_DEPTH_BIT, usedAccessTypes, nextAccessTypes, usedImageLayout, THSVS_IMAGE_LAYOUT_OPTIMAL);
7327  }
7328 
7329  VkBufferImageCopy bufferImageCopy = {
7330  .bufferOffset = 0,
7331  .bufferRowLength = 0,
7332  .bufferImageHeight = 0,
7333  .imageSubresource = {
7334  .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
7335  .mipLevel = 0,
7336  .baseArrayLayer = 0,
7337  .layerCount = 1
7338  },
7339  .imageOffset = {
7340  .x = static_cast<int32_t>(x),
7341  .y = static_cast<int32_t>(usedHeight - 1 - y),
7342  .z = 0
7343  },
7344  .imageExtent = {
7345  .width = 1,
7346  .height = 1,
7347  .depth = 1
7348  },
7349  };
7350 
7351  // copy image to buffer
7352  prepareSetupCommandBuffer(currentContext.idx);
7353  vkCmdCopyImageToBuffer(
7354  currentContext.setupCommandInUse,
7355  usedImage,
7356  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
7357  buffer,
7358  1,
7359  &bufferImageCopy
7360  );
7361  finishSetupCommandBuffer(currentContext.idx);
7362 
7363  //
7364  void* data;
7365  VkResult err;
7366  err = vmaMapMemory(vmaAllocator, allocation, &data);
7367  assert(!err);
7368  pixelDepth = static_cast<float*>(data)[0];
7369  vmaUnmapMemory(vmaAllocator, allocation);
7370 
7371  //
7372  vmaSpinlock.unlock();
7373 
7374  {
7375  // unset SRC
7376  array<ThsvsAccessType, 2> lastAccessTypes = { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE };
7377  setImageLayout3(currentContext.idx, usedImage, VK_IMAGE_ASPECT_DEPTH_BIT, lastAccessTypes, usedAccessTypes, THSVS_IMAGE_LAYOUT_OPTIMAL, usedImageLayout);
7378  }
7379 
7380  // mark buffer for deletion
7381  deleteMutex.lock();
7382  deleteBuffers.emplace_back(
7383  buffer,
7384  allocation
7385  );
7386  deleteMutex.unlock();
7387 
7388  //
7389  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(pixelDepth));
7390 
7391  //
7392  return pixelDepth;
7393 }
7394 
7395 ByteBuffer* VKRenderer::readPixels(int32_t x, int32_t y, int32_t width, int32_t height)
7396 {
7397  if (VERBOSE == true) Console::println("VKRenderer::" + string(__FUNCTION__) + "()");
7398 
7399  // determine image to read
7400  VkFormat usedFormat = VK_FORMAT_UNDEFINED;
7401  VkImage usedImage = VK_NULL_HANDLE;
7402  uint32_t usedWidth = 0;
7403  uint32_t usedHeight = -1;
7404  array<ThsvsAccessType, 2> usedAccessTypes;
7405  ThsvsImageLayout usedImageLayout = THSVS_IMAGE_LAYOUT_OPTIMAL;
7406  auto frameBuffer = boundFrameBufferId < 0 || boundFrameBufferId >= framebuffers.size()?nullptr:framebuffers[boundFrameBufferId];
7407  if (frameBuffer == nullptr) {
7408  auto& swapchainBuffer = windowFramebufferBuffers[lastWindowFramebufferIdx];
7409  usedFormat = windowFormat;
7410  usedImage = swapchainBuffer.image;
7411  usedWidth = swapchainBuffer.width;
7412  usedHeight = swapchainBuffer.height;
7413  usedAccessTypes = swapchainBuffer.accessTypes;
7414  usedImageLayout = swapchainBuffer.svsLayout;
7415  } else {
7416  auto colorBufferTexture = getTextureInternal(frameBuffer->colorTextureId);
7417  if (colorBufferTexture == nullptr) {
7418  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): color buffer: color buffer texture not found: " + to_string(frameBuffer->colorTextureId));
7419  return nullptr;
7420  } else {
7421  usedFormat = colorBufferTexture->format;
7422  usedImage = colorBufferTexture->image;
7423  usedWidth = colorBufferTexture->width;
7424  usedHeight = colorBufferTexture->height;
7425  usedAccessTypes = colorBufferTexture->accessTypes[0];
7426  usedImageLayout = colorBufferTexture->svsLayout;
7427  }
7428  }
7429 
7430  //
7431  VkImage image = VK_NULL_HANDLE;
7432  VmaAllocation allocation = VK_NULL_HANDLE;
7433 
7434  //
7435  const VkImageCreateInfo imageCreateInfo = {
7436  .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
7437  .pNext = nullptr,
7438  .flags = 0,
7439  .imageType = VK_IMAGE_TYPE_2D,
7440  .format = usedFormat,
7441  .extent = {
7442  .width = static_cast<uint32_t>(width),
7443  .height = static_cast<uint32_t>(height),
7444  .depth = 1
7445  },
7446  .mipLevels = 1,
7447  .arrayLayers = 1,
7448  .samples = VK_SAMPLE_COUNT_1_BIT,
7449  .tiling = VK_IMAGE_TILING_LINEAR,
7450  .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
7451  .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
7452  .queueFamilyIndexCount = 0,
7453  .pQueueFamilyIndices = 0,
7454  .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
7455  };
7456 
7457  VmaAllocationCreateInfo imageAllocCreateInfo = {};
7458  imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_UNKNOWN;
7459  imageAllocCreateInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
7460 
7461  VmaAllocationInfo allocationInfo = {};
7462 
7463  VkResult err;
7464  err = vmaCreateImage(vmaAllocator, &imageCreateInfo, &imageAllocCreateInfo, &image, &allocation, &allocationInfo);
7465  assert(!err);
7466 
7467  VkImageCopy imageCopy = {
7468  .srcSubresource = {
7469  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
7470  .mipLevel = 0,
7471  .baseArrayLayer = 0,
7472  .layerCount = 1
7473  },
7474  .srcOffset = {
7475  .x = x,
7476  .y = y,
7477  .z = 0
7478  },
7479  .dstSubresource = {
7480  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
7481  .mipLevel = 0,
7482  .baseArrayLayer = 0,
7483  .layerCount = 1
7484  },
7485  .dstOffset = {
7486  .x = 0,
7487  .y = 0,
7488  .z = 0
7489  },
7490  .extent = {
7491  .width = static_cast<uint32_t>(width),
7492  .height = static_cast<uint32_t>(height),
7493  .depth = 1
7494  }
7495  };
7496  auto& currentContext = contexts[CONTEXTINDEX_DEFAULT];
7497  {
7498  // set SRC
7499  array<ThsvsAccessType, 2> nextAccessTypes = { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE };
7500  setImageLayout3(currentContext.idx, usedImage, VK_IMAGE_ASPECT_COLOR_BIT, usedAccessTypes, nextAccessTypes, usedImageLayout, THSVS_IMAGE_LAYOUT_OPTIMAL);
7501  }
7502  {
7503  // set DST
7504  array<ThsvsAccessType, 2> accessTypes = { THSVS_ACCESS_HOST_PREINITIALIZED, THSVS_ACCESS_NONE };
7505  array<ThsvsAccessType, 2> nextAccessTypes = { THSVS_ACCESS_TRANSFER_WRITE, THSVS_ACCESS_NONE };
7506  setImageLayout3(currentContext.idx, image, VK_IMAGE_ASPECT_COLOR_BIT, accessTypes, nextAccessTypes, THSVS_IMAGE_LAYOUT_OPTIMAL, THSVS_IMAGE_LAYOUT_OPTIMAL);
7507  }
7508 
7509  prepareSetupCommandBuffer(currentContext.idx);
7510  vkCmdCopyImage(
7511  currentContext.setupCommandInUse,
7512  usedImage,
7513  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
7514  image,
7515  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
7516  1,
7517  &imageCopy
7518  );
7519  finishSetupCommandBuffer(currentContext.idx);
7520 
7521  const VkImageSubresource imageSubResource = {
7522  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
7523  .mipLevel = 0,
7524  .arrayLayer = 0,
7525  };
7526  VkSubresourceLayout subResourceLayout;
7527  vkGetImageSubresourceLayout(device, image, &imageSubResource, &subResourceLayout);
7528 
7529  //
7530  vmaSpinlock.lock();
7531 
7532  //
7533  void* data;
7534  err = vmaMapMemory(vmaAllocator, allocation, &data);
7535  assert(!err);
7536  auto pixelBuffer = ByteBuffer::allocate(width * height * 4);
7537  for (int y = height - 1; y >= 0; y--) {
7538  auto row = static_cast<uint8_t*>(static_cast<uint8_t*>(data) + subResourceLayout.offset + subResourceLayout.rowPitch * y);
7539  for (auto x = 0; x < width; x++) {
7540  pixelBuffer->put(static_cast<uint8_t>(row[x * 4 + 2])); // b
7541  pixelBuffer->put(static_cast<uint8_t>(row[x * 4 + 1])); // g
7542  pixelBuffer->put(static_cast<uint8_t>(row[x * 4 + 0])); // r
7543  pixelBuffer->put(static_cast<uint8_t>(row[x * 4 + 3])); // a
7544  }
7545  }
7546  vmaUnmapMemory(vmaAllocator, allocation);
7547 
7548  //
7549  vmaSpinlock.unlock();
7550 
7551  {
7552  // unset SRC
7553  array<ThsvsAccessType, 2> lastAccessTypes = { THSVS_ACCESS_TRANSFER_READ, THSVS_ACCESS_NONE };
7554  setImageLayout3(currentContext.idx, usedImage, VK_IMAGE_ASPECT_COLOR_BIT, lastAccessTypes, usedAccessTypes, THSVS_IMAGE_LAYOUT_OPTIMAL, usedImageLayout);
7555  }
7556 
7557  // mark for deletion
7558  deleteMutex.lock();
7559  deleteImages.emplace_back(
7560  image,
7561  allocation,
7562  VK_NULL_HANDLE,
7563  VK_NULL_HANDLE
7564  );
7565  deleteMutex.unlock();
7566 
7567  //
7568  return pixelBuffer;
7569 }
7570 
7572 {
7573  enableBlending();
7574  disableCulling(0);
7577 }
7578 
7580 {
7583  enableCulling(0);
7584  disableBlending();
7585 }
7586 
7587 void VKRenderer::dispatchCompute(int contextIdx, int32_t numGroupsX, int32_t numGroupsY, int32_t numGroupsZ) {
7588  // have our context typed
7589  auto& currentContext = contexts[contextIdx];
7590  auto& programCommandBuffer = currentContext.program->contexts[currentContext.idx].commandBuffers[currentContext.currentCommandBuffer];
7591 
7592  //
7593  auto uboDescriptorSet = programCommandBuffer.uboDescriptorSets[programCommandBuffer.uboDescriptorSetsIdx];
7594 
7595  // start draw command buffer, it not yet done
7596  beginDrawCommandBuffer(currentContext.idx);
7597  // render pass
7598  endRenderPass(currentContext.idx);
7599  // pipeline
7600  setupSkinningComputingPipeline(currentContext.idx, currentContext.program);
7601 
7602  // do compute command
7603  auto shaderIdx = 0;
7604  for (auto shader: currentContext.program->shaders) {
7605  for (int i = 0; i <= shader->maxBindings; i++) {
7606  currentContext.descriptorBufferInfos[i] = {
7607  .buffer = currentContext.boundBuffers[i],
7608  .offset = 0,
7609  .range = currentContext.boundBufferSizes[i]
7610  };
7611  currentContext.descriptorWriteSets[i] = {
7612  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
7613  .pNext = nullptr,
7614  .dstSet = uboDescriptorSet,
7615  .dstBinding = static_cast<uint32_t>(i),
7616  .dstArrayElement = 0,
7617  .descriptorCount = 1,
7618  .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
7619  .pImageInfo = nullptr,
7620  .pBufferInfo = &currentContext.descriptorBufferInfos[i],
7621  .pTexelBufferView = nullptr
7622  };
7623  }
7624 
7625  // uniform buffer
7626  if (shader->uboBindingIdx == -1) {
7627  shaderIdx++;
7628  continue;
7629  }
7630 
7631  //
7632  //
7633  auto& uniformBuffer = shader->uniformBuffers[currentContext.idx];
7634  auto& src = uniformBuffer.buffers[uniformBuffer.bufferIdx];
7635  auto uboBuffer = src.buffer;
7636  uniformBuffer.bufferIdx = (uniformBuffer.bufferIdx + 1) % uniformBuffer.buffers.size();
7637  vmaMemCpy(src.allocation, uniformBuffer.uniformBufferData.data(), uniformBuffer.size);
7638 
7639  //
7640  currentContext.descriptorBufferInfos[shader->uboBindingIdx] = {
7641  .buffer = uboBuffer,
7642  .offset = 0,
7643  .range = shader->uboSize
7644  };
7645 
7646  //
7647  currentContext.descriptorWriteSets[shader->uboBindingIdx] = {
7648  .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
7649  .pNext = nullptr,
7650  .dstSet = uboDescriptorSet,
7651  .dstBinding = static_cast<uint32_t>(shader->uboBindingIdx),
7652  .dstArrayElement = 0,
7653  .descriptorCount = 1,
7654  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
7655  .pImageInfo = nullptr,
7656  .pBufferInfo = &currentContext.descriptorBufferInfos[shader->uboBindingIdx],
7657  .pTexelBufferView = nullptr,
7658  };
7659 
7660  //
7661  shaderIdx++;
7662  }
7663 
7664  //
7665  vkUpdateDescriptorSets(device, currentContext.program->layoutBindings, currentContext.descriptorWriteSets.data(), 0, nullptr);
7666 
7667  //
7668  auto& drawCommand = currentContext.commandBuffers[currentContext.currentCommandBuffer].drawCommand;
7669  vkCmdBindDescriptorSets(drawCommand, VK_PIPELINE_BIND_POINT_COMPUTE, currentContext.program->pipelineLayout, 0, 1, &uboDescriptorSet, 0, nullptr);
7670  vkCmdDispatch(drawCommand, numGroupsX, numGroupsY, numGroupsZ);
7671 
7672  //
7673  programCommandBuffer.uboDescriptorSetsIdx = (programCommandBuffer.uboDescriptorSetsIdx + 1) % programCommandBuffer.uboDescriptorSets.size();
7674  currentContext.commandCount++;
7675 
7676  //
7677  requestSubmitDrawBuffers(currentContext.idx);
7678 
7679  //
7680  AtomicOperations::increment(statistics.computeCalls);
7681 }
7682 
7684  //
7686 
7687  //
7688  VkResult fenceResult;
7689  do {
7690  fenceResult = vkWaitForFences(device, contextsDrawFences.size(), contextsDrawFences.data(), VK_TRUE, 100000000);
7691  } while (fenceResult == VK_TIMEOUT);
7692 
7693  //
7694  for (auto& context: contexts) context.computeRenderBarrierBuffers.clear();
7695 
7696  //
7698 }
7699 
7701  VkResult err;
7702 
7703  // TODO: pass multiple buffer barriers to vkCmdPipelineBarrier
7704  //
7705  auto prevAccesses = THSVS_ACCESS_COMPUTE_SHADER_WRITE;
7706  auto nextAccesses = THSVS_ACCESS_VERTEX_BUFFER;
7707  for (auto& context: contexts) {
7708  for (auto buffer: context.computeRenderBarrierBuffers) {
7709  ThsvsBufferBarrier svsBufferBarrier = {
7710  .prevAccessCount = 1,
7711  .pPrevAccesses = &prevAccesses,
7712  .nextAccessCount = 1,
7713  .pNextAccesses = &nextAccesses,
7714  .srcQueueFamilyIndex = 0,
7715  .dstQueueFamilyIndex = 0,
7716  .buffer = buffer,
7717  .offset = 0,
7718  .size = VK_WHOLE_SIZE
7719  };
7720  VkBufferMemoryBarrier vkBufferMemoryBarrier;
7721  VkPipelineStageFlags srcStages;
7722  VkPipelineStageFlags dstStages;
7723  thsvsGetVulkanBufferMemoryBarrier(
7724  svsBufferBarrier,
7725  &srcStages,
7726  &dstStages,
7727  &vkBufferMemoryBarrier
7728  );
7729  prepareSetupCommandBuffer(context.idx);
7730  vkCmdPipelineBarrier(context.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 1, &vkBufferMemoryBarrier, 0, nullptr);
7731  finishSetupCommandBuffer(context.idx);
7732  }
7733  context.computeRenderBarrierBuffers.clear();
7734  }
7735 }
7736 
7737 void VKRenderer::uploadSkinningBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer* data) {
7738  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
7739 }
7740 
7741 void VKRenderer::uploadSkinningBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, IntBuffer* data) {
7742  auto& currentContext = contexts[contextIdx];
7743  uploadBufferObjectInternal(contextIdx, bufferObjectId, size, data->getBuffer(), (VkBufferUsageFlagBits)(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
7744 }
7745 
7746 void VKRenderer::bindSkinningVerticesBufferObject(int contextIdx, int32_t bufferObjectId) {
7747  auto& currentContext = contexts[contextIdx];
7748  currentContext.boundBuffers[0] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[0]);
7749 }
7750 
7751 void VKRenderer::bindSkinningNormalsBufferObject(int contextIdx, int32_t bufferObjectId) {
7752  auto& currentContext = contexts[contextIdx];
7753  currentContext.boundBuffers[1] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[1]);
7754 }
7755 
7756 void VKRenderer::bindSkinningVertexJointsBufferObject(int contextIdx, int32_t bufferObjectId) {
7757  auto& currentContext = contexts[contextIdx];
7758  currentContext.boundBuffers[2] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[2]);
7759 }
7760 
7761 void VKRenderer::bindSkinningVertexJointIdxsBufferObject(int contextIdx, int32_t bufferObjectId) {
7762  auto& currentContext = contexts[contextIdx];
7763  currentContext.boundBuffers[3] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[3]);
7764 }
7765 
7766 void VKRenderer::bindSkinningVertexJointWeightsBufferObject(int contextIdx, int32_t bufferObjectId) {
7767  auto& currentContext = contexts[contextIdx];
7768  currentContext.boundBuffers[4] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[4]);
7769 }
7770 
7771 void VKRenderer::bindSkinningVerticesResultBufferObject(int contextIdx, int32_t bufferObjectId) {
7772  auto& currentContext = contexts[contextIdx];
7773  currentContext.boundBuffers[5] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[5]);
7774  currentContext.computeRenderBarrierBuffers.push_back(currentContext.boundBuffers[5]);
7775  //
7776  auto prevAccesses = THSVS_ACCESS_VERTEX_BUFFER;
7777  auto nextAccesses = THSVS_ACCESS_COMPUTE_SHADER_WRITE;
7778  ThsvsBufferBarrier svsbufferBarrier = {
7779  .prevAccessCount = 1,
7780  .pPrevAccesses = &prevAccesses,
7781  .nextAccessCount = 1,
7782  .pNextAccesses = &nextAccesses,
7783  .srcQueueFamilyIndex = 0,
7784  .dstQueueFamilyIndex = 0,
7785  .buffer = currentContext.boundBuffers[5],
7786  .offset = 0,
7787  .size = VK_WHOLE_SIZE
7788  };
7789  VkBufferMemoryBarrier vkBufferMemoryBarrier;
7790  VkPipelineStageFlags srcStages;
7791  VkPipelineStageFlags dstStages;
7792  thsvsGetVulkanBufferMemoryBarrier(
7793  svsbufferBarrier,
7794  &srcStages,
7795  &dstStages,
7796  &vkBufferMemoryBarrier
7797  );
7798  prepareSetupCommandBuffer(currentContext.idx);
7799  vkCmdPipelineBarrier(currentContext.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 1, &vkBufferMemoryBarrier, 0, nullptr);
7800  finishSetupCommandBuffer(currentContext.idx);
7801 }
7802 
7803 void VKRenderer::bindSkinningNormalsResultBufferObject(int contextIdx, int32_t bufferObjectId) {
7804  auto& currentContext = contexts[contextIdx];
7805  currentContext.boundBuffers[6] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[6]);
7806  currentContext.computeRenderBarrierBuffers.push_back(currentContext.boundBuffers[6]);
7807  auto prevAccesses = THSVS_ACCESS_VERTEX_BUFFER;
7808  auto nextAccesses = THSVS_ACCESS_COMPUTE_SHADER_WRITE;
7809  ThsvsBufferBarrier svsbufferBarrier = {
7810  .prevAccessCount = 1,
7811  .pPrevAccesses = &prevAccesses,
7812  .nextAccessCount = 1,
7813  .pNextAccesses = &nextAccesses,
7814  .srcQueueFamilyIndex = 0,
7815  .dstQueueFamilyIndex = 0,
7816  .buffer = currentContext.boundBuffers[6],
7817  .offset = 0,
7818  .size = VK_WHOLE_SIZE
7819  };
7820  VkBufferMemoryBarrier vkBufferMemoryBarrier;
7821  VkPipelineStageFlags srcStages;
7822  VkPipelineStageFlags dstStages;
7823  thsvsGetVulkanBufferMemoryBarrier(
7824  svsbufferBarrier,
7825  &srcStages,
7826  &dstStages,
7827  &vkBufferMemoryBarrier
7828  );
7829  prepareSetupCommandBuffer(currentContext.idx);
7830  vkCmdPipelineBarrier(currentContext.setupCommandInUse, srcStages, dstStages, 0, 0, nullptr, 1, &vkBufferMemoryBarrier, 0, nullptr);
7831  finishSetupCommandBuffer(currentContext.idx);
7832 }
7833 
7834 void VKRenderer::bindSkinningMatricesBufferObject(int contextIdx, int32_t bufferObjectId) {
7835  auto& currentContext = contexts[contextIdx];
7836  currentContext.boundBuffers[7] = getBindBufferObjectInternal(bufferObjectId, currentContext.boundBufferSizes[7]);
7837 }
7838 
7839 void VKRenderer::setVSync(bool vSync) {
7840  Console::println("VKRenderer::" + string(__FUNCTION__) + "(): " + to_string(this->vSync) + " --> " + to_string(vSync));
7841  if (this->vSync == vSync) return;
7842  swapchainPresentMode = vSync == true?VK_PRESENT_MODE_FIFO_KHR:VK_PRESENT_MODE_IMMEDIATE_KHR;
7843  this->vSync = vSync;
7844 }
7845 
7847  array<VmaBudget, VK_MAX_MEMORY_HEAPS> budget;
7848  vmaGetBudget(vmaAllocator, budget.data());
7849  auto stats = statistics;
7850  stats.memoryUsageGPU = budget[0].allocationBytes;
7851  stats.memoryUsageShared = budget[1].allocationBytes;
7852  statistics.time = Time::getCurrentMillis();
7853  statistics.memoryUsageGPU = -1LL;
7855  statistics.clearCalls = 0;
7856  statistics.renderCalls = 0;
7857  statistics.instances = 0;
7859  statistics.triangles = 0;
7860  statistics.points = 0;
7861  statistics.linePoints = 0;
7866  statistics.submits = 0;
7869  return stats;
7870 }
#define ARRAY_SIZE(a)
Definition: VKRenderer.cpp:77
#define ERR_EXIT(err_msg, err_class)
Definition: VKRenderer.cpp:78
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint)
Definition: VKRenderer.cpp:84
#define GET_DEVICE_PROC_ADDR(dev, entrypoint)
Definition: VKRenderer.cpp:92
#define TEXTUREDESCRIPTORSET_MAX_TEXTURES
Definition: VKRenderer.h:61
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:41
Engine main class.
Definition: Engine.h:131
void reshape(int32_t width, int32_t height)
Reshape.
Definition: Engine.cpp:972
static Engine * getInstance()
Returns engine instance.
Definition: Engine.h:612
static TextureManager * getTextureManager()
Definition: Engine.h:627
static int getThreadCount()
Definition: Engine.h:670
TDME2 engine entity shader parameters.
Frame buffer class.
Definition: FrameBuffer.h:22
Texture entity.
Definition: Texture.h:24
TextureFilter getMinFilter() const
Definition: Texture.h:339
const vector< MipMapTexture > & getMipMapTextures(bool bc7Encoded)
Get mip map textures.
Definition: Texture.cpp:286
bool isRepeat() const
Definition: Texture.h:309
ByteBuffer getRGBTextureData()
Definition: Texture.h:253
bool isUseMipMap() const
Definition: Texture.h:294
uint8_t getRGBDepthBitsPerPixel() const
Definition: Texture.h:186
const string & getId() const
Definition: Texture.h:172
ByteBuffer getBC7TextureData()
Definition: Texture.cpp:140
uint16_t getTextureHeight() const
Definition: Texture.h:211
TextureFilter getMagFilter() const
Definition: Texture.h:354
uint16_t getTextureWidth() const
Definition: Texture.h:218
ClampMode getClampMode() const
Definition: Texture.h:324
@ TEXTUREFILTER_LINEAR_MIPMAP_LINEAR
Definition: Texture.h:49
@ TEXTUREFILTER_LINEAR_MIPMAP_NEAREST
Definition: Texture.h:47
@ TEXTUREFILTER_NEAREST_MIPMAP_NEAREST
Definition: Texture.h:46
@ TEXTUREFILTER_NEAREST_MIPMAP_LINEAR
Definition: Texture.h:48
bool isUseCompression() const
Definition: Texture.h:279
Timing class.
Definition: Timing.h:16
int32_t addCubeMapTexture(const string &id, Texture *textureLeft, Texture *textureRight, Texture *textureTop, Texture *textureBottom, Texture *textureFront, Texture *textureBack, int contextIdx=0)
Adds a cube map texture to manager.
TextureManager_TextureManaged * addTexture(const string &id, bool &created)
Adds a texture to manager.
vector< Renderer_Context > rendererContexts
Definition: Renderer.h:192
virtual void onBindTexture(int contextIdx, int32_t textureId)=0
On bind texture event.
static void loadShader(VKRenderer::shader_type &shader, int32_t type, const string &pathName, const string &fileName, const string &definitions=string(), const string &functions=string())
Loads a shader.
static bool linkProgram(VKRenderer::program_type &program)
Links attached shaders to a program.
void setClearColor(float red, float green, float blue, float alpha) override
Set up clear color.
void prepareTextureImage(int contextIdx, struct texture_type *textureObject, VkImageTiling tiling, VkImageUsageFlags usage, VkFlags requiredFlags, Texture *texture, const array< ThsvsAccessType, 2 > &nextAccesses, ThsvsImageLayout imageLayout, bool disableMipMaps=true, uint32_t baseLevel=0, uint32_t levelCount=1)
Definition: VKRenderer.cpp:662
void enableDepthBufferWriting() override
Enable depth buffer writing.
void bindSpriteSheetDimensionBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind sprite sheet dimension buffer object.
void bindTexture(int contextIdx, int32_t textureId) override
Binds a texture with given id or unbinds when using ID_NONE.
void clear(int32_t mask) override
Clear render buffer with given mask.
void createSkinningComputingProgram(program_type *program)
void bindTangentsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind tangents buffer object.
void disposeBufferObjects(vector< int32_t > &bufferObjectIds) override
Disposes a frame buffer object.
int32_t getTextureUnit(int contextIdx) override
Get texture unit.
void setProgramUniformFloatMatrix3x3(int contextIdx, int32_t uniformId, const array< float, 9 > &data) override
Set up a float matrix 3x3 uniform value.
VkPhysicalDeviceProperties gpuProperties
Definition: VKRenderer.h:400
void doneGuiMode() override
Set up renderer for 3d rendering.
void setColorMask(bool red, bool green, bool blue, bool alpha) override
Set up GL rendering colormask.
void bindTextureCoordinatesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind texture coordinates buffer object.
void submitDrawCommandBuffers(int commandBufferCount, VkCommandBuffer *commandBuffers, VkFence &fence)
Definition: VKRenderer.cpp:387
void setImageLayout2(int contextIdx, texture_type *textureObject, const array< ThsvsAccessType, 2 > &accessTypes, const array< ThsvsAccessType, 2 > &nextAccessTypes, ThsvsImageLayout layout, ThsvsImageLayout nextLayout, bool discardContent, uint32_t baseMipLevel, uint32_t levelCount, uint32_t baseArrayLayer, uint32_t layerCount, bool updateTextureObject)
Definition: VKRenderer.cpp:579
void bindSkinningVertexJointWeightsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning vertex joint weights buffer object.
vector< delete_buffer_type > deleteBuffers
Definition: VKRenderer.h:484
void attachShaderToProgram(int32_t programId, int32_t shaderId) override
Attaches a shader to a program.
void setupObjectsRenderingPipeline(int contextIdx, program_type *program)
void dispatchCompute(int contextIdx, int32_t numNodesX, int32_t numNodesY, int32_t numNodesZ) override
Dispatch compute.
void setFrontFace(int contextIdx, int32_t frontFace) override
Set up clock wise or counter clock wise faces as front face.
void setTextureUnit(int contextIdx, int32_t textureUnit) override
Sets up texture unit.
void drawLinesFromBufferObjects(int contextIdx, int32_t points, int32_t pointsOffset) override
Draw lines from buffer objects.
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VmaAllocation &allocation, VmaAllocationInfo &allocationInfo)
void createLinesRenderingPipeline(int contextIdx, program_type *program)
void disableBlending() override
Disables blending.
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR
Definition: VKRenderer.h:411
void setProgramAttributeLocation(int32_t programId, int32_t location, const string &name) override
Bind attribute to a input location.
VkBool32 checkLayers(uint32_t checkCount, const char **checkNames, const vector< VkLayerProperties > &instanceLayers)
Definition: VKRenderer.cpp:185
void setViewPort(int32_t width, int32_t height) override
Set up viewport parameter.
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR
Definition: VKRenderer.h:413
void bindSkinningVerticesResultBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning vertices result buffer object.
void setProgramUniformFloat(int contextIdx, int32_t uniformId, float value) override
Set up a float uniform value.
const Renderer_Statistics getStatistics() override
void uploadCubeMapSingleTexture(int contextIdx, texture_type *cubemapTextureType, Texture *texture, uint32_t baseArrayLayer)
void initialize() override
Initialize renderer.
void setVSync(bool vSync) override
Enable/Disable v-sync.
int32_t createGBufferColorTexture(int32_t width, int32_t height) override
Creates a geometry buffer color RGBA texture.
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR
Definition: VKRenderer.h:410
unordered_map< int32_t, shader_type * > shaders
Definition: VKRenderer.h:433
uint16_t createPipelineIndex(program_type *program, int contextIdx)
void setProgramUniformFloatVec3(int contextIdx, int32_t uniformId, const array< float, 3 > &data) override
Set up a float vec3 uniform value.
void disposeFrameBufferObject(int32_t frameBufferId) override
Disposes a frame buffer object.
void uploadBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer *data) override
Uploads buffer data to buffer object.
void uploadBufferObjectInternal(int contextIdx, buffer_object_type *buffer, int32_t size, const uint8_t *data, VkBufferUsageFlagBits usage)
void setProgramUniformInternal(int contextIdx, int32_t uniformId, uint8_t *data, int32_t size)
void memoryBarrier() override
Memory barrier.
void createBufferTexture(int32_t textureId, int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex, VkFormat format)
void setupSkinningComputingPipeline(int contextIdx, program_type *program)
void setProgramUniformInteger(int contextIdx, int32_t uniformId, int32_t value) override
Set up a integer uniform value.
int32_t getProgramUniformLocation(int32_t programId, const string &name) override
Returns location of given uniform variable.
void disableDepthBufferWriting() override
Disable depth buffer writing.
void createRenderProgram(program_type *program)
void setImageLayout(int contextIdx, texture_type *textureObject, const array< ThsvsAccessType, 2 > &nextAccessTypes, ThsvsImageLayout nextLayout, bool discardContent, uint32_t baseMipLevel=0, uint32_t levelCount=1, bool submit=true)
Definition: VKRenderer.cpp:419
void bindSkinningVertexJointIdxsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning vertex joint indices buffer object.
void applyImageLayoutChange(int contextIdx, const image_layout_change &imageLayoutChange, texture_type *textureObject, bool submit=true)
Definition: VKRenderer.cpp:522
void bindNormalsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind normals buffer object.
void drawPointsFromBufferObjects(int contextIdx, int32_t points, int32_t pointsOffset) override
Draw points from buffer objects.
void vmaMemCpy(VmaAllocation allocationDst, const uint8_t *src, uint32_t size, uint32_t offset=0)
void disposeTexture(int32_t textureId) override
Dispose a texture.
int32_t createColorBufferTexture(int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex) override
Creates a color buffer texture.
void disableCulling(int contextIdx) override
Disable culling.
VkBuffer getBindBufferObjectInternal(int32_t bufferObjectId, uint32_t &size)
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR
Definition: VKRenderer.h:407
void bindEffectColorMulsBufferObject(int contextIdx, int32_t bufferObjectId, int32_t divisor) override
Bind effect color muls buffer object.
int32_t createCubeMapTexture(int contextIdx, int32_t width, int32_t height) override
Create cube map texture from frame buffers.
void bindCubeMapTexture(int contextIdx, int32_t textureId) override
Binds a cube map texture with given id or unbinds when using ID_NONE.
framebuffer_pipelines_type * framebufferPipelinesCache
Definition: VKRenderer.h:424
void setProgramUniformFloatVec4(int contextIdx, int32_t uniformId, const array< float, 4 > &data) override
Set up a float vec4 uniform value.
void setDepthFunction(int32_t depthFunction) override
Set up depth function.
void uploadCubeMapTexture(int contextIdx, Texture *textureLeft, Texture *textureRight, Texture *textureTop, Texture *textureBottom, Texture *textureFront, Texture *textureBack) override
Uploads cube map texture data to current bound texture.
void bindFrameBuffer(int32_t frameBufferId) override
Enables a framebuffer to be rendered.
int32_t loadShader(int32_t type, const string &pathName, const string &fileName, const string &definitions=string(), const string &functions=string()) override
Loads a shader.
vector< framebuffer_pipelines_type * > framebuffersPipelines
Definition: VKRenderer.h:425
void createDepthStencilStateCreateInfo(VkPipelineDepthStencilStateCreateInfo &depthStencilStateCreateInfo)
void resizeDepthBufferTexture(int32_t textureId, int32_t width, int32_t height) override
Resizes a depth texture.
void resizeGBufferGeometryTexture(int32_t textureId, int32_t width, int32_t height) override
Resizes a geometry buffer geometry texture.
void finishFrame() override
Finish frame.
bool isInstancedRenderingAvailable() override
Checks if instanced rendering is available.
void drawTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset) override
Draw triangles from buffer objects.
void setupGUIRenderingPipeline(int contextIdx, program_type *program)
void createDepthBufferTexture(int32_t textureId, int32_t width, int32_t height, int32_t cubeMapTextureId, int32_t cubeMapTextureIndex)
void setImageLayout3(int contextIdx, VkImage image, VkImageAspectFlags aspectMask, const array< ThsvsAccessType, 2 > &accessTypes, const array< ThsvsAccessType, 2 > &nextAccessTypes, ThsvsImageLayout layout, ThsvsImageLayout nextLayout)
Definition: VKRenderer.cpp:623
void initGuiMode() override
Set up renderer for GUI rendering.
framebuffer_pipelines_type * createFramebufferPipelines(uint64_t framebufferPipelinesId)
void applyImageLayoutChanges(int contextIdx, const array< image_layout_change, 8 > imageLayoutChanges, array< texture_type *, 8 > textureObjects, bool submit=true)
Definition: VKRenderer.cpp:542
void bindSkinningVertexJointsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning vertex joints buffer object.
void setCullFace(int32_t cullFace) override
Sets up which face will be culled.
vector< int32_t > createBufferObjects(int32_t bufferCount, bool useGPUMemory, bool shared) override
Generate buffer objects for vertex data and such.
void enableBlending() override
Enables blending.
void setupPointsRenderingPipeline(int contextIdx, program_type *program)
static constexpr int COMPUTE_STORAGE_BUFFER_COUNT
Definition: VKRenderer.h:96
void setupLinesRenderingPipeline(int contextIdx, program_type *program)
void createObjectsRenderingPipeline(int contextIdx, program_type *program)
void uploadIndicesBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, ShortBuffer *data) override
Uploads buffer data to buffer object.
void drawInstancedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, VkBuffer indicesBuffer, int32_t instances)
bool linkProgram(int32_t programId) override
Links attached shaders to a program.
void createGUIRenderingPipeline(int contextIdx, program_type *program)
void setProgramUniformFloatMatrix4x4(int contextIdx, int32_t uniformId, const array< float, 16 > &data) override
Set up a float matrix 4x4 uniform value.
void enableCulling(int contextIdx) override
Enable culling.
vector< delete_image_type > deleteImages
Definition: VKRenderer.h:485
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR
Definition: VKRenderer.h:409
bool beginDrawCommandBuffer(int contextIdx, int bufferId=-1)
Definition: VKRenderer.cpp:271
array< buffer_object_type *, BUFFERS_MAX+1 > buffers
Definition: VKRenderer.h:434
void bindOriginsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind origins buffer object.
int32_t createProgram(int type) override
Creates a shader program.
void bindIndicesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind indices buffer object.
void initializeFrame() override
Pre Frame Initialization.
int32_t createGBufferGeometryTexture(int32_t width, int32_t height) override
Creates a geometry buffer geometry texture.
void uploadSkinningBufferObject(int contextIdx, int32_t bufferObjectId, int32_t size, FloatBuffer *data) override
Upload skinning buffer object.
void enableAdditionBlending() override
Enable blending with c = a + b.
framebuffer_pipelines_type * getFramebufferPipelines(uint64_t framebufferPipelinesId)
void bindVerticesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind vertices buffer object.
texture_type * getBindTextureInternal(int32_t textureId)
void prepareMipMapTextureImage(int contextIdx, struct texture_type *textureObject, VkImageTiling tiling, VkImageUsageFlags usage, VkFlags requiredFlags, Texture *texture, const Texture::MipMapTexture &mipMapTexture, const array< ThsvsAccessType, 2 > &nextAccesses, ThsvsImageLayout imageLayout)
Definition: VKRenderer.cpp:753
void createRasterizationStateCreateInfo(int contextIdx, VkPipelineRasterizationStateCreateInfo &rasterizationStateCreateInfo)
void drawInstancedIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset, int32_t instances) override
Draw instanced indexed triangles from buffer objects.
void bindVertices2BufferObject(int contextIdx, int32_t bufferObjectId) override
Bind vertices 2 buffer object.
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR
Definition: VKRenderer.h:412
void useProgram(int contextIdx, int32_t programId) override
Use shader program.
void bindColorsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind colors buffer object.
void bindPointSizesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind point sizes buffer object.
void bindSkinningVerticesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning vertices buffer object.
void createColorBlendAttachmentState(VkPipelineColorBlendAttachmentState &blendAttachmentState)
void bindBitangentsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind bitangents buffer object.
void bindSkinningNormalsResultBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning normals result buffer object.
void setProgramUniformFloatMatrices4x4(int contextIdx, int32_t uniformId, int32_t count, FloatBuffer *data) override
Set up a float matrices 4x4 uniform values.
void resizeGBufferColorTexture(int32_t textureId, int32_t width, int32_t height) override
Resizes a geometry buffer color RGBA texture.
void bindSkinningMatricesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning matrices result buffer object.
int32_t createGeometryBufferObject(int32_t depthBufferTextureId, int32_t geometryBufferTextureId1, int32_t geometryBufferTextureId2, int32_t geometryBufferTextureId3, int32_t colorBufferTextureId1, int32_t colorBufferTextureId2, int32_t colorBufferTextureId3, int32_t colorBufferTextureId4, int32_t colorBufferTextureId5) override
Creates a geometry frame buffer object.
vector< window_frambuffer_buffer_type > windowFramebufferBuffers
Definition: VKRenderer.h:418
void updateViewPort() override
Update viewport.
void createFramebufferObject(int32_t frameBufferId)
VkPipeline getPipelineInternal(int contextIdx, program_type *programm, uint64_t framebuffePipelineId, uint32_t pipelineIdx)
void bindModelMatricesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind model matrices buffer object.
void createPointsRenderingPipeline(int contextIdx, program_type *program)
void drawIndexedTrianglesFromBufferObjects(int contextIdx, int32_t triangles, int32_t trianglesOffset) override
Draw indexed triangles from buffer objects.
void disableDepthBufferTest() override
Disable depth buffer test.
void bindSkinningNormalsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind skinning normal buffer object.
void unbindBufferObjects(int contextIdx) override
Unbind buffer objects.
array< texture_type *, TEXTURES_MAX+1 > textures
Definition: VKRenderer.h:435
VkPhysicalDeviceMemoryProperties memoryProperties
Definition: VKRenderer.h:403
texture_type * getTextureInternal(int32_t textureId)
void bindEffectColorAddsBufferObject(int contextIdx, int32_t bufferObjectIdd, int32_t divisor) override
Bind effect color adds buffer object.
int32_t createTexture() override
Creates a texture.
VkQueueFamilyProperties * queueProperties
Definition: VKRenderer.h:402
float readPixelDepth(int32_t x, int32_t y) override
Reads a pixel depth.
void uploadTexture(int contextIdx, Texture *texture) override
Uploads texture data to current bound texture.
void getImageLayoutChange(image_layout_change &imageLayoutChange, texture_type *textureObject, const array< ThsvsAccessType, 2 > &prevAccessTypes, const array< ThsvsAccessType, 2 > &nextAccessTypes, ThsvsImageLayout prevLayout, ThsvsImageLayout nextLayout, bool discardContent, uint32_t baseMipLevel=0, uint32_t levelCount=1)
Definition: VKRenderer.cpp:471
VkCommandBuffer endDrawCommandBuffer(int contextIdx, int bufferId=-1, bool cycleBuffers=true)
Definition: VKRenderer.cpp:357
void setLineWidth(float lineWidth) override
Set line width.
ByteBuffer * readPixels(int32_t x, int32_t y, int32_t width, int32_t height) override
Read pixels.
void enableDepthBufferTest() override
Enable depth buffer test.
void resizeColorBufferTexture(int32_t textureId, int32_t width, int32_t height) override
Resize color buffer texture.
static constexpr int OBJECTS_VERTEX_BUFFER_COUNT
Definition: VKRenderer.h:92
void bindTextureSpriteIndicesBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind texture and sprite indices buffer object.
void setProgramUniformFloatVec2(int contextIdx, int32_t uniformId, const array< float, 2 > &data) override
Set up a float vec2 uniform value.
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR
Definition: VKRenderer.h:408
buffer_object_type * getBufferObjectInternal(int32_t bufferObjectId)
void bindSolidColorsBufferObject(int contextIdx, int32_t bufferObjectId) override
Bind solid colors buffer object.
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR
Definition: VKRenderer.h:406
vector< framebuffer_object_type * > framebuffers
Definition: VKRenderer.h:438
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
File system singleton class.
Definition: FileSystem.h:17
Mutex implementation.
Definition: Mutex.h:19
void unlock()
Unlocks this mutex.
Definition: Mutex.h:54
void lock()
Locks the mutex, additionally mutex locks will block until other locks have been unlocked.
Definition: Mutex.h:47
Implementation for read/write lock.
Definition: ReadWriteLock.h:17
void unlock()
Unlocks this spin lock.
Definition: SpinLock.h:51
void lock()
Locks the spin lock, additionally spin lock locks will block until other locks have been unlocked.
Definition: SpinLock.h:44
Base class of buffers.
Definition: Buffer.h:21
uint8_t get(int64_t position) const
Definition: Buffer.h:107
const uint8_t * getBuffer() const
Definition: Buffer.h:150
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29
Float buffer class.
Definition: FloatBuffer.h:18
Integer buffer class.
Definition: IntBuffer.h:14
Integer class.
Definition: Integer.h:25
Run time type information utility class.
Definition: RTTI.h:14
Short buffer class.
Definition: ShortBuffer.h:14
String tools class.
Definition: StringTools.h:22
Time utility class.
Definition: Time.h:20
std::exception Exception
Exception base class.
Definition: Exception.h:18
array< array< ThsvsAccessType, 2 >, 6 > accessTypes
Definition: VKRenderer.h:269