Vulkan Schnee 0.0.1 (22840dc8)
High-performance rendering engine
Loading...
Searching...
No Matches
VulkanHelper.h
1#pragma once
2#include "plog/Log.h"
3#include <mutex>
4#include <vulkan/vulkan_core.h>
5#include <unordered_map>
6
7namespace Engine::Core
8{
10} // namespace Engine::Core
11
12namespace EngineCore
13{
14 class ApplicationContext;
15} // namespace EngineCore
16
24{
25 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
26 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
27 PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
28 PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
29 PFN_vkCmdDrawMeshTasksIndirectCountEXT vkCmdDrawMeshTasksIndirectCountEXT = nullptr;
30 PFN_vkCmdPushConstants2 vkCmdPushConstants2 = nullptr;
31 PFN_vkCmdBindDescriptorSets2 vkCmdBindDescriptorSets2 = nullptr;
32 PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr;
33 PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT = nullptr;
34 PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT = nullptr;
35 PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT = nullptr;
36#ifdef ENABLE_TRACY
37 // Tracy calibrated timestamps extension functions
38 PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT =
39 nullptr;
40 PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT = nullptr;
41 PFN_vkResetQueryPool vkResetQueryPool = nullptr;
42#endif
43};
44
49{
53 VkBuffer sourceBuffer = VK_NULL_HANDLE;
54
58 VkBuffer destinationBuffer = VK_NULL_HANDLE;
59
63 VkDeviceSize size = VK_WHOLE_SIZE;
64
68 VkDeviceSize srcOffset = 0;
69
73 VkDeviceSize dstOffset = 0;
74};
75
79enum DynamicFunctionInitState : uint32_t
80{
81 NOT_INITIALIZED = 0,
82 DEBUG_FUNCTIONS_INITIALIZED = 1,
83 FINISHED = 2
84};
85
94{
95public:
101 static void initializeDebugFunctions(VkInstance instance);
102
109 static void initializeFunctions( VkInstance instance, VkDevice device );
110
117
126 template <typename T>
127 static void loadVkFunction( VkInstance instance, const std::string & name, T & functionPointer )
128 {
129 functionPointer = reinterpret_cast<T>( vkGetInstanceProcAddr( instance, name.c_str() ) );
130
131 if ( !functionPointer )
132 {
133 std::stringstream error;
134 error << "Vulkan INSTANCE extension function " << name << " is not supported!";
135 PLOGE << error.str();
136 throw std::runtime_error( error.str() );
137 }
138 }
139
148 template <typename T>
149 static void loadVkDeviceFunction( VkDevice device, const std::string & name, T & functionPointer )
150 {
151 functionPointer = reinterpret_cast<T>( vkGetDeviceProcAddr( device, name.c_str() ) );
152 if ( !functionPointer )
153 {
154 std::stringstream error;
155 error << "Vulkan DEVICE extension function " << name << " is not supported!";
156 PLOGE << error.str();
157 throw std::runtime_error( error.str() );
158 }
159 }
160
172 static void createBuffer(
173 VkDevice device,
174 VkPhysicalDevice physicalDevice,
175 VkDeviceSize size,
176 VkBufferUsageFlags usage,
177 VkMemoryPropertyFlags properties,
178 VkBuffer & buffer,
179 VkDeviceMemory & bufferMemory
180 );
181
194 VkDevice device,
195 VkPhysicalDevice physicalDevice,
196 VkCommandPool commandPool,
197 VkQueue queue,
198 VkDeviceSize size,
199 const void * dataPtr,
200 VkBuffer targetBuffer
201 );
202
208 static bool isValid( void * object );
209
215 static std::string strIsValid( void * object );
216
225 static uint32_t findMemoryType(
226 VkPhysicalDevice physicalDevice,
227 uint32_t typeFilter,
228 VkMemoryPropertyFlags properties
229 );
230
240 VkPhysicalDevice physicalDevice,
241 VkMemoryRequirements2 requirements,
242 VkMemoryPropertyFlags properties,
243 uint32_t & out_typeIndex
244 );
245
252 static VkDeviceSize align( VkDeviceSize value, VkDeviceSize alignment );
253
263 static void copyBuffer(
264 VkDevice device,
265 VkCommandPool commandPool,
266 VkQueue graphicsQueue,
267 VkBuffer sourceBuffer,
268 VkBuffer destinationBuffer,
269 VkDeviceSize size
270 );
271
281 VkDevice device,
282 VkCommandPool commandPool,
283 VkQueue graphicsQueue,
284 const std::vector<BufferCopyObject> & bufferCopyObjects
285 );
286
296 VkCommandBuffer commandBuffer,
297 const std::vector<BufferCopyObject> & bufferCopyObjects
298 );
299
306 static VkCommandBuffer beginSingleTimeCommands( VkDevice device, VkCommandPool commandPool );
307
316 VkDevice device,
317 VkQueue graphicsQueue,
318 VkCommandPool commandPool,
319 VkCommandBuffer commandBuffer
320 );
327 static void cleanupBuffer( VkDevice device, VkBuffer buffer, VkDeviceMemory bufferMemory );
328
343 static void createImage(
344 VkDevice device,
345 VkPhysicalDevice physicalDevice,
346 uint32_t width,
347 uint32_t height,
348 VkFormat format,
349 VkImageTiling tiling,
350 VkImageUsageFlags usage,
351 VkMemoryPropertyFlags properties,
352 VkImage & image,
353 VkDeviceMemory & imageMemory
354 );
355
370 VkCommandBuffer commandBuffer,
371 VkDevice device,
372 VkQueue graphicsQueue,
373 VkCommandPool commandPool,
374 VkImage image,
375 VkFormat format,
376 VkImageLayout oldLayout,
377 VkImageLayout newLayout,
378 uint32_t layerCount = 1
379 );
380
386 static bool hasStencilComponent( VkFormat format );
387
398 static void copyBufferToImage(
399 VkDevice device,
400 VkCommandPool commandPool,
401 VkQueue graphicsQueue,
402 VkBuffer buffer,
403 VkImage image,
404 uint32_t width,
405 uint32_t height
406 );
407
417 static VkImageView
418 createImageView( VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags );
419
425 static VkDescriptorBufferInfo fullBufferInfo( VkBuffer buffer );
426
435 static VkResult allocateDescriptorSets(
436 VkDevice device,
437 const VkDescriptorSetAllocateInfo * pAllocateInfo,
438 VkDescriptorSet * pDescriptorSets,
439 const std::string & name
440 );
441
452 static VkResult createSemaphore(
453 VkDevice device,
454 const VkSemaphoreCreateInfo * pCreateInfo,
455 const VkAllocationCallbacks * pAllocator,
456 VkSemaphore * pSemaphore,
457 const std::string & name
458 );
459
469 static VkResult allocateCommandBuffers(
470 VkDevice device,
471 const VkCommandBufferAllocateInfo * pAllocateInfo,
472 VkCommandBuffer * pCommandBuffers,
473 const std::string & name
474 );
475
487 VkDevice device,
488 const VkDescriptorSetLayoutCreateInfo * pCreateInfo,
489 const VkAllocationCallbacks * pAllocator,
490 VkDescriptorSetLayout * pSetLayout,
491 const std::string & name
492 );
493
504 static VkResult createPipelineLayout(
505 VkDevice device,
506 const VkPipelineLayoutCreateInfo * pCreateInfo,
507 const VkAllocationCallbacks * pAllocator,
508 VkPipelineLayout * pPipelineLayout,
509 const std::string & name
510 );
511
521 static void createFence(
522 VkDevice device,
523 const VkFenceCreateInfo * pCreateInfo,
524 const VkAllocationCallbacks * pAllocator,
525 VkFence * pFence,
526 const std::string & name
527 );
528
538 static VkResult createDescriptorPool(
539 VkDevice device,
540 const VkDescriptorPoolCreateInfo * pCreateInfo,
541 const VkAllocationCallbacks * pAllocator,
542 VkDescriptorPool * pDescriptorPool,
543 const std::string & name
544 );
545
546private:
553 static std::string getName( const std::string & name, const std::string & suffix );
554
555public:
556 /*static VkSampler createTextureSampler(const EngineCore::VulkanContext context);*/
557#ifdef IS_IN_DEBUG
565 static void
566 beginLabel( VkCommandBuffer commandBuffer, const char * pLabelName, const float color[4] = nullptr );
567
573 static void endLabel( VkCommandBuffer commandBuffer );
574
575private:
576 static std::unordered_map<uint64_t, std::string> objectNames;
577public:
578#else
582 static void beginLabel( VkCommandBuffer, const char *, const float * ) {}
583
587 static void endLabel( VkCommandBuffer ) {}
588#endif
589
590public:
591#ifdef IS_IN_DEBUG
592
593# define VK_OBJECT_TYPE_CASE( VkType, VkEnum ) \
594 if constexpr ( std::is_same_v<VulkanObjectType, VkType> ) \
595 return VkEnum;
596
602 template <typename VulkanObjectType>
603 static constexpr VkObjectType getVulkanObjectType()
604 {
605 VK_OBJECT_TYPE_CASE( VkBuffer, VK_OBJECT_TYPE_BUFFER );
606 VK_OBJECT_TYPE_CASE( VkQueue, VK_OBJECT_TYPE_QUEUE );
607 VK_OBJECT_TYPE_CASE( VkDescriptorPool, VK_OBJECT_TYPE_DESCRIPTOR_POOL );
608 VK_OBJECT_TYPE_CASE( VkDescriptorSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT );
609 VK_OBJECT_TYPE_CASE( VkDescriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET );
610 VK_OBJECT_TYPE_CASE( VkPipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT );
611 VK_OBJECT_TYPE_CASE( VkPipeline, VK_OBJECT_TYPE_PIPELINE );
612 VK_OBJECT_TYPE_CASE( VkCommandBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER );
613 VK_OBJECT_TYPE_CASE( VkSemaphore, VK_OBJECT_TYPE_SEMAPHORE );
614 VK_OBJECT_TYPE_CASE( VkFence, VK_OBJECT_TYPE_FENCE );
615 VK_OBJECT_TYPE_CASE( VkImage, VK_OBJECT_TYPE_IMAGE );
616 VK_OBJECT_TYPE_CASE( VkDeviceMemory, VK_OBJECT_TYPE_DEVICE_MEMORY );
617 VK_OBJECT_TYPE_CASE( VkImageView, VK_OBJECT_TYPE_IMAGE_VIEW );
618 VK_OBJECT_TYPE_CASE( VkSampler, VK_OBJECT_TYPE_SAMPLER );
619 VK_OBJECT_TYPE_CASE( VkRenderPass, VK_OBJECT_TYPE_RENDER_PASS );
620 VK_OBJECT_TYPE_CASE( VkShaderModule, VK_OBJECT_TYPE_SHADER_MODULE );
621 VK_OBJECT_TYPE_CASE( VkCommandPool, VK_OBJECT_TYPE_COMMAND_POOL );
622
623 PLOGF << "Failed to find the type of " << typeid( VulkanObjectType ).name();
624 return VK_OBJECT_TYPE_UNKNOWN;
625 }
626
633 template <typename VulkanObjectType>
634 static void setObjectName( VkDevice device, VulkanObjectType objectHandle, const std::string & name );
635
641 template <typename VulkanObjectType>
642 static std::string getDebugName ( VulkanObjectType objectHandle );
643#else
650 template <typename VulkanObjectType>
651 static void setObjectName( VkDevice device, VulkanObjectType objectHandle, const std::string & name )
652 {
653 }
654
660 template <typename VulkanObjectType>
661 static std::string getDebugName ( VulkanObjectType objectHandle )
662 {
663 return "";
664 }
665#endif
666
667private:
669 static DynamicFunctionInitState s_functionInitializationState;
670 static std::mutex s_mutex;
671};
672
673#ifdef IS_IN_DEBUG
674template <typename VulkanObjectType>
675void VulkanHelper::setObjectName( VkDevice device, VulkanObjectType objectHandle, const std::string & name )
676{
677 // Only proceed if the function pointer was successfully loaded
678 if ( s_functionInitializationState < DEBUG_FUNCTIONS_INITIALIZED ||
680 {
681 return;
682 }
683
684 VkDebugUtilsObjectNameInfoEXT nameInfo = {};
685 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
686 nameInfo.objectHandle = reinterpret_cast<uint64_t>( objectHandle );
687 nameInfo.objectType = VulkanHelper::getVulkanObjectType<VulkanObjectType>();
688 nameInfo.pObjectName = name.c_str();
689
690 // Call the function
691 s_functions.vkSetDebugUtilsObjectNameEXT( device, &nameInfo );
692
693 objectNames.insert( {reinterpret_cast<uint64_t>(objectHandle), name} );
694}
695
696template <typename VulkanObjectType>
697std::string VulkanHelper::getDebugName( VulkanObjectType objectHandle )
698{
699 const auto objectHandle64 = reinterpret_cast<uint64_t>( objectHandle );
700 if (!objectNames.contains( objectHandle64 ) )
701 {
702 return "Unnamed Object";
703 }
704 return objectNames.find( objectHandle64 )->second;
705}
706#endif
707
724{
725public:
726#ifdef IS_IN_DEBUG
733 DebugLabel( VkCommandBuffer commandBuffer, const char * pLabelName, const float color[4] = nullptr )
734 : m_commandBuffer( commandBuffer )
735 {
736 VulkanHelper::beginLabel( m_commandBuffer, pLabelName, color );
737 }
738
743 {
744 VulkanHelper::endLabel( m_commandBuffer );
745 }
746#else
750 DebugLabel( VkCommandBuffer, const char *, const float * = nullptr ) {}
751
756#endif
757
761 DebugLabel( const DebugLabel & ) = delete;
762
766 DebugLabel & operator=( const DebugLabel & ) = delete;
767
771 DebugLabel( DebugLabel && ) = delete;
772
777
778private:
779#ifdef IS_IN_DEBUG
780 VkCommandBuffer m_commandBuffer;
781#endif
782};
~DebugLabel()
Release-build no-op destructor.
DebugLabel(const DebugLabel &)=delete
Debug label scopes cannot be copied.
DebugLabel & operator=(const DebugLabel &)=delete
Debug label scopes cannot be copy-assigned.
DebugLabel(VkCommandBuffer, const char *, const float *=nullptr)
Release-build no-op constructor.
DebugLabel(DebugLabel &&)=delete
Debug label scopes cannot be moved.
DebugLabel & operator=(DebugLabel &&)=delete
Debug label scopes cannot be move-assigned.
The application context is the core class which stores the basic openxr and vulkan objects.
Static helpers for common Vulkan allocation, copy, descriptor, and debug operations.
static VkDescriptorBufferInfo fullBufferInfo(VkBuffer buffer)
Creates descriptor buffer info for a whole buffer binding.
static std::string getName(const std::string &name, const std::string &suffix)
Appends an object-type suffix to a debug name.
static VkResult createPipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout, const std::string &name)
Creates a pipeline layout and assigns a debug name.
static bool hasStencilComponent(VkFormat format)
Checks whether a Vulkan format contains a stencil component.
static void initializeFunctions(VkInstance instance, VkDevice device)
Loads all Vulkan extension functions used by the engine.
static void loadVkDeviceFunction(VkDevice device, const std::string &name, T &functionPointer)
Loads one Vulkan device-level function pointer.
static std::string getDebugName(VulkanObjectType objectHandle)
Release-build no-op for retrieving a Vulkan object debug name.
static void copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkDeviceSize size)
Copies bytes from one buffer to another and waits for the queue to become idle.
static VkResult createSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore, const std::string &name)
Creates a semaphore and assigns a debug name.
static std::string strIsValid(void *object)
Returns a checkmark or cross string for a Vulkan dispatchable handle value.
static DynamicFunctionInitState s_functionInitializationState
static VulkanFunctions s_functions
static const VulkanFunctions & getFunctions()
Returns the loaded Vulkan extension function table.
static void endLabel(VkCommandBuffer)
Release-build no-op for ending a Vulkan debug label region.
static VkImageView createImageView(VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags)
Creates a 2D image view over one mip level and one array layer.
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)
Creates a 2D image, allocates memory for it, and binds the memory at offset 0.
static bool isValid(void *object)
Checks whether a Vulkan dispatchable handle value is non-null.
static void copyBufferMultiple(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, const std::vector< BufferCopyObject > &bufferCopyObjects)
Copies several buffer regions in one command buffer and waits for the queue to become idle.
static VkDeviceSize align(VkDeviceSize value, VkDeviceSize alignment)
Rounds a size up to the next multiple of an alignment.
static VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool)
Allocates and begins a primary command buffer for one-time submission.
static void setObjectName(VkDevice device, VulkanObjectType objectHandle, const std::string &name)
Release-build no-op for assigning a Vulkan object debug name.
static void loadVkFunction(VkInstance instance, const std::string &name, T &functionPointer)
Loads one Vulkan instance-level function pointer.
static VkResult allocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets, const std::string &name)
Allocates descriptor sets and assigns a debug name to the first returned set.
static void recordBufferCopyMultiple(Engine::Core::ApplicationContext *context, VkCommandBuffer commandBuffer, const std::vector< BufferCopyObject > &bufferCopyObjects)
Records several buffer copy commands into an existing command buffer.
static void initializeDebugFunctions(VkInstance instance)
Loads debug utils extension functions from an instance.
static void endSingleTimeCommands(VkDevice device, VkQueue graphicsQueue, VkCommandPool commandPool, VkCommandBuffer commandBuffer)
Ends, submits, waits for, and frees a one-time command buffer.
static void copyBufferToImage(VkDevice device, VkCommandPool commandPool, VkQueue graphicsQueue, VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
Copies a buffer into the first layer and mip level of a 2D image.
static uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties)
Finds a memory type index that satisfies a bitmask and required properties.
static void createBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
Creates a Vulkan buffer, allocates memory for it, and binds the memory at offset 0.
static VkResult createDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool, const std::string &name)
Creates a descriptor pool and assigns a debug name.
static void createFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence, const std::string &name)
Creates a fence and assigns a debug name.
static VkResult createDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout, const std::string &name)
Creates a descriptor set layout and assigns a debug name.
static void transitionImageLayout(VkCommandBuffer commandBuffer, VkDevice device, VkQueue graphicsQueue, VkCommandPool commandPool, VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t layerCount=1)
Records an image layout transition barrier into an existing command buffer.
static void cleanupBuffer(VkDevice device, VkBuffer buffer, VkDeviceMemory bufferMemory)
Destroys a buffer and frees its memory when the handles are non-null.
static void beginLabel(VkCommandBuffer, const char *, const float *)
Release-build no-op for beginning a Vulkan debug label region.
static void uploadDataToExistingBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, VkDeviceSize size, const void *dataPtr, VkBuffer targetBuffer)
Uploads CPU memory into an existing buffer through a temporary staging buffer.
static std::mutex s_mutex
static bool findSuitableMemoryType(VkPhysicalDevice physicalDevice, VkMemoryRequirements2 requirements, VkMemoryPropertyFlags properties, uint32_t &out_typeIndex)
Finds a memory type index without throwing on failure.
static VkResult allocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers, const std::string &name)
Allocates command buffers and assigns a debug name to the first returned command buffer.
Description of one buffer-to-buffer copy operation.
VkBuffer sourceBuffer
Source buffer for the copy.
VkDeviceSize srcOffset
Byte offset in the source buffer.
VkDeviceSize size
Number of bytes to copy.
VkDeviceSize dstOffset
Offset in source buffer (usually 0 for staging)
VkBuffer destinationBuffer
Destination buffer for the copy.
Function pointers for Vulkan extension entry points used by the engine.
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT
Ends command-buffer debug labels.
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT
Ends conditional rendering.
PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT
Draws mesh tasks indirectly.
PFN_vkCmdBindDescriptorSets2 vkCmdBindDescriptorSets2
Binds descriptor sets with the Vulkan 1.4 entry point.
PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT
Begins conditional rendering.
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT
Creates debug messengers.
PFN_vkCmdPushConstants2 vkCmdPushConstants2
Pushes constants with the Vulkan 1.4 entry point.
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT
Destroys debug messengers.
PFN_vkCmdDrawMeshTasksIndirectCountEXT vkCmdDrawMeshTasksIndirectCountEXT
Draws mesh tasks with an indirect count.
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT
Begins command-buffer debug labels.
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT
Assigns debug names to Vulkan objects.