From bebb17a9734a48ee58f7e7352c70ccf0de6c2d1e Mon Sep 17 00:00:00 2001 From: AgAmemnno Date: Fri, 21 Apr 2023 12:32:40 +0200 Subject: [PATCH] Vulkan: Provide Debug Utilities This PR uses the VK_EXT_debug_utils extension, but it's only for labeling, so it doesn't rely on the VK_LAYER_KHRONOS_validation functionality. The functions that do these things are loaded into the runtime as vulkan extensions. Declare the function pointers in a struct and make them members of vk_context. Pull Request: https://projects.blender.org/blender/blender/pulls/106098 --- intern/ghost/intern/GHOST_ContextVK.cc | 9 +- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/tests/shader_test.cc | 2 +- source/blender/gpu/vulkan/vk_common.hh | 64 ++++++++++ source/blender/gpu/vulkan/vk_context.cc | 7 +- source/blender/gpu/vulkan/vk_context.hh | 21 ++- source/blender/gpu/vulkan/vk_debug.cc | 163 ++++++++++++++++++++++++ source/blender/gpu/vulkan/vk_debug.hh | 60 +++++++++ 8 files changed, 320 insertions(+), 7 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_debug.hh diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index d1dc8083955..74cc42e9176 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -903,13 +903,14 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() auto extensions_available = getExtensionsAvailable(); vector layers_enabled; - if (m_debug) { - enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug); - } - vector extensions_device; vector extensions_enabled; + if (m_debug) { + enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug); + requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + if (use_window_surface) { const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension(); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 4305778d21f..675d7c22b81 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -235,6 +235,7 @@ set(VULKAN_SRC vulkan/vk_common.hh vulkan/vk_context.hh vulkan/vk_data_conversion.hh + vulkan/vk_debug.hh vulkan/vk_descriptor_pools.hh vulkan/vk_descriptor_set.hh vulkan/vk_drawlist.hh diff --git a/source/blender/gpu/tests/shader_test.cc b/source/blender/gpu/tests/shader_test.cc index 26536dd221f..c6911314210 100644 --- a/source/blender/gpu/tests/shader_test.cc +++ b/source/blender/gpu/tests/shader_test.cc @@ -145,7 +145,7 @@ static void test_shader_compute_vbo() GPU_shader_bind(shader); /* Construct VBO. */ - static GPUVertFormat format = {0}; + GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DEVICE_ONLY); GPU_vertbuf_data_alloc(vbo, SIZE); diff --git a/source/blender/gpu/vulkan/vk_common.hh b/source/blender/gpu/vulkan/vk_common.hh index d8b5df769fd..a09270908f7 100644 --- a/source/blender/gpu/vulkan/vk_common.hh +++ b/source/blender/gpu/vulkan/vk_common.hh @@ -7,6 +7,8 @@ #pragma once +#include + #ifdef __APPLE__ # include #else @@ -25,5 +27,67 @@ VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat format); VkImageViewType to_vk_image_view_type(const eGPUTextureType type); VkImageType to_vk_image_type(const eGPUTextureType type); VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const void *data); +#ifdef __cplusplus +template VkObjectType to_vk_object_type(T /*vk_obj*/) +{ + const std::type_info &tid = typeid(T); +# define VK_EQ_TYPEID(name, name2) \ + if (tid == typeid(name)) { \ + return VK_OBJECT_TYPE_##name2; \ + } + VK_EQ_TYPEID(VkInstance, INSTANCE); + VK_EQ_TYPEID(VkPhysicalDevice, PHYSICAL_DEVICE); + VK_EQ_TYPEID(VkDevice, DEVICE); + VK_EQ_TYPEID(VkQueue, QUEUE); + VK_EQ_TYPEID(VkSemaphore, SEMAPHORE); + VK_EQ_TYPEID(VkCommandBuffer, COMMAND_BUFFER); + VK_EQ_TYPEID(VkFence, FENCE); + VK_EQ_TYPEID(VkDeviceMemory, DEVICE_MEMORY); + VK_EQ_TYPEID(VkBuffer, BUFFER); + VK_EQ_TYPEID(VkImage, IMAGE); + VK_EQ_TYPEID(VkEvent, EVENT); + VK_EQ_TYPEID(VkQueryPool, QUERY_POOL); + VK_EQ_TYPEID(VkBufferView, BUFFER_VIEW); + VK_EQ_TYPEID(VkImageView, IMAGE_VIEW); + VK_EQ_TYPEID(VkShaderModule, SHADER_MODULE); + VK_EQ_TYPEID(VkPipelineCache, PIPELINE_CACHE); + VK_EQ_TYPEID(VkPipelineLayout, PIPELINE_LAYOUT); + VK_EQ_TYPEID(VkRenderPass, RENDER_PASS); + VK_EQ_TYPEID(VkPipeline, PIPELINE); + VK_EQ_TYPEID(VkDescriptorSetLayout, DESCRIPTOR_SET_LAYOUT); + VK_EQ_TYPEID(VkSampler, SAMPLER); + VK_EQ_TYPEID(VkDescriptorPool, DESCRIPTOR_POOL); + VK_EQ_TYPEID(VkDescriptorSet, DESCRIPTOR_SET); + VK_EQ_TYPEID(VkFramebuffer, FRAMEBUFFER); + VK_EQ_TYPEID(VkCommandPool, COMMAND_POOL); + VK_EQ_TYPEID(VkSamplerYcbcrConversion, SAMPLER_YCBCR_CONVERSION); + VK_EQ_TYPEID(VkDescriptorUpdateTemplate, DESCRIPTOR_UPDATE_TEMPLATE); + VK_EQ_TYPEID(VkSurfaceKHR, SURFACE_KHR); + VK_EQ_TYPEID(VkSwapchainKHR, SWAPCHAIN_KHR); + VK_EQ_TYPEID(VkDisplayKHR, DISPLAY_KHR); + VK_EQ_TYPEID(VkDisplayModeKHR, DISPLAY_MODE_KHR); + VK_EQ_TYPEID(VkDebugReportCallbackEXT, DEBUG_REPORT_CALLBACK_EXT); +# ifdef VK_ENABLE_BETA_EXTENSIONS + VK_EQ_TYPEID(VkVideoSessionKHR, VIDEO_SESSION_KHR); +# endif +# ifdef VK_ENABLE_BETA_EXTENSIONS + VK_EQ_TYPEID(VkVideoSessionParametersKHR, VIDEO_SESSION_PARAMETERS_KHR); +# endif + VK_EQ_TYPEID(VkCuModuleNVX, CU_MODULE_NVX); + VK_EQ_TYPEID(VkCuFunctionNVX, CU_FUNCTION_NVX); + VK_EQ_TYPEID(VkDebugUtilsMessengerEXT, DEBUG_UTILS_MESSENGER_EXT); + VK_EQ_TYPEID(VkAccelerationStructureKHR, ACCELERATION_STRUCTURE_KHR); + VK_EQ_TYPEID(VkValidationCacheEXT, VALIDATION_CACHE_EXT); + VK_EQ_TYPEID(VkAccelerationStructureNV, ACCELERATION_STRUCTURE_NV); + VK_EQ_TYPEID(VkPerformanceConfigurationINTEL, PERFORMANCE_CONFIGURATION_INTEL); + VK_EQ_TYPEID(VkDeferredOperationKHR, DEFERRED_OPERATION_KHR); + VK_EQ_TYPEID(VkIndirectCommandsLayoutNV, INDIRECT_COMMANDS_LAYOUT_NV); + VK_EQ_TYPEID(VkPrivateDataSlotEXT, PRIVATE_DATA_SLOT_EXT); + + BLI_assert_unreachable(); +# undef VK_EQ_TYPEID + return VK_OBJECT_TYPE_UNKNOWN; +} +#endif } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index b77b6693261..a71910ee71a 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -4,8 +4,8 @@ /** \file * \ingroup gpu */ - #include "vk_context.hh" +#include "vk_debug.hh" #include "vk_backend.hh" #include "vk_framebuffer.hh" @@ -31,8 +31,12 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) &vk_device_, &vk_queue_family_, &vk_queue_); + debug::init_callbacks(this, vkGetInstanceProcAddr); init_physical_device_limits(); + debug::object_label(this, vk_device_, "LogicalDevice"); + debug::object_label(this, vk_queue_, "GenericQueue"); + /* Initialize the memory allocator. */ VmaAllocatorCreateInfo info = {}; /* Should use same vulkan version as GHOST (1.2), but set to 1.0 as 1.2 requires @@ -57,6 +61,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) VKContext::~VKContext() { vmaDestroyAllocator(mem_allocator_); + debug::destroy_callbacks(this); } void VKContext::init_physical_device_limits() diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 2025c27ed4d..b65fa13edd7 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -8,8 +8,9 @@ #pragma once #include "gpu_context_private.hh" - #include "vk_command_buffer.hh" +#include "vk_common.hh" +#include "vk_debug.hh" #include "vk_descriptor_pools.hh" namespace blender::gpu { @@ -32,6 +33,9 @@ class VKContext : public Context { /** Limits of the device linked to this context. */ VkPhysicalDeviceLimits vk_physical_device_limits_; + /** Functions of vk_ext_debugutils to use in this context. */ + debug::VKDebuggingTools debugging_tools_; + void *ghost_context_; public: @@ -74,6 +78,11 @@ class VKContext : public Context { return vk_physical_device_limits_; } + VkInstance instance_get() const + { + return vk_instance_; + }; + VkDevice device_get() const { return vk_device_; @@ -104,6 +113,16 @@ class VKContext : public Context { return mem_allocator_; } + debug::VKDebuggingTools &debugging_tools_get() + { + return debugging_tools_; + } + + const debug::VKDebuggingTools &debugging_tools_get() const + { + return debugging_tools_; + } + private: void init_physical_device_limits(); diff --git a/source/blender/gpu/vulkan/vk_debug.cc b/source/blender/gpu/vulkan/vk_debug.cc index 29c66df6d33..32fc70e37bf 100644 --- a/source/blender/gpu/vulkan/vk_debug.cc +++ b/source/blender/gpu/vulkan/vk_debug.cc @@ -5,8 +5,11 @@ * \ingroup gpu */ +#include "BKE_global.h" + #include "vk_backend.hh" #include "vk_context.hh" +#include "vk_debug.hh" namespace blender::gpu { void VKContext::debug_group_begin(const char *, int) {} @@ -54,3 +57,163 @@ bool VKContext::debug_capture_scope_begin(void * /*scope*/) void VKContext::debug_capture_scope_end(void * /*scope*/) {} } // namespace blender::gpu + +namespace blender::gpu::debug { + +static void load_dynamic_functions(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr) +{ + VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + VkInstance vk_instance = context->instance_get(); + + if (instance_proc_addr) { + + debugging_tools.enabled = false; + debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = (PFN_vkCmdBeginDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkCmdBeginDebugUtilsLabelEXT"); + debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = (PFN_vkCmdEndDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkCmdEndDebugUtilsLabelEXT"); + debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = (PFN_vkCmdInsertDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkCmdInsertDebugUtilsLabelEXT"); + debugging_tools.vkCreateDebugUtilsMessengerEXT_r = (PFN_vkCreateDebugUtilsMessengerEXT)instance_proc_addr( + vk_instance, "vkCreateDebugUtilsMessengerEXT"); + debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = (PFN_vkDestroyDebugUtilsMessengerEXT)instance_proc_addr( + vk_instance, "vkDestroyDebugUtilsMessengerEXT"); + debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = (PFN_vkQueueBeginDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkQueueBeginDebugUtilsLabelEXT"); + debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = (PFN_vkQueueEndDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkQueueEndDebugUtilsLabelEXT"); + debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = (PFN_vkQueueInsertDebugUtilsLabelEXT)instance_proc_addr( + vk_instance, "vkQueueInsertDebugUtilsLabelEXT"); + debugging_tools.vkSetDebugUtilsObjectNameEXT_r = (PFN_vkSetDebugUtilsObjectNameEXT)instance_proc_addr( + vk_instance, "vkSetDebugUtilsObjectNameEXT"); + debugging_tools.vkSetDebugUtilsObjectTagEXT_r = (PFN_vkSetDebugUtilsObjectTagEXT)instance_proc_addr( + vk_instance, "vkSetDebugUtilsObjectTagEXT"); + debugging_tools.vkSubmitDebugUtilsMessageEXT_r = (PFN_vkSubmitDebugUtilsMessageEXT)instance_proc_addr( + vk_instance, "vkSubmitDebugUtilsMessageEXT"); + if (debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r) { + debugging_tools.enabled = true; + } + } + else { + debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkCreateDebugUtilsMessengerEXT_r = nullptr; + debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = nullptr; + debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = nullptr; + debugging_tools.vkSetDebugUtilsObjectNameEXT_r = nullptr; + debugging_tools.vkSetDebugUtilsObjectTagEXT_r = nullptr; + debugging_tools.vkSubmitDebugUtilsMessageEXT_r = nullptr; + debugging_tools.enabled = false; + } +} + +bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr) +{ + if (instance_proc_addr) { + load_dynamic_functions(context, instance_proc_addr); + return true; + }; + return false; +} + +void destroy_callbacks(VKContext *context) +{ + VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + load_dynamic_functions(context, nullptr); + } +} + +void object_label(VKContext *context, + VkObjectType vk_object_type, + uint64_t object_handle, + const char *name) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + VkDebugUtilsObjectNameInfoEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + info.objectType = vk_object_type; + info.objectHandle = object_handle; + info.pObjectName = name; + debugging_tools.vkSetDebugUtilsObjectNameEXT_r(context->device_get(), &info); + } + } +} + +void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + VkDebugUtilsLabelEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + info.pLabelName = name; + debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r(vk_command_buffer, &info); + } + } +} + +void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + VkDebugUtilsLabelEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + info.pLabelName = name; + debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r(vk_command_buffer, &info); + } + } +} + +void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + debugging_tools.vkCmdEndDebugUtilsLabelEXT_r(vk_command_buffer); + } + } +} + +void push_marker(VKContext *context, VkQueue vk_queue, const char *name) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + VkDebugUtilsLabelEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + info.pLabelName = name; + debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r(vk_queue, &info); + } + } +} + +void set_marker(VKContext *context, VkQueue vk_queue, const char *name) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + VkDebugUtilsLabelEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + info.pLabelName = name; + debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r(vk_queue, &info); + } + } +} + +void pop_marker(VKContext *context, VkQueue vk_queue) +{ + if (G.debug & G_DEBUG_GPU) { + const VKDebuggingTools &debugging_tools = context->debugging_tools_get(); + if (debugging_tools.enabled) { + debugging_tools.vkQueueEndDebugUtilsLabelEXT_r(vk_queue); + } + } +} +} // namespace blender::gpu::debug diff --git a/source/blender/gpu/vulkan/vk_debug.hh b/source/blender/gpu/vulkan/vk_debug.hh new file mode 100644 index 00000000000..590a97c1fef --- /dev/null +++ b/source/blender/gpu/vulkan/vk_debug.hh @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ +#pragma once + +#include "BKE_global.h" +#include "BLI_string.h" + +#include "vk_common.hh" + +#include + +namespace blender::gpu { +class VKContext; +namespace debug { +typedef struct VKDebuggingTools { + bool enabled = false; + /* Function pointer definitions. */ + PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_r = nullptr; + PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_r = nullptr; + PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT_r = nullptr; + PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT_r = nullptr; + PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT_r = nullptr; + PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT_r = nullptr; + PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT_r = nullptr; + PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT_r = nullptr; + PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT_r = nullptr; + PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_r = nullptr; + PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT_r = nullptr; + +} VKDebuggingTools; + +bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr); +void destroy_callbacks(VKContext *context); +void object_label(VKContext *context, VkObjectType vk_object_type, uint64_t object_handle, const char *name); + +template void object_label(VKContext *context, T vk_object_type, const char *name) +{ + if (!(G.debug & G_DEBUG_GPU)) { + return; + } + const size_t label_size = 64; + char label[label_size]; + memset(label, 0, label_size); + static int stats = 0; + SNPRINTF(label, "%s_%d", name, stats++); + object_label(context, to_vk_object_type(vk_object_type), (uint64_t)vk_object_type, (const char *)label); +}; + +void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name); +void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name); +void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer); +void push_marker(VKContext *context, VkQueue vk_queue, const char *name); +void set_marker(VKContext *context, VkQueue vk_queue, const char *name); +void pop_marker(VKContext *context, VkQueue vk_queue); +} // namespace debug +} // namespace blender::gpu