video_core/vulkan: Add debug object names (#7233)

* vk_platform: Add `SetObjectName`

Creates a name-info struct and automatically deduces the object handle type using vulkan-hpp's handle trait data.
Supports `string_view` and `fmt` arguments.

* vk_texture_runtime: Use `SetObjectName` for surface handles

Names both the image handle and the image-view.

* vk_stream_buffer: Add debug object names

Names the buffer and its device memory based on its size and type.

* vk_swapchain: Set swapchain handle debug names

Identifies the swapchain images themselves as well as the semaphores

* vk_present_window: Set handle debug names

* vk_resource_pool: Set debug handle names

* vk_blit_helper: Set debug handle names

* vk_platform: Use `VulkanHandleType` concept

Use a new `concept`-type rather than `enable_if`-patterns to restrict
this function to Vulkan handle-types only.
This commit is contained in:
Wunk 2023-12-07 20:58:47 -08:00 committed by GitHub
parent 59df319f48
commit 4d9eedd0d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 11 deletions

View file

@ -198,7 +198,27 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_, Descrip
MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)}, MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)},
depth_blit_pipeline{MakeDepthStencilBlitPipeline()}, depth_blit_pipeline{MakeDepthStencilBlitPipeline()},
linear_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eLinear>)}, linear_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eLinear>)},
nearest_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eNearest>)} {} nearest_sampler{device.createSampler(SAMPLER_CREATE_INFO<vk::Filter::eNearest>)} {
if (instance.HasDebuggingToolAttached()) {
SetObjectName(device, compute_pipeline_layout, "BlitHelper: compute_pipeline_layout");
SetObjectName(device, compute_buffer_pipeline_layout,
"BlitHelper: compute_buffer_pipeline_layout");
SetObjectName(device, two_textures_pipeline_layout,
"BlitHelper: two_textures_pipeline_layout");
SetObjectName(device, full_screen_vert, "BlitHelper: full_screen_vert");
SetObjectName(device, d24s8_to_rgba8_comp, "BlitHelper: d24s8_to_rgba8_comp");
SetObjectName(device, depth_to_buffer_comp, "BlitHelper: depth_to_buffer_comp");
SetObjectName(device, blit_depth_stencil_frag, "BlitHelper: blit_depth_stencil_frag");
SetObjectName(device, d24s8_to_rgba8_pipeline, "BlitHelper: d24s8_to_rgba8_pipeline");
SetObjectName(device, depth_to_buffer_pipeline, "BlitHelper: depth_to_buffer_pipeline");
if (depth_blit_pipeline) {
SetObjectName(device, depth_blit_pipeline, "BlitHelper: depth_blit_pipeline");
}
SetObjectName(device, linear_sampler, "BlitHelper: linear_sampler");
SetObjectName(device, nearest_sampler, "BlitHelper: nearest_sampler");
}
}
BlitHelper::~BlitHelper() { BlitHelper::~BlitHelper() {
device.destroyPipelineLayout(compute_pipeline_layout); device.destroyPipelineLayout(compute_pipeline_layout);

View file

@ -33,4 +33,24 @@ vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library,
DebugCallback CreateDebugCallback(vk::Instance instance, bool& debug_utils_supported); DebugCallback CreateDebugCallback(vk::Instance instance, bool& debug_utils_supported);
template <typename T>
concept VulkanHandleType = vk::isVulkanHandleType<T>::value;
template <VulkanHandleType HandleType>
void SetObjectName(vk::Device device, const HandleType& handle, std::string_view debug_name) {
const vk::DebugUtilsObjectNameInfoEXT name_info = {
.objectType = HandleType::objectType,
.objectHandle = reinterpret_cast<u64>(static_cast<typename HandleType::NativeType>(handle)),
.pObjectName = debug_name.data(),
};
device.setDebugUtilsObjectNameEXT(name_info);
}
template <VulkanHandleType HandleType, typename... Args>
void SetObjectName(vk::Device device, const HandleType& handle, const char* format,
const Args&... args) {
const std::string debug_name = fmt::vformat(format, fmt::make_format_args(args...));
SetObjectName(device, handle, debug_name);
}
} // namespace Vulkan } // namespace Vulkan

View file

@ -11,6 +11,7 @@
#include "video_core/renderer_vulkan/vk_present_window.h" #include "video_core/renderer_vulkan/vk_present_window.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/vk_swapchain.h"
#include "vk_platform.h"
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
@ -135,6 +136,16 @@ PresentWindow::PresentWindow(Frontend::EmuWindow& emu_window_, const Instance& i
free_queue.push(&frame); free_queue.push(&frame);
} }
if (instance.HasDebuggingToolAttached()) {
for (u32 i = 0; i < num_images; ++i) {
Vulkan::SetObjectName(device, swap_chain[i].cmdbuf, "Swapchain Command Buffer {}", i);
Vulkan::SetObjectName(device, swap_chain[i].render_ready,
"Swapchain Semaphore: render_ready {}", i);
Vulkan::SetObjectName(device, swap_chain[i].present_done,
"Swapchain Fence: present_done {}", i);
}
}
if (use_present_thread) { if (use_present_thread) {
present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); }); present_thread = std::jthread([this](std::stop_token token) { PresentThread(token); });
} }

