2023-06-20 14:24:24 +02:00
|
|
|
// Copyright 2023 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
// Include the vulkan platform specific header
|
|
|
|
#if defined(ANDROID)
|
|
|
|
#define VK_USE_PLATFORM_ANDROID_KHR
|
|
|
|
#elif defined(WIN32)
|
|
|
|
#define VK_USE_PLATFORM_WIN32_KHR
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
#define VK_USE_PLATFORM_METAL_EXT
|
|
|
|
#else
|
|
|
|
#define VK_USE_PLATFORM_WAYLAND_KHR
|
|
|
|
#define VK_USE_PLATFORM_XLIB_KHR
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
#include <boost/container/static_vector.hpp>
|
2024-02-16 04:38:32 +01:00
|
|
|
#include <fmt/format.h>
|
2023-06-20 14:24:24 +02:00
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
#include "common/settings.h"
|
|
|
|
#include "core/frontend/emu_window.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
|
|
|
|
|
|
|
namespace Vulkan {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(
|
|
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type,
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) {
|
|
|
|
|
|
|
|
switch (callback_data->messageIdNumber) {
|
|
|
|
case 0x609a13b: // Vertex attribute at location not consumed by shader
|
|
|
|
return VK_FALSE;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-06-24 00:51:16 +02:00
|
|
|
Common::Log::Level level{};
|
2023-06-20 14:24:24 +02:00
|
|
|
switch (severity) {
|
|
|
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Error;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Info;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
|
|
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Debug;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
default:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Info;
|
2023-06-20 14:24:24 +02:00
|
|
|
}
|
|
|
|
|
2023-06-24 00:51:16 +02:00
|
|
|
LOG_GENERIC(Common::Log::Class::Render_Vulkan, level, "{}: {}",
|
2023-06-20 14:24:24 +02:00
|
|
|
callback_data->pMessageIdName ? callback_data->pMessageIdName : "<null>",
|
|
|
|
callback_data->pMessage ? callback_data->pMessage : "<null>");
|
|
|
|
|
|
|
|
return VK_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
|
|
|
|
VkDebugReportObjectTypeEXT objectType,
|
2024-01-07 21:37:42 +01:00
|
|
|
uint64_t object, std::size_t location,
|
2023-06-20 14:24:24 +02:00
|
|
|
int32_t messageCode,
|
|
|
|
const char* pLayerPrefix,
|
|
|
|
const char* pMessage, void* pUserData) {
|
|
|
|
|
|
|
|
const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags);
|
2023-06-24 00:51:16 +02:00
|
|
|
Common::Log::Level level{};
|
2023-06-20 14:24:24 +02:00
|
|
|
switch (severity) {
|
|
|
|
case VK_DEBUG_REPORT_ERROR_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Error;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Warning;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
|
|
|
|
case VK_DEBUG_REPORT_WARNING_BIT_EXT:
|
|
|
|
case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Debug;
|
2023-06-20 14:24:24 +02:00
|
|
|
break;
|
|
|
|
default:
|
2023-06-24 00:51:16 +02:00
|
|
|
level = Common::Log::Level::Info;
|
2023-06-20 14:24:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const vk::DebugReportObjectTypeEXT type = static_cast<vk::DebugReportObjectTypeEXT>(objectType);
|
2023-06-24 00:51:16 +02:00
|
|
|
LOG_GENERIC(Common::Log::Class::Render_Vulkan, level,
|
2023-06-20 14:24:24 +02:00
|
|
|
"type = {}, object = {} | MessageCode = {:#x}, LayerPrefix = {} | {}",
|
|
|
|
vk::to_string(type), object, messageCode, pLayerPrefix, pMessage);
|
|
|
|
|
|
|
|
return VK_FALSE;
|
|
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
2023-09-13 00:28:50 +02:00
|
|
|
std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
|
|
|
|
[[maybe_unused]] Frontend::GraphicsContext* context) {
|
|
|
|
#ifdef ANDROID
|
|
|
|
// Android may override the Vulkan driver from the frontend.
|
|
|
|
if (auto library = context->GetDriverLibrary(); library) {
|
|
|
|
return library;
|
|
|
|
}
|
|
|
|
#endif
|
2023-06-20 14:24:24 +02:00
|
|
|
auto library = std::make_shared<Common::DynamicLibrary>();
|
|
|
|
#ifdef __APPLE__
|
|
|
|
const std::string filename = Common::DynamicLibrary::GetLibraryName("vulkan");
|
2023-07-05 06:00:24 +02:00
|
|
|
if (!library->Load(filename)) {
|
2023-06-20 14:24:24 +02:00
|
|
|
// Fall back to directly loading bundled MoltenVK library.
|
2023-07-05 06:00:24 +02:00
|
|
|
const std::string mvk_filename = Common::DynamicLibrary::GetLibraryName("MoltenVK");
|
|
|
|
void(library->Load(mvk_filename));
|
2023-06-20 14:24:24 +02:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
std::string filename = Common::DynamicLibrary::GetLibraryName("vulkan", 1);
|
|
|
|
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename);
|
|
|
|
if (!library->Load(filename)) {
|
|
|
|
// Android devices may not have libvulkan.so.1, only libvulkan.so.
|
|
|
|
filename = Common::DynamicLibrary::GetLibraryName("vulkan");
|
|
|
|
LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename);
|
|
|
|
void(library->Load(filename));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return library;
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window) {
|
|
|
|
const auto& window_info = emu_window.GetWindowInfo();
|
|
|
|
vk::SurfaceKHR surface{};
|
|
|
|
|
|
|
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
|
|
|
if (window_info.type == Frontend::WindowSystemType::Windows) {
|
|
|
|
const vk::Win32SurfaceCreateInfoKHR win32_ci = {
|
|
|
|
.hinstance = nullptr,
|
|
|
|
.hwnd = static_cast<HWND>(window_info.render_surface),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
|
|
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Win32 surface");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
if (window_info.type == Frontend::WindowSystemType::X11) {
|
|
|
|
const vk::XlibSurfaceCreateInfoKHR xlib_ci = {
|
|
|
|
.dpy = static_cast<Display*>(window_info.display_connection),
|
|
|
|
.window = reinterpret_cast<Window>(window_info.render_surface),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (instance.createXlibSurfaceKHR(&xlib_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
|
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
} else if (window_info.type == Frontend::WindowSystemType::Wayland) {
|
|
|
|
const vk::WaylandSurfaceCreateInfoKHR wayland_ci = {
|
|
|
|
.display = static_cast<wl_display*>(window_info.display_connection),
|
|
|
|
.surface = static_cast<wl_surface*>(window_info.render_surface),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (instance.createWaylandSurfaceKHR(&wayland_ci, nullptr, &surface) !=
|
|
|
|
vk::Result::eSuccess) {
|
|
|
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(VK_USE_PLATFORM_METAL_EXT)
|
|
|
|
if (window_info.type == Frontend::WindowSystemType::MacOS) {
|
|
|
|
const vk::MetalSurfaceCreateInfoEXT macos_ci = {
|
|
|
|
.pLayer = static_cast<const CAMetalLayer*>(window_info.render_surface),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (instance.createMetalSurfaceEXT(&macos_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
|
|
LOG_CRITICAL(Render_Vulkan, "Failed to initialize MacOS surface");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
|
|
if (window_info.type == Frontend::WindowSystemType::Android) {
|
|
|
|
vk::AndroidSurfaceCreateInfoKHR android_ci = {
|
|
|
|
.window = reinterpret_cast<ANativeWindow*>(window_info.render_surface),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (instance.createAndroidSurfaceKHR(&android_ci, nullptr, &surface) !=
|
|
|
|
vk::Result::eSuccess) {
|
|
|
|
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Android surface");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!surface) {
|
|
|
|
LOG_CRITICAL(Render_Vulkan, "Presentation not supported on this platform");
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type,
|
|
|
|
bool enable_debug_utils) {
|
|
|
|
const auto properties = vk::enumerateInstanceExtensionProperties();
|
|
|
|
if (properties.empty()) {
|
|
|
|
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the windowing system specific extension
|
|
|
|
std::vector<const char*> extensions;
|
2024-01-09 20:33:47 +01:00
|
|
|
extensions.reserve(7);
|
2023-06-20 14:24:24 +02:00
|
|
|
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
2024-01-09 20:33:47 +01:00
|
|
|
// For configuring MoltenVK.
|
|
|
|
extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME);
|
2023-06-20 14:24:24 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (window_type) {
|
|
|
|
case Frontend::WindowSystemType::Headless:
|
|
|
|
break;
|
|
|
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
|
|
|
case Frontend::WindowSystemType::Windows:
|
|
|
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
|
|
break;
|
|
|
|
#elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
case Frontend::WindowSystemType::X11:
|
|
|
|
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
|
|
|
break;
|
|
|
|
case Frontend::WindowSystemType::Wayland:
|
|
|
|
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
|
|
|
break;
|
|
|
|
#elif defined(VK_USE_PLATFORM_METAL_EXT)
|
|
|
|
case Frontend::WindowSystemType::MacOS:
|
|
|
|
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
|
|
|
break;
|
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
|
|
case Frontend::WindowSystemType::Android:
|
|
|
|
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window_type != Frontend::WindowSystemType::Headless) {
|
|
|
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enable_debug_utils) {
|
|
|
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
|
|
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanitize extension list
|
|
|
|
std::erase_if(extensions, [&](const char* extension) -> bool {
|
|
|
|
const auto it =
|
|
|
|
std::find_if(properties.begin(), properties.end(), [extension](const auto& prop) {
|
|
|
|
return std::strcmp(extension, prop.extensionName) == 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (it == properties.end()) {
|
|
|
|
LOG_INFO(Render_Vulkan, "Candidate instance extension {} is not available", extension);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
return extensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::InstanceCreateFlags GetInstanceFlags() {
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
return vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
|
|
|
|
#else
|
|
|
|
return static_cast<vk::InstanceCreateFlags>(0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::UniqueInstance CreateInstance(const Common::DynamicLibrary& library,
|
|
|
|
Frontend::WindowSystemType window_type, bool enable_validation,
|
|
|
|
bool dump_command_buffers) {
|
2023-09-14 23:21:12 +02:00
|
|
|
if (!library.IsLoaded()) {
|
|
|
|
throw std::runtime_error("Failed to load Vulkan driver library");
|
|
|
|
}
|
|
|
|
|
2024-01-12 18:16:04 +01:00
|
|
|
const auto vkGetInstanceProcAddr =
|
2023-06-20 14:24:24 +02:00
|
|
|
library.GetSymbol<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
|
|
|
if (!vkGetInstanceProcAddr) {
|
2023-09-13 00:28:50 +02:00
|
|
|
throw std::runtime_error("Failed GetSymbol vkGetInstanceProcAddr");
|
2023-06-20 14:24:24 +02:00
|
|
|
}
|
|
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
|
|
|
|
2024-02-16 04:38:32 +01:00
|
|
|
const u32 available_version = VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceVersion
|
|
|
|
? vk::enumerateInstanceVersion()
|
|
|
|
: VK_API_VERSION_1_0;
|
|
|
|
if (available_version < TargetVulkanApiVersion) {
|
|
|
|
throw std::runtime_error(fmt::format(
|
|
|
|
"Vulkan {}.{} is required, but only {}.{} is supported by instance!",
|
|
|
|
VK_VERSION_MAJOR(TargetVulkanApiVersion), VK_VERSION_MINOR(TargetVulkanApiVersion),
|
|
|
|
VK_VERSION_MAJOR(available_version), VK_VERSION_MINOR(available_version)));
|
2023-06-20 14:24:24 +02:00
|
|
|
}
|
|
|
|
|
2023-09-16 01:00:10 +02:00
|
|
|
const auto extensions = GetInstanceExtensions(window_type, enable_validation);
|
|
|
|
|
2023-06-20 14:24:24 +02:00
|
|
|
const vk::ApplicationInfo application_info = {
|
|
|
|
.pApplicationName = "Citra",
|
|
|
|
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
|
|
|
|
.pEngineName = "Citra Vulkan",
|
|
|
|
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
|
2024-02-16 04:38:32 +01:00
|
|
|
.apiVersion = TargetVulkanApiVersion,
|
2023-06-20 14:24:24 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
boost::container::static_vector<const char*, 2> layers;
|
|
|
|
if (enable_validation) {
|
|
|
|
layers.push_back("VK_LAYER_KHRONOS_validation");
|
|
|
|
}
|
|
|
|
if (dump_command_buffers) {
|
|
|
|
layers.push_back("VK_LAYER_LUNARG_api_dump");
|
|
|
|
}
|
|
|
|
|
2024-01-09 20:33:47 +01:00
|
|
|
vk::InstanceCreateInfo instance_ci = {
|
2023-06-20 14:24:24 +02:00
|
|
|
.flags = GetInstanceFlags(),
|
|
|
|
.pApplicationInfo = &application_info,
|
|
|
|
.enabledLayerCount = static_cast<u32>(layers.size()),
|
|
|
|
.ppEnabledLayerNames = layers.data(),
|
|
|
|
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
|
|
|
.ppEnabledExtensionNames = extensions.data(),
|
|
|
|
};
|
|
|
|
|
2024-01-09 20:33:47 +01:00
|
|
|
#ifdef __APPLE__
|
|
|
|
// Use synchronous queue submits if async presentation is enabled, to avoid threading
|
|
|
|
// indirection.
|
|
|
|
const auto synchronous_queue_submits = Settings::values.async_presentation.GetValue();
|
|
|
|
// If the device is lost, make an attempt to resume if possible to avoid crashes.
|
|
|
|
constexpr auto resume_lost_device = true;
|
|
|
|
// Maximize concurrency to improve shader compilation performance.
|
|
|
|
constexpr auto maximize_concurrent_compilation = true;
|
|
|
|
|
|
|
|
constexpr auto layer_name = "MoltenVK";
|
|
|
|
const vk::LayerSettingEXT layer_settings[] = {
|
|
|
|
{layer_name, "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", vk::LayerSettingTypeEXT::eBool32, 1,
|
|
|
|
&synchronous_queue_submits},
|
|
|
|
{layer_name, "MVK_CONFIG_RESUME_LOST_DEVICE", vk::LayerSettingTypeEXT::eBool32, 1,
|
|
|
|
&resume_lost_device},
|
|
|
|
{layer_name, "MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION",
|
|
|
|
vk::LayerSettingTypeEXT::eBool32, 1, &maximize_concurrent_compilation},
|
|
|
|
};
|
|
|
|
const vk::LayerSettingsCreateInfoEXT layer_settings_ci = {
|
|
|
|
.pNext = nullptr,
|
|
|
|
.settingCount = static_cast<uint32_t>(std::size(layer_settings)),
|
|
|
|
.pSettings = layer_settings,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (std::find(extensions.begin(), extensions.end(), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) !=
|
|
|
|
extensions.end()) {
|
|
|
|
instance_ci.pNext = &layer_settings_ci;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-06-20 14:24:24 +02:00
|
|
|
auto instance = vk::createInstanceUnique(instance_ci);
|
|
|
|
|
|
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance);
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::UniqueDebugUtilsMessengerEXT CreateDebugMessenger(vk::Instance instance) {
|
|
|
|
const vk::DebugUtilsMessengerCreateInfoEXT msg_ci = {
|
|
|
|
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
|
|
|
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
|
|
|
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
|
|
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose,
|
|
|
|
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
|
|
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
|
|
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eDeviceAddressBinding |
|
|
|
|
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
|
|
|
.pfnUserCallback = DebugUtilsCallback,
|
|
|
|
};
|
|
|
|
return instance.createDebugUtilsMessengerEXTUnique(msg_ci);
|
|
|
|
}
|
|
|
|
|
|
|
|
vk::UniqueDebugReportCallbackEXT CreateDebugReportCallback(vk::Instance instance) {
|
|
|
|
const vk::DebugReportCallbackCreateInfoEXT callback_ci = {
|
|
|
|
.flags = vk::DebugReportFlagBitsEXT::eDebug | vk::DebugReportFlagBitsEXT::eInformation |
|
|
|
|
vk::DebugReportFlagBitsEXT::eError |
|
|
|
|
vk::DebugReportFlagBitsEXT::ePerformanceWarning |
|
|
|
|
vk::DebugReportFlagBitsEXT::eWarning,
|
|
|
|
.pfnCallback = DebugReportCallback,
|
|
|
|
};
|
|
|
|
return instance.createDebugReportCallbackEXTUnique(callback_ci);
|
|
|
|
}
|
|
|
|
|
2023-09-13 00:28:50 +02:00
|
|
|
DebugCallback CreateDebugCallback(vk::Instance instance, bool& debug_utils_supported) {
|
2023-06-20 14:24:24 +02:00
|
|
|
if (!Settings::values.renderer_debug) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
const auto properties = vk::enumerateInstanceExtensionProperties();
|
|
|
|
if (properties.empty()) {
|
|
|
|
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
const auto it = std::find_if(properties.begin(), properties.end(), [](const auto& prop) {
|
|
|
|
return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
|
|
|
|
});
|
|
|
|
// Prefer debug util messenger if available.
|
2023-09-13 00:28:50 +02:00
|
|
|
debug_utils_supported = it != properties.end();
|
|
|
|
if (debug_utils_supported) {
|
2023-06-20 14:24:24 +02:00
|
|
|
return CreateDebugMessenger(instance);
|
|
|
|
}
|
|
|
|
// Otherwise fallback to debug report callback.
|
|
|
|
return CreateDebugReportCallback(instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Vulkan
|