renderer_vulkan: Create debug callback on separate file and throw
Initialize debug callbacks (messenger) from a separate file. This allows sharing code with different backends. Change our Vulkan error handling to use exceptions instead of error codes, simplifying the initialization process.
This commit is contained in:
parent
25f88d99ce
commit
47843b4f09
|
@ -258,6 +258,8 @@ add_library(video_core STATIC
|
||||||
textures/texture.h
|
textures/texture.h
|
||||||
video_core.cpp
|
video_core.cpp
|
||||||
video_core.h
|
video_core.h
|
||||||
|
vulkan_common/vulkan_debug_callback.cpp
|
||||||
|
vulkan_common/vulkan_debug_callback.h
|
||||||
vulkan_common/vulkan_instance.cpp
|
vulkan_common/vulkan_instance.cpp
|
||||||
vulkan_common/vulkan_instance.h
|
vulkan_common/vulkan_instance.h
|
||||||
vulkan_common/vulkan_library.cpp
|
vulkan_common/vulkan_library.cpp
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||||
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
#include "video_core/renderer_vulkan/vk_swapchain.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_debug_callback.h"
|
||||||
#include "video_core/vulkan_common/vulkan_instance.h"
|
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||||
#include "video_core/vulkan_common/vulkan_library.h"
|
#include "video_core/vulkan_common/vulkan_library.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
@ -48,24 +49,6 @@
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
namespace {
|
namespace {
|
||||||
VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* data,
|
|
||||||
[[maybe_unused]] void* user_data) {
|
|
||||||
const char* const message{data->pMessage};
|
|
||||||
|
|
||||||
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
|
||||||
LOG_CRITICAL(Render_Vulkan, "{}", message);
|
|
||||||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
|
||||||
LOG_WARNING(Render_Vulkan, "{}", message);
|
|
||||||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
|
|
||||||
LOG_INFO(Render_Vulkan, "{}", message);
|
|
||||||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
|
|
||||||
LOG_DEBUG(Render_Vulkan, "{}", message);
|
|
||||||
}
|
|
||||||
return VK_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetReadableVersion(u32 version) {
|
std::string GetReadableVersion(u32 version) {
|
||||||
return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
|
return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
|
||||||
VK_VERSION_PATCH(version));
|
VK_VERSION_PATCH(version));
|
||||||
|
@ -158,7 +141,11 @@ bool RendererVulkan::Init() {
|
||||||
library = OpenLibrary();
|
library = OpenLibrary();
|
||||||
std::tie(instance, instance_version) = CreateInstance(
|
std::tie(instance, instance_version) = CreateInstance(
|
||||||
library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug);
|
library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug);
|
||||||
if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
|
if (Settings::values.renderer_debug) {
|
||||||
|
debug_callback = CreateDebugCallback(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateSurface() || !PickDevices()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,18 +188,6 @@ void RendererVulkan::ShutDown() {
|
||||||
device.reset();
|
device.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RendererVulkan::CreateDebugCallback() {
|
|
||||||
if (!Settings::values.renderer_debug) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
debug_callback = instance.TryCreateDebugCallback(DebugCallback);
|
|
||||||
if (!debug_callback) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to create debug callback");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RendererVulkan::CreateSurface() {
|
bool RendererVulkan::CreateSurface() {
|
||||||
[[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
|
[[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
|
||||||
VkSurfaceKHR unsafe_surface = nullptr;
|
VkSurfaceKHR unsafe_surface = nullptr;
|
||||||
|
|
|
@ -56,8 +56,6 @@ public:
|
||||||
static std::vector<std::string> EnumerateDevices();
|
static std::vector<std::string> EnumerateDevices();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateDebugCallback();
|
|
||||||
|
|
||||||
bool CreateSurface();
|
bool CreateSurface();
|
||||||
|
|
||||||
bool PickDevices();
|
bool PickDevices();
|
||||||
|
@ -78,7 +76,7 @@ private:
|
||||||
|
|
||||||
VKScreenInfo screen_info;
|
VKScreenInfo screen_info;
|
||||||
|
|
||||||
vk::DebugCallback debug_callback;
|
vk::DebugUtilsMessenger debug_callback;
|
||||||
std::unique_ptr<VKDevice> device;
|
std::unique_ptr<VKDevice> device;
|
||||||
std::unique_ptr<VKMemoryManager> memory_manager;
|
std::unique_ptr<VKMemoryManager> memory_manager;
|
||||||
std::unique_ptr<StateTracker> state_tracker;
|
std::unique_ptr<StateTracker> state_tracker;
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_debug_callback.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
namespace {
|
||||||
|
VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* data,
|
||||||
|
[[maybe_unused]] void* user_data) {
|
||||||
|
const std::string_view message{data->pMessage};
|
||||||
|
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||||
|
LOG_CRITICAL(Render_Vulkan, "{}", message);
|
||||||
|
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
||||||
|
LOG_WARNING(Render_Vulkan, "{}", message);
|
||||||
|
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
|
||||||
|
LOG_INFO(Render_Vulkan, "{}", message);
|
||||||
|
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
|
||||||
|
LOG_DEBUG(Render_Vulkan, "{}", message);
|
||||||
|
}
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
|
||||||
|
return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||||
|
.pfnUserCallback = Callback,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance);
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
|
@ -117,21 +117,20 @@ std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
|
||||||
bool enable_debug_utils, bool enable_layers) {
|
bool enable_debug_utils, bool enable_layers) {
|
||||||
if (!library.IsOpen()) {
|
if (!library.IsOpen()) {
|
||||||
LOG_ERROR(Render_Vulkan, "Vulkan library not available");
|
LOG_ERROR(Render_Vulkan, "Vulkan library not available");
|
||||||
return {};
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
|
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
|
||||||
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
|
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
|
||||||
return {};
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
if (!vk::Load(dld)) {
|
if (!vk::Load(dld)) {
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
||||||
return {};
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils);
|
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils);
|
||||||
if (!AreExtensionsSupported(dld, extensions)) {
|
if (!AreExtensionsSupported(dld, extensions)) {
|
||||||
return {};
|
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> layers = Layers(enable_layers);
|
std::vector<const char*> layers = Layers(enable_layers);
|
||||||
RemoveUnavailableLayers(dld, layers);
|
RemoveUnavailableLayers(dld, layers);
|
||||||
|
|
||||||
|
@ -139,12 +138,9 @@ std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
|
||||||
const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1);
|
const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1);
|
||||||
|
|
||||||
vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
|
vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
|
||||||
if (!instance) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (!vk::Load(*instance, dld)) {
|
if (!vk::Load(*instance, dld)) {
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
||||||
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
return std::make_pair(std::move(instance), version);
|
return std::make_pair(std::move(instance), version);
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,7 +435,7 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
|
Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
|
||||||
InstanceDispatch& dispatch) noexcept {
|
InstanceDispatch& dispatch) {
|
||||||
const VkApplicationInfo application_info{
|
const VkApplicationInfo application_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
@ -455,22 +455,17 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
|
||||||
.enabledExtensionCount = extensions.size(),
|
.enabledExtensionCount = extensions.size(),
|
||||||
.ppEnabledExtensionNames = extensions.data(),
|
.ppEnabledExtensionNames = extensions.data(),
|
||||||
};
|
};
|
||||||
|
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
|
Check(dispatch.vkCreateInstance(&ci, nullptr, &instance));
|
||||||
// Failed to create the instance.
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) {
|
if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) {
|
||||||
// We successfully created an instance but the destroy function couldn't be loaded.
|
// We successfully created an instance but the destroy function couldn't be loaded.
|
||||||
// This is a good moment to panic.
|
// This is a good moment to panic.
|
||||||
return {};
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Instance(instance, dispatch);
|
return Instance(instance, dispatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() {
|
std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() const {
|
||||||
u32 num;
|
u32 num;
|
||||||
if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
|
if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -483,27 +478,11 @@ std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices(
|
||||||
return std::make_optional(std::move(physical_devices));
|
return std::make_optional(std::move(physical_devices));
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugCallback Instance::TryCreateDebugCallback(
|
DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
|
||||||
PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
|
const VkDebugUtilsMessengerCreateInfoEXT& create_info) const {
|
||||||
const VkDebugUtilsMessengerCreateInfoEXT ci{
|
VkDebugUtilsMessengerEXT object;
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
Check(dld->vkCreateDebugUtilsMessengerEXT(handle, &create_info, nullptr, &object));
|
||||||
.pNext = nullptr,
|
return DebugUtilsMessenger(object, handle, *dld);
|
||||||
.flags = 0,
|
|
||||||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
|
||||||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
|
||||||
.pfnUserCallback = callback,
|
|
||||||
.pUserData = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDebugUtilsMessengerEXT messenger;
|
|
||||||
if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return DebugCallback(messenger, handle, *dld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
|
void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
|
||||||
|
|
|
@ -555,7 +555,7 @@ private:
|
||||||
const DeviceDispatch* dld = nullptr;
|
const DeviceDispatch* dld = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
|
using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
|
||||||
using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
|
using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
|
||||||
using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
|
using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
|
||||||
using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
|
using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
|
||||||
|
@ -573,16 +573,19 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
|
||||||
using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
|
using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Creates a Vulkan instance. Use "operator bool" for error handling.
|
/// Creates a Vulkan instance.
|
||||||
|
/// @throw Exception on initialization error.
|
||||||
static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
|
static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
|
||||||
InstanceDispatch& dispatch) noexcept;
|
InstanceDispatch& dispatch);
|
||||||
|
|
||||||
/// Enumerates physical devices.
|
/// Enumerates physical devices.
|
||||||
/// @return Physical devices and an empty handle on failure.
|
/// @return Physical devices and an empty handle on failure.
|
||||||
std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
|
std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices() const;
|
||||||
|
|
||||||
/// Tries to create a debug callback messenger. Returns an empty handle on failure.
|
/// Creates a debug callback messenger.
|
||||||
DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
|
/// @throw Exception on creation failure.
|
||||||
|
DebugUtilsMessenger CreateDebugUtilsMessenger(
|
||||||
|
const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Queue {
|
class Queue {
|
||||||
|
|
Reference in New Issue