View file

@ -101,6 +101,15 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
auto buffers = device.allocateCommandBuffers(buffer_alloc_info); auto buffers = device.allocateCommandBuffers(buffer_alloc_info);
std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin()); std::copy(buffers.begin(), buffers.end(), pool.cmdbufs.begin());
if (instance.HasDebuggingToolAttached()) {
Vulkan::SetObjectName(device, pool.handle, "CommandPool: Pool({})",
COMMAND_BUFFER_POOL_SIZE);
for (u32 i = 0; i < pool.cmdbufs.size(); ++i) {
Vulkan::SetObjectName(device, pool.cmdbufs[i], "CommandPool: Command Buffer {}", i);
}
}
} }
vk::CommandBuffer CommandPool::Commit() { vk::CommandBuffer CommandPool::Commit() {

View file

@ -173,7 +173,7 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) {
stream_buffer_size = static_cast<u64>(requirements.memoryRequirements.size); stream_buffer_size = static_cast<u64>(requirements.memoryRequirements.size);
LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KB with flags {}", LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KiB with flags {}",
BufferTypeName(type), stream_buffer_size / 1024, BufferTypeName(type), stream_buffer_size / 1024,
vk::to_string(mem_type.propertyFlags)); vk::to_string(mem_type.propertyFlags));
@ -198,6 +198,14 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) {
device.bindBufferMemory(buffer, memory, 0); device.bindBufferMemory(buffer, memory, 0);
mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE)); mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE));
if (instance.HasDebuggingToolAttached()) {
Vulkan::SetObjectName(device, buffer, "StreamBuffer({}): {} KiB {}", BufferTypeName(type),
stream_buffer_size / 1024, vk::to_string(mem_type.propertyFlags));
Vulkan::SetObjectName(device, memory, "StreamBufferMemory({}): {} Kib {}",
BufferTypeName(type), stream_buffer_size / 1024,
vk::to_string(mem_type.propertyFlags));
}
} }
void StreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) { void StreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {

View file

@ -247,12 +247,27 @@ void Swapchain::RefreshSemaphores() {
for (vk::Semaphore& semaphore : present_ready) { for (vk::Semaphore& semaphore : present_ready) {
semaphore = device.createSemaphore({}); semaphore = device.createSemaphore({});
} }
if (instance.HasDebuggingToolAttached()) {
for (u32 i = 0; i < image_count; ++i) {
Vulkan::SetObjectName(device, image_acquired[i],
"Swapchain Semaphore: image_acquired {}", i);
Vulkan::SetObjectName(device, present_ready[i], "Swapchain Semaphore: present_ready {}",
i);
}
}
} }
void Swapchain::SetupImages() { void Swapchain::SetupImages() {
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
images = device.getSwapchainImagesKHR(swapchain); images = device.getSwapchainImagesKHR(swapchain);
image_count = static_cast<u32>(images.size()); image_count = static_cast<u32>(images.size());
if (instance.HasDebuggingToolAttached()) {
for (u32 i = 0; i < image_count; ++i) {
Vulkan::SetObjectName(device, images[i], "Swapchain Image {}", i);
}
}
} }
} // namespace Vulkan } // namespace Vulkan

View file

@ -189,15 +189,6 @@ Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, T
UNREACHABLE(); UNREACHABLE();
} }
if (!debug_name.empty() && instance->HasDebuggingToolAttached()) {
const vk::DebugUtilsObjectNameInfoEXT name_info = {
.objectType = vk::ObjectType::eImage,
.objectHandle = reinterpret_cast<u64>(unsafe_image),
.pObjectName = debug_name.data(),
};
instance->GetDevice().setDebugUtilsObjectNameEXT(name_info);
}
const vk::Image image{unsafe_image}; const vk::Image image{unsafe_image};
const vk::ImageViewCreateInfo view_info = { const vk::ImageViewCreateInfo view_info = {
.image = image, .image = image,
@ -214,6 +205,12 @@ Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, T
}; };
vk::UniqueImageView image_view = instance->GetDevice().createImageViewUnique(view_info); vk::UniqueImageView image_view = instance->GetDevice().createImageViewUnique(view_info);
if (!debug_name.empty() && instance->HasDebuggingToolAttached()) {
Vulkan::SetObjectName(instance->GetDevice(), image, debug_name);
Vulkan::SetObjectName(instance->GetDevice(), image_view.get(), "{} View({})", debug_name,
vk::to_string(aspect));
}
return Handle{ return Handle{
.alloc = allocation, .alloc = allocation,
.image = image, .image = image,