Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
VulkanHelper.cpp
Go to the documentation of this file.
2
6
7#include <stdexcept>
8#include <vulkan/vulkan_core.h>
9
12std::mutex VulkanHelper::s_mutex;
13#ifdef IS_IN_DEBUG
14std::unordered_map<uint64_t, std::string> VulkanHelper::objectNames;
15#endif
16
17void VulkanHelper::initializeDebugFunctions( VkInstance instance )
18{
20#ifdef IS_IN_DEBUG
21 loadVkFunction( instance, "vkCreateDebugUtilsMessengerEXT", s_functions.vkCreateDebugUtilsMessengerEXT );
22 loadVkFunction( instance, "vkDestroyDebugUtilsMessengerEXT", s_functions.vkDestroyDebugUtilsMessengerEXT );
23
24 loadVkFunction( instance, "vkCmdBeginDebugUtilsLabelEXT", s_functions.vkCmdBeginDebugUtilsLabelEXT );
25 loadVkFunction( instance, "vkCmdEndDebugUtilsLabelEXT", s_functions.vkCmdEndDebugUtilsLabelEXT );
26
27 loadVkFunction( instance, "vkSetDebugUtilsObjectNameEXT", s_functions.vkSetDebugUtilsObjectNameEXT );
28#endif
30}
31
32void VulkanHelper::initializeFunctions( VkInstance instance, VkDevice device )
33{
34 std::lock_guard<std::mutex> lock( s_mutex );
36 {
37 PLOGW << "Vulkan functions already initialized. Ignoring redundant call.";
38 return;
39 }
40
41 initializeDebugFunctions( instance );
42
43 loadVkFunction( instance, "vkCmdDrawMeshTasksIndirectEXT", s_functions.vkCmdDrawMeshTasksIndirectEXT );
44 loadVkFunction( instance, "vkCmdDrawMeshTasksIndirectCountEXT", s_functions.vkCmdDrawMeshTasksIndirectCountEXT );
45 loadVkFunction( instance, "vkCmdPushConstants2", s_functions.vkCmdPushConstants2 );
46 loadVkFunction (instance, "vkCmdBindDescriptorSets2", s_functions.vkCmdBindDescriptorSets2);
47 loadVkDeviceFunction( device, "vkCmdBeginConditionalRenderingEXT", s_functions.vkCmdBeginConditionalRenderingEXT);
48 loadVkDeviceFunction( device, "vkCmdEndConditionalRenderingEXT", s_functions.vkCmdEndConditionalRenderingEXT);
49
50#ifdef ENABLE_TRACY
51 // Load Tracy calibrated timestamps extension functions (only if extensions are supported)
53 instance,
54 "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
55 s_functions.vkGetPhysicalDeviceCalibrateableTimeDomainsEXT
56 );
57 loadVkFunction( instance, "vkGetCalibratedTimestampsEXT", s_functions.vkGetCalibratedTimestampsEXT );
58 loadVkDeviceFunction( device, "vkResetQueryPool", s_functions.vkResetQueryPool );
59#endif
60
62 PLOGI << "Vulkan extension functions initialized successfully.";
63}
64
66{
68 {
69 throw std::runtime_error(
70 "Vulkan functions have not been initialized! Call VulkanHelper::initializeFunctions() first."
71 );
72 }
73 return s_functions;
74}
75
77 VkDevice device,
78 VkPhysicalDevice physicalDevice,
79 VkDeviceSize size,
80 VkBufferUsageFlags usage,
81 VkMemoryPropertyFlags properties,
82 VkBuffer & buffer,
83 VkDeviceMemory & bufferMemory
84)
85{
86#ifdef ENABLE_TRACY
87 TRACY_ZONE_SCOPED_NAMED( "Create buffer" );
88#endif
89 VkBufferCreateInfo bufferInfo{};
90 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
91 bufferInfo.size = size;
92 bufferInfo.usage = usage;
93 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // it will only be accessed by the graphics pipeline
94 bufferInfo.flags = 0;
95
96 {
97 TRACY_ZONE_SCOPED_NAMED( "Buffer creation" );
98 if ( vkCreateBuffer( device, &bufferInfo, nullptr, &buffer ) != VK_SUCCESS )
99 {
100 throw std::runtime_error( "failed to create buffer!" );
101 }
102 }
103
104
105 VkMemoryRequirements memoryRequirements;
106 {
107 TRACY_ZONE_SCOPED_NAMED( "Finding Memory Requirements" );
108 vkGetBufferMemoryRequirements( device, buffer, &memoryRequirements );
109
110 }
111
112 VkMemoryAllocateInfo allocInfo{};
113 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
114 allocInfo.allocationSize = memoryRequirements.size;
115 allocInfo.memoryTypeIndex =
116 findMemoryType( physicalDevice, memoryRequirements.memoryTypeBits, properties );
117
118 {
119 TRACY_ZONE_SCOPED_NAMED( "Allocating buffer memory" );
120 if ( vkAllocateMemory( device, &allocInfo, nullptr, &bufferMemory ) != VK_SUCCESS )
121 {
122#if IS_IN_DEBUG
123 std::stringstream ss;
124 ss << "failed to allocate buffer memory for buffer ";
125 ss << VulkanHelper::getDebugName( buffer );
126 throw std::runtime_error(ss.str().c_str());
127#else
128 throw std::runtime_error( "failed to allocate vertex buffer memory!" );
129#endif
130 }
131 }
132
133 vkBindBufferMemory( device, buffer, bufferMemory, 0 );
134}
135
137 VkDevice device,
138 VkPhysicalDevice physicalDevice,
139 VkCommandPool commandPool,
140 VkQueue queue,
141 VkDeviceSize size,
142 const void * dataPtr,
143 VkBuffer targetBuffer
144)
145{
146 // Create staging buffer
147 VkBuffer stagingBuffer;
148 VkDeviceMemory stagingBufferMemory;
150 device,
151 physicalDevice,
152 size,
153 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
154 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
155 stagingBuffer,
156 stagingBufferMemory
157 );
158
159 // Map staging buffer and copy data
160 void * mappedData;
161 vkMapMemory( device, stagingBufferMemory, 0, size, 0, &mappedData );
162 memcpy( mappedData, dataPtr, static_cast<size_t>( size ) );
163 vkUnmapMemory( device, stagingBufferMemory );
164
165 // Copy from staging buffer to existing target buffer
166 VulkanHelper::copyBuffer( device, commandPool, queue, stagingBuffer, targetBuffer, size );
167
168 // Clean up staging buffer
169 vkDestroyBuffer( device, stagingBuffer, nullptr );
170 vkFreeMemory( device, stagingBufferMemory, nullptr );
171}
172
173bool VulkanHelper::isValid( void * object )
174{
175 return object != VK_NULL_HANDLE;
176}
177
178std::string VulkanHelper::strIsValid( void * object )
179{
180 return isValid( object ) ? CHECK_STR : CROSS_STR;
181}
182
184 VkDevice device,
185 VkPhysicalDevice physicalDevice,
186 VkCommandPool commandPool,
187 VkQueue queue,
188 VkDeviceSize size,
189 VkBufferUsageFlags usage,
190 const void * dataPtr,
191 VkBuffer & buffer,
192 VkDeviceMemory & bufferMemory
193)
194{
195 VkBuffer stagingBuffer;
196 VkDeviceMemory stagingBufferMemory;
198 device,
199 physicalDevice,
200 size,
201 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
202 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
203 stagingBuffer,
204 stagingBufferMemory
205 );
206
207 void * mappedData;
208 vkMapMemory( device, stagingBufferMemory, 0, size, 0, &mappedData );
209 memcpy( mappedData, dataPtr, static_cast<size_t>( size ) );
210 vkUnmapMemory( device, stagingBufferMemory );
211
213 device,
214 physicalDevice,
215 size,
216 VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage,
217 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
218 buffer,
219 bufferMemory
220 );
221
222 VulkanHelper::copyBuffer( device, commandPool, queue, stagingBuffer, buffer, size );
223
224 vkDestroyBuffer( device, stagingBuffer, nullptr );
225 vkFreeMemory( device, stagingBufferMemory, nullptr );
226}
227
229 VkDevice device,
230 VkPhysicalDevice physicalDevice,
231 VkCommandPool commandPool,
232 VkQueue queue,
233 VkDeviceSize size,
234 const void * dataPtr,
235 VkBuffer buffer,
236 VkDeviceMemory bufferMemory
237)
238{
239 VkBuffer stagingBuffer;
240 VkDeviceMemory stagingBufferMemory;
241
243 device,
244 physicalDevice,
245 size,
246 VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
247 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
248 stagingBuffer,
249 stagingBufferMemory
250 );
251
252 void * mappedData;
253 vkMapMemory( device, stagingBufferMemory, 0, size, 0, &mappedData );
254 memcpy( mappedData, dataPtr, static_cast<size_t>( size ) );
255 vkUnmapMemory( device, stagingBufferMemory );
256
257 VulkanHelper::copyBuffer( device, commandPool, queue, stagingBuffer, buffer, size );
258
259 vkDestroyBuffer( device, stagingBuffer, nullptr );
260 vkFreeMemory( device, stagingBufferMemory, nullptr );
261}
262
264 VkPhysicalDevice physicalDevice,
265 uint32_t typeFilter,
266 VkMemoryPropertyFlags properties
267)
268{
269 VkPhysicalDeviceMemoryProperties memoryProperties;
270 vkGetPhysicalDeviceMemoryProperties( physicalDevice, &memoryProperties );
271
272 for ( uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++ )
273 {
274 if ( typeFilter & ( 1 << i ) &&
275 ( memoryProperties.memoryTypes[i].propertyFlags & properties ) == properties )
276 {
277 return i;
278 }
279 }
280
281 throw std::runtime_error( "failed to find suitable memory type!" );
282}
283
285 VkPhysicalDevice physicalDevice,
286 VkMemoryRequirements2 requirements,
287 VkMemoryPropertyFlags properties,
288 uint32_t & out_typeIndex
289)
290{
291 VkPhysicalDeviceMemoryProperties supportedMemoryProperties;
292 vkGetPhysicalDeviceMemoryProperties( physicalDevice, &supportedMemoryProperties );
293
294 const VkMemoryPropertyFlags typeFilter = requirements.memoryRequirements.memoryTypeBits;
295 for ( uint32_t memoryTypeIndex = 0u; memoryTypeIndex < supportedMemoryProperties.memoryTypeCount;
296 ++memoryTypeIndex )
297 {
298 const VkMemoryPropertyFlags propertyFlags =
299 supportedMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags;
300 if ( typeFilter & ( 1u << memoryTypeIndex ) && ( propertyFlags & properties ) == properties )
301 {
302 out_typeIndex = memoryTypeIndex;
303 return true;
304 }
305 }
306
307 return false;
308}
309
310VkDeviceSize VulkanHelper::align( VkDeviceSize value, VkDeviceSize alignment )
311{
312 if ( value == 0u )
313 {
314 return value;
315 }
316 return ( value + alignment - 1u ) & ~( alignment - 1u );
317}
318
320 VkDevice device,
321 VkCommandPool commandPool,
322 VkQueue graphicsQueue,
323 VkBuffer sourceBuffer,
324 VkBuffer destinationBuffer,
325 VkDeviceSize size
326)
327{
328#ifdef ENABLE_TRACY
329 TRACY_ZONE_SCOPED_NAMED( "Copy buffer" );
330#endif
331 VkCommandBuffer commandBuffer = beginSingleTimeCommands( device, commandPool );
332
333 VkBufferCopy copyRegion{};
334 copyRegion.size = size;
335 vkCmdCopyBuffer( commandBuffer, sourceBuffer, destinationBuffer, 1, &copyRegion );
336
337 endSingleTimeCommands( device, graphicsQueue, commandPool, commandBuffer );
338}
339
341 VkDevice device,
342 VkCommandPool commandPool,
343 VkQueue graphicsQueue,
344 const std::vector<BufferCopyObject> & bufferCopyObjects
345)
346{
347#ifdef ENABLE_TRACY
348 TRACY_ZONE_SCOPED_NAMED( "Copy buffer" );
349#endif
350 VkCommandBuffer commandBuffer = beginSingleTimeCommands( device, commandPool );
351
352 for ( const BufferCopyObject & copyObject : bufferCopyObjects )
353 {
354 VkBufferCopy copyRegion{};
355 copyRegion.size = copyObject.size;
356 vkCmdCopyBuffer(
357 commandBuffer, copyObject.sourceBuffer, copyObject.destinationBuffer, 1, &copyRegion
358 );
359 }
360
361 endSingleTimeCommands( device, graphicsQueue, commandPool, commandBuffer );
362}
363
365 EngineCore::ApplicationContext * context, // Pass context to get queue indices
366 VkCommandBuffer commandBuffer,
367 const std::vector<BufferCopyObject> & bufferCopyObjects
368)
369{
370#ifdef ENABLE_TRACY
372#endif
373
374 // Get queue family indices once before the loop
375 uint32_t graphicsFamilyIndex = context->getVkGraphicsQueueFamilyIndex();
376 uint32_t transferFamilyIndex = context->getVkTransferQueueFamilyIndex();
377 bool familiesDiffer = ( transferFamilyIndex != graphicsFamilyIndex );
378
379 for ( const BufferCopyObject & copyObject : bufferCopyObjects )
380 {
381 VkBufferCopy copyRegion{};
382 copyRegion.size = copyObject.size;
383 copyRegion.srcOffset = 0;
384 copyRegion.dstOffset = 0;
385 vkCmdCopyBuffer(
386 commandBuffer, copyObject.sourceBuffer, copyObject.destinationBuffer, 1, &copyRegion
387 );
388
389 // --- Synchronization ---
390 // This barrier's job depends on whether the queue families differ.
391
392 VkBufferMemoryBarrier bufferMemoryBarrier{};
393 bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
394 bufferMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; // Memory written by the transfer
395 bufferMemoryBarrier.buffer = copyObject.destinationBuffer;
396 bufferMemoryBarrier.offset = 0;
397 bufferMemoryBarrier.size = VK_WHOLE_SIZE;
398
399 if ( familiesDiffer )
400 {
401 // **Queue Family Release Operation**
402 // If families differ, we need to release ownership from the transfer queue family.
403 // The corresponding 'acquire' operation will happen in the GRAPHICS command buffer.
404 bufferMemoryBarrier.dstAccessMask = 0; // No access needed on transfer queue after release
405 bufferMemoryBarrier.srcQueueFamilyIndex = transferFamilyIndex;
406 bufferMemoryBarrier.dstQueueFamilyIndex = graphicsFamilyIndex;
407
408 vkCmdPipelineBarrier(
409 commandBuffer,
410 VK_PIPELINE_STAGE_TRANSFER_BIT, // Stage where the write happened
411 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // Doesn't matter on release, just needs to happen
412 // after srcStage
413 0, // No dependency flags needed for release
414 0,
415 nullptr, // No memory barriers
416 1,
417 &bufferMemoryBarrier, // The buffer release barrier
418 0,
419 nullptr
420 ); // No image barriers
421 }
422 else
423 {
424 // **Same Queue Family**
425 // No ownership transfer needed. The memory visibility for the graphics queue
426 // will be handled ENTIRELY by the semaphore wait + pWaitDstStageMask
427 // in the graphics vkQueueSubmit call.
428 // We DON'T put graphics stages (DRAW_INDIRECT, MESH_SHADER etc.) here.
429 // A barrier might *only* be needed if subsequent commands *within this transfer CB*
430 // depended on this copy, which isn't the case here.
431 // So, often, no barrier is needed here when families are the same.
432
433 // Optional: If you wanted to ensure this write is finished before ANY
434 // *subsequent* transfer command in *this same command buffer*, you could use:
435 /*
436 bufferMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; //
437 Or whatever next transfer needs bufferMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
438 bufferMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
439
440 vkCmdPipelineBarrier(
441 commandBuffer,
442 VK_PIPELINE_STAGE_TRANSFER_BIT, // Stage where the write happened
443 VK_PIPELINE_STAGE_TRANSFER_BIT, // Stage for subsequent transfers
444 0,
445 0, nullptr,
446 1, &bufferMemoryBarrier,
447 0, nullptr);
448 */
449 // However, for syncing with the graphics queue, this is NOT needed.
450 }
451 } // End for loop
452}
453
454VkCommandBuffer VulkanHelper::beginSingleTimeCommands( VkDevice device, VkCommandPool commandPool )
455{
456 VkCommandBufferAllocateInfo allocInfo{};
457 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
458 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
459 allocInfo.commandPool = commandPool;
460 allocInfo.commandBufferCount = 1;
461
462 VkCommandBuffer commandBuffer;
463 vkAllocateCommandBuffers( device, &allocInfo, &commandBuffer );
464 VulkanHelper::setObjectName( device, commandBuffer, "Single time command buffer" );
465
466 VkCommandBufferBeginInfo beginInfo{};
467 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
468 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
469
470 vkBeginCommandBuffer( commandBuffer, &beginInfo );
471
472 return commandBuffer;
473}
474
476 VkDevice device,
477 VkQueue graphicsQueue,
478 VkCommandPool commandPool,
479 VkCommandBuffer commandBuffer
480)
481{
482 vkEndCommandBuffer( commandBuffer );
483
484 VkSubmitInfo submitInfo{};
485 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
486 submitInfo.commandBufferCount = 1;
487 submitInfo.pCommandBuffers = &commandBuffer;
488
489 vkQueueSubmit( graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE );
490 vkQueueWaitIdle( graphicsQueue );
491
492 vkFreeCommandBuffers( device, commandPool, 1, &commandBuffer );
493}
494
495void VulkanHelper::cleanupBuffer( VkDevice device, VkBuffer buffer, VkDeviceMemory bufferMemory )
496{
497 if ( buffer != VK_NULL_HANDLE )
498 vkDestroyBuffer( device, buffer, nullptr );
499 if ( bufferMemory != VK_NULL_HANDLE )
500 vkFreeMemory( device, bufferMemory, nullptr );
501}
502
504 VkDevice device,
505 VkPhysicalDevice physicalDevice,
506 uint32_t width,
507 uint32_t height,
508 VkFormat format,
509 VkImageTiling tiling,
510 VkImageUsageFlags usage,
511 VkMemoryPropertyFlags properties,
512 VkImage & image,
513 VkDeviceMemory & imageMemory
514)
515{
516 VkImageCreateInfo imageInfo{};
517 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
518 imageInfo.imageType = VK_IMAGE_TYPE_2D;
519 imageInfo.extent.width = width;
520 imageInfo.extent.height = height;
521 imageInfo.extent.depth = 1;
522 imageInfo.mipLevels = 1;
523 imageInfo.arrayLayers = 1;
524 imageInfo.format = format;
525 imageInfo.tiling = tiling;
526 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
527 imageInfo.usage = usage;
528 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
529 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
530 imageInfo.flags = 0;
531
532 if ( vkCreateImage( device, &imageInfo, nullptr, &image ) != VK_SUCCESS )
533 {
534 throw std::runtime_error( "failed to create image!" );
535 }
536
537 VkMemoryRequirements memoryRequirements;
538 vkGetImageMemoryRequirements( device, image, &memoryRequirements );
539
540 VkMemoryAllocateInfo allocInfo{};
541 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
542 allocInfo.allocationSize = memoryRequirements.size;
543 allocInfo.memoryTypeIndex =
544 VulkanHelper::findMemoryType( physicalDevice, memoryRequirements.memoryTypeBits, properties );
545 assert(memoryRequirements.size > 0);
546 if ( vkAllocateMemory( device, &allocInfo, nullptr, &imageMemory ) != VK_SUCCESS )
547 {
548 throw std::runtime_error( "failed to allocate image memory!" );
549 }
550
551 vkBindImageMemory( device, image, imageMemory, 0 );
552}
553
555 VkCommandBuffer commandBuffer,
556 VkDevice device,
557 VkQueue graphicsQueue,
558 VkCommandPool commandPool,
559 VkImage image,
560 VkFormat format,
561 VkImageLayout oldLayout,
562 VkImageLayout newLayout,
563 uint32_t layerCount
564)
565{
566 VkImageMemoryBarrier barrier{};
567 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
568 barrier.oldLayout = oldLayout;
569 barrier.newLayout = newLayout;
570 barrier.image = image;
571 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // Add this
572 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // Add this
573
574 if ( newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL )
575 {
576 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
577
578 if ( VulkanHelper::hasStencilComponent( format ) )
579 {
580 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
581 }
582 }
583 else
584 {
585 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
586 }
587 barrier.subresourceRange.baseMipLevel = 0;
588 barrier.subresourceRange.levelCount = 1;
589 barrier.subresourceRange.baseArrayLayer = 0;
590 barrier.subresourceRange.layerCount = layerCount; // <--- USE THE PARAMETER
591
592 // This part of your function is very specific and can be improved.
593 // Let's make it more robust for our use case.
594 barrier.srcAccessMask = 0;
595 barrier.dstAccessMask = 0;
596
597 VkPipelineStageFlags sourceStage;
598 VkPipelineStageFlags destinationStage;
599
600 if ( oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL )
601 {
602 barrier.srcAccessMask = 0;
603 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
604 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
605 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
606 }
607 else if ( oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL )
608 {
609 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
610 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
611 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
612 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
613 }
614 else if ( oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL )
615 {
616 barrier.srcAccessMask = 0;
617 barrier.dstAccessMask =
618 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
619 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
620 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
621 }
622 // ---- ADD THIS NEW CASE ----
623 else if ( oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL )
624 {
625 barrier.srcAccessMask = 0;
626 barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
627 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
628 destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
629 }
630 else
631 {
632 throw std::invalid_argument( "unsupported layout transition!" );
633 }
634
635 vkCmdPipelineBarrier(
636 commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier
637 );
638}
639
641{
642 return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
643}
644
646 VkDevice device,
647 VkCommandPool commandPool,
648 VkQueue graphicsQueue,
649 VkBuffer buffer,
650 VkImage image,
651 uint32_t width,
652 uint32_t height
653)
654{
655 VkCommandBuffer commandBuffer = beginSingleTimeCommands( device, commandPool );
656
657 VkBufferImageCopy region{};
658 region.bufferOffset = 0;
659 region.bufferRowLength = 0;
660 region.bufferImageHeight = 0;
661
662 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
663 region.imageSubresource.mipLevel = 0;
664 region.imageSubresource.baseArrayLayer = 0;
665 region.imageSubresource.layerCount = 1;
666
667 region.imageOffset = { 0, 0, 0 };
668 region.imageExtent = { width, height, 1 };
669
670 vkCmdCopyBufferToImage( commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region );
671
672 VulkanHelper::endSingleTimeCommands( device, graphicsQueue, commandPool, commandBuffer );
673}
674
676 VkDevice device,
677 VkImage image,
678 VkFormat format,
679 VkImageAspectFlags aspectFlags
680)
681{
682 assert( image != VK_NULL_HANDLE );
683
684 VkImageViewCreateInfo viewInfo{};
685 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
686 viewInfo.image = image;
687 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
688 viewInfo.format = format;
689
690 viewInfo.subresourceRange.aspectMask = aspectFlags;
691 viewInfo.subresourceRange.baseMipLevel = 0;
692 viewInfo.subresourceRange.levelCount = 1;
693 viewInfo.subresourceRange.baseArrayLayer = 0;
694 viewInfo.subresourceRange.layerCount = 1;
695
696 viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
697 viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
698 viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
699 viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
700
701 VkImageView imageView = nullptr;
702 if ( vkCreateImageView( device, &viewInfo, nullptr, &imageView ) != VK_SUCCESS )
703 {
704 throw std::runtime_error( "failed to create texture image view!" );
705 }
706
707 return imageView;
708}
709
710VkDescriptorBufferInfo VulkanHelper::fullBufferInfo( VkBuffer buffer )
711{
712#ifdef IS_IN_DEBUG
713 PLOGD << "Buffer \"" << VulkanHelper::getDebugName( buffer ) << "\" is valid: " << VulkanHelper::strIsValid( buffer );
714#endif
715 VkDescriptorBufferInfo bufferInfo{
716 .buffer = buffer,
717 .offset = 0,
718 .range = VK_WHOLE_SIZE
719 };
720 return bufferInfo;
721}
722
724 VkDevice device,
725 const VkDescriptorSetAllocateInfo * pAllocateInfo,
726 VkDescriptorSet * pDescriptorSets,
727 const std::string & name
728)
729{
730 PLOG_FN_VK_RETURN( vkAllocateDescriptorSets( device, pAllocateInfo, pDescriptorSets ) );
731 setObjectName( device, *pDescriptorSets, getName( name, " Descriptor Set allocations" ) );
732 return result;
733}
734
736 VkDevice device,
737 const VkSemaphoreCreateInfo * pCreateInfo,
738 const VkAllocationCallbacks * pAllocator,
739 VkSemaphore * pSemaphore,
740 const std::string & name
741)
742{
743 assert( pCreateInfo );
744 PLOG_THROW_FN_VK_RETURN( vkCreateSemaphore( device, pCreateInfo, pAllocator, pSemaphore ) );
745 setObjectName( device, *pSemaphore, getName( name, " Semaphore" ) );
746 return result;
747}
748
750 VkDevice device,
751 const VkCommandBufferAllocateInfo * pAllocateInfo,
752 VkCommandBuffer * pCommandBuffers,
753 const std::string & name
754)
755{
756 PLOG_THROW_FN_VK_RETURN( vkAllocateCommandBuffers( device, pAllocateInfo, pCommandBuffers ) );
757 setObjectName( device, *pCommandBuffers, getName( name, " Command Buffer allocation" ) );
758 return result;
759}
760
762 VkDevice device,
763 const VkDescriptorSetLayoutCreateInfo * pCreateInfo,
764 const VkAllocationCallbacks * pAllocator,
765 VkDescriptorSetLayout * pSetLayout,
766 const std::string & name
767)
768{
769 PLOG_THROW_FN_VK_RETURN( vkCreateDescriptorSetLayout( device, pCreateInfo, pAllocator, pSetLayout ) );
770 setObjectName( device, *pSetLayout, getName( name, " Descriptor Set Layout" ) );
771 return result;
772}
773
775 VkDevice device,
776 const VkPipelineLayoutCreateInfo * pCreateInfo,
777 const VkAllocationCallbacks * pAllocator,
778 VkPipelineLayout * pPipelineLayout,
779 const std::string & name
780)
781{
782 assert(pCreateInfo != nullptr);
783 PLOG_THROW_FN_VK_RETURN( vkCreatePipelineLayout( device, pCreateInfo, pAllocator, pPipelineLayout ) );
784 setObjectName( device, *pPipelineLayout, getName( name, " Pipeline Layout" ) );
785 return result;
786}
787
789 VkDevice device,
790 const VkFenceCreateInfo * pCreateInfo,
791 const VkAllocationCallbacks * pAllocator,
792 VkFence * pFence,
793 const std::string & name
794)
795{
796 PLOG_THROW_FN_VK_RETURN( vkCreateFence( device, pCreateInfo, pAllocator, pFence ) );
797 setObjectName( device, *pFence, getName( name, " Fence" ) );
798}
799
801 VkDevice device,
802 const VkDescriptorPoolCreateInfo * pCreateInfo,
803 const VkAllocationCallbacks * pAllocator,
804 VkDescriptorPool * pDescriptorPool,
805 const std::string & name
806)
807{
808 PLOG_FN_VK_RETURN( vkCreateDescriptorPool( device, pCreateInfo, pAllocator, pDescriptorPool ) )
809 setObjectName( device, *pDescriptorPool, getName( name, " descriptor Pool" ) );
810 return result;
811}
812
813std::string VulkanHelper::getName( const std::string & name, const std::string & suffix )
814{
815 std::stringstream ss;
816 ss << name;
817 ss << suffix;
818 return ss.str();
819}
820
821#ifdef IS_IN_DEBUG
822void VulkanHelper::beginLabel( VkCommandBuffer commandBuffer, const char * pLabelName, const float color[4] )
823{
824 // Only proceed if the function pointer was successfully loaded
826 {
827 return;
828 }
829
830 VkDebugUtilsLabelEXT labelInfo{};
831 labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
832 labelInfo.pLabelName = pLabelName;
833
834 // The color is optional. If provided, copy it.
835 if ( color )
836 {
837 labelInfo.color[0] = color[0];
838 labelInfo.color[1] = color[1];
839 labelInfo.color[2] = color[2];
840 labelInfo.color[3] = color[3];
841 }
842
843 s_functions.vkCmdBeginDebugUtilsLabelEXT( commandBuffer, &labelInfo );
844}
845
846void VulkanHelper::endLabel( VkCommandBuffer commandBuffer )
847{
848 // Only proceed if the function pointer was successfully loaded
849 if ( !s_functions.vkCmdEndDebugUtilsLabelEXT )
850 {
851 return;
852 }
853
854 s_functions.vkCmdEndDebugUtilsLabelEXT( commandBuffer );
855}
856#endif // IS_IN_DEBUG
857
858/*
859VkSampler VulkanHelper::createTextureSampler(const EngineCore::VulkanContext context) {
860
861 VkSampler textureSampler;
862
863 VkSamplerCreateInfo samplerInfo{};
864 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
865 samplerInfo.magFilter = VK_FILTER_LINEAR;
866 samplerInfo.minFilter = VK_FILTER_LINEAR;
867 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
868 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
869 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
870 samplerInfo.anisotropyEnable = VK_TRUE;
871
872 VkPhysicalDeviceProperties properties{};
873 vkGetPhysicalDeviceProperties(context.getPhysicalDevice(), &properties);
874 samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
875
876 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
877 samplerInfo.unnormalizedCoordinates = VK_FALSE;
878
879 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
880 samplerInfo.mipLodBias = 0.0f;
881 samplerInfo.minLod = 0.0f;
882 samplerInfo.maxLod = 0.0f;
883
884 if (vkCreateSampler(context.getDevice(), &samplerInfo, nullptr, &textureSampler)) {
885 throw std::runtime_error("failed to create texture sampler!");
886 }
887
888 return textureSampler;
889}
890*/
constexpr const char * CHECK_STR
constexpr const char * CROSS_STR
#define TRACY_ZONE_SCOPED_FUNCTION
#define TRACY_ZONE_SCOPED_NAMED(name)
DynamicFunctionInitState
@ NOT_INITIALIZED
@ DEBUG_FUNCTIONS_INITIALIZED
@ FINISHED
The application context is the core class which stores the basic openxr and vulkan objects.
uint32_t getVkTransferQueueFamilyIndex() const
gets the transfer queue family index
uint32_t getVkGraphicsQueueFamilyIndex() const
Gets the zero-based index of the vulkan draw queue family.
static VkResult createPipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout, const std::string &name)
static void createBufferWithStaging(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, VkDeviceSize size, VkBufferUsageFlags usage, const void *dataPtr, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
static void endSingleTimeCommands(VkDevice device, VkQueue graphicsQueue, VkCommandPool commandPool, VkCommandBuffer commandBuffer)
static void initializeDebugFunctions(VkInstance instance)
static VkImageView createImageView(VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
static void copyDataToBufferViaStaging(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, VkDeviceSize size, const void *dataPtr, VkBuffer buffer, VkDeviceMemory bufferMemory)
static VkDeviceSize align(VkDeviceSize value, VkDeviceSize alignment)
static bool findSuitableMemoryType(VkPhysicalDevice physicalDevice, VkMemoryRequirements2 requirements, VkMemoryPropertyFlags properties, uint32_t &out_typeIndex)
static void loadVkDeviceFunction(VkDevice device, const std::string &name, T &functionPointer)
static std::string strIsValid(void *object)
static std::string getDebugName(VulkanObjectType objectHandle)
static void copyBufferToImage(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
static void recordBufferCopyMultiple(EngineCore::ApplicationContext *context, VkCommandBuffer commandBuffer, const std::vector< BufferCopyObject > &bufferCopyObjects)
static DynamicFunctionInitState s_functionInitializationState
static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkDeviceSize size)
static VulkanFunctions s_functions
static void endLabel(VkCommandBuffer)
static void createFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence, const std::string &name)
static VkResult allocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers, const std::string &name)
static VkResult createSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore, const std::string &name)
static void uploadDataToExistingBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, VkDeviceSize size, const void *dataPtr, VkBuffer targetBuffer)
static bool isValid(void *object)
static void transitionImageLayout(VkCommandBuffer commandBuffer, VkDevice device, VkQueue graphicsQueue, VkCommandPool commandPool, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t layerCount=1)
static void setObjectName(VkDevice device, VulkanObjectType objectHandle, const std::string &name)
static void loadVkFunction(VkInstance instance, const std::string &name, T &functionPointer)
static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties)
static void cleanupBuffer(VkDevice device, VkBuffer buffer, VkDeviceMemory bufferMemory)
static bool hasStencilComponent(VkFormat format)
static VkResult allocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets, const std::string &name)
static VkDescriptorBufferInfo fullBufferInfo(VkBuffer buffer)
static VkResult createDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool, const std::string &name)
static std::string getName(const std::string &name, const std::string &suffix)
static void initializeFunctions(VkInstance instance, VkDevice device)
static const VulkanFunctions & getFunctions()
static void createBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
static void beginLabel(VkCommandBuffer, const char *, const float *)
static std::mutex s_mutex
static VkResult createDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout, const std::string &name)
static void createImage(VkDevice device, VkPhysicalDevice physicalDevice, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory)
static void copyBufferMultiple(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, const std::vector< BufferCopyObject > &bufferCopyObjects)
static VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool)
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT