Vulkan: Provide utilities to put markers and labels where needed in the GPUmodule #106098

Merged
Jeroen Bakker merged 29 commits from :vk_debug_update into main 2023-04-21 12:32:52 +02:00
8 changed files with 320 additions and 7 deletions

View File

@ -903,13 +903,14 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
auto extensions_available = getExtensionsAvailable();
vector<const char *> layers_enabled;
if (m_debug) {
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
}
vector<const char *> extensions_device;
vector<const char *> 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();

View File

@ -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

View File

@ -145,7 +145,7 @@ static void test_shader_compute_vbo()
GPU_shader_bind(shader);
/* Construct VBO. */
static GPUVertFormat format = {0};
GPUVertFormat format = {0};
Review

The OpenGL test increments the vertex buffer attribute length, causing a subsequent Vulkan test to run-time check failure #2.

The OpenGL test increments the vertex buffer attribute length, causing a subsequent Vulkan test to run-time check failure #2.
Review

You're right. Will change in main branch.

You're right. Will change in main branch.
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);

View File

@ -7,6 +7,8 @@
#pragma once
#include <typeinfo>
#ifdef __APPLE__
# include <MoltenVK/vk_mvk_moltenvk.h>
#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<typename T> 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;
}
vnapdv marked this conversation as resolved Outdated

// namespace blender::gpu can be removed.

`// namespace blender::gpu` can be removed.
#endif
} // namespace blender::gpu

View File

@ -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");
vnapdv marked this conversation as resolved Outdated

In the name Vk is redundant. Would use
"LogicalDevice" and "GenericQueue" is enough.

Generic as it handles compute shaders as well. In the future the plan is to have multiple queue families (async compute) as a separate queue.

In the name Vk is redundant. Would use "LogicalDevice" and "GenericQueue" is enough. Generic as it handles compute shaders as well. In the future the plan is to have multiple queue families (async compute) as a separate queue.
/* 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);
Review

This break is as a chain on the device. It has no direct relationship with VKContext.

This break is as a chain on the device. It has no direct relationship with VKContext.
}
void VKContext::init_physical_device_limits()

View File

@ -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();

View File

@ -5,8 +5,11 @@
* \ingroup gpu
*/
vnapdv marked this conversation as resolved Outdated

Add empty lines between each category of includes

Add empty lines between each category of includes
#include "BKE_global.h"
#include "vk_backend.hh"
#include "vk_context.hh"
#include "vk_debug.hh"
vnapdv marked this conversation as resolved Outdated

Add empty line between includes and code.

Add empty line between includes and code.
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)

rename function to load_dynamic_functions. the terms vulkan and debug are redundant.

rename function to `load_dynamic_functions`. the terms vulkan and debug are redundant.
{
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;
vnapdv marked this conversation as resolved
Review

use context when referring to VKContext (be consistent with other areas of the code-base)

When referring to instances of the Vulkan API it is used. Eg VkCommandBuffer parameters should be named vk_command_buffer VKCommandBuffer (internal class) should be referred to as command_buffer.

Abbreviations like q should not be used, just call them what they are queue.

etc

use `context` when referring to `VKContext` (be consistent with other areas of the code-base) When referring to instances of the Vulkan API it is used. Eg VkCommandBuffer parameters should be named `vk_command_buffer` VKCommandBuffer (internal class) should be referred to as `command_buffer`. Abbreviations like `q` should not be used, just call them what they are `queue`. etc
}
void destroy_callbacks(VKContext *context)
{
VKDebuggingTools &debugging_tools = context->debugging_tools_get();
if (debugging_tools.enabled) {
vnapdv marked this conversation as resolved Outdated

/home/jeroen/blender-git/blender/source/blender/gpu/vulkan/vk_debug.cc:125:26: warning: variable ‘tools’ set but not used [-Wunused-but-set-variable]

`/home/jeroen/blender-git/blender/source/blender/gpu/vulkan/vk_debug.cc:125:26: warning: variable ‘tools’ set but not used [-Wunused-but-set-variable]`
load_dynamic_functions(context, nullptr);
}
}
void object_label(VKContext *context,

obj isn't very useful. would use object_handle

`obj` isn't very useful. would use `object_handle`
VkObjectType vk_object_type,

objType -> vk_object_type

`objType` -> `vk_object_type`
uint64_t object_handle,
vnapdv marked this conversation as resolved Outdated

Add empty line between each function.

Add empty line between each function.
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);
}
}
Review

cmd -> vk_command_buffer. No need to confuse readers with incorrect abbreviations.

Also check the other functions.

`cmd` -> `vk_command_buffer`. No need to confuse readers with incorrect abbreviations. Also check the other functions.
}
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);
}
}
Review

queue -> vk_queue.

I add vk_ to all Vulkan API data types to not confuse them with our internal types. Best to keep this consistent. I know not all parts already use this convention. But would want all the new code to follow it.

Also check other functions below.

`queue` -> `vk_queue`. I add `vk_` to all Vulkan API data types to not confuse them with our internal types. Best to keep this consistent. I know not all parts already use this convention. But would want all the new code to follow it. Also check other functions below.
}
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

View File

@ -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 <typeindex>
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;
vnapdv marked this conversation as resolved Outdated

we should remove vk from the function names it is redundant in these cases

we should remove vk from the function names it is redundant in these cases
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);

obj -> object_handle

`obj` -> `object_handle`
template<typename T> 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);
};
vnapdv marked this conversation as resolved Outdated

push_marker / pop_marker / set_marker

`push_marker` / `pop_marker` / `set_marker`

Also update the definitions to match the parameter names of the implementation.

Also update the definitions to match the parameter names of the implementation.
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