mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-12-24 17:30:56 +01:00
renderer_vulkan: Move instance initialization to a separate file
Simplify Vulkan's backend initialization code by moving it to a separate file, allowing us to initialize a Vulkan instance from different backends.
This commit is contained in:
parent
d1435009ed
commit
25f88d99ce
4 changed files with 176 additions and 111 deletions
|
@ -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_instance.cpp
|
||||||
|
vulkan_common/vulkan_instance.h
|
||||||
vulkan_common/vulkan_library.cpp
|
vulkan_common/vulkan_library.cpp
|
||||||
vulkan_common/vulkan_library.h
|
vulkan_common/vulkan_library.h
|
||||||
vulkan_common/vulkan_wrapper.cpp
|
vulkan_common/vulkan_wrapper.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_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"
|
||||||
|
|
||||||
|
@ -46,11 +47,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using Core::Frontend::WindowSystemType;
|
|
||||||
|
|
||||||
VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* data,
|
const VkDebugUtilsMessengerCallbackDataEXT* data,
|
||||||
|
@ -69,109 +66,6 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<vk::Instance, u32> CreateInstance(
|
|
||||||
Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
|
|
||||||
WindowSystemType window_type = WindowSystemType::Headless, bool enable_debug_utils = false,
|
|
||||||
bool enable_layers = false) {
|
|
||||||
if (!library.IsOpen()) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Vulkan library not available");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (!vk::Load(dld)) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const char*> extensions;
|
|
||||||
extensions.reserve(6);
|
|
||||||
switch (window_type) {
|
|
||||||
case Core::Frontend::WindowSystemType::Headless:
|
|
||||||
break;
|
|
||||||
#ifdef _WIN32
|
|
||||||
case Core::Frontend::WindowSystemType::Windows:
|
|
||||||
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|
||||||
case Core::Frontend::WindowSystemType::X11:
|
|
||||||
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
|
||||||
break;
|
|
||||||
case Core::Frontend::WindowSystemType::Wayland:
|
|
||||||
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (window_type != Core::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_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
|
||||||
|
|
||||||
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
|
|
||||||
if (!properties) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const char* extension : extensions) {
|
|
||||||
const auto it =
|
|
||||||
std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) {
|
|
||||||
return !std::strcmp(extension, prop.extensionName);
|
|
||||||
});
|
|
||||||
if (it == properties->end()) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const char*> layers;
|
|
||||||
layers.reserve(1);
|
|
||||||
if (enable_layers) {
|
|
||||||
layers.push_back("VK_LAYER_KHRONOS_validation");
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld);
|
|
||||||
if (!layer_properties) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers");
|
|
||||||
layers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto layer_it = layers.begin(); layer_it != layers.end();) {
|
|
||||||
const char* const layer = *layer_it;
|
|
||||||
const auto it = std::find_if(
|
|
||||||
layer_properties->begin(), layer_properties->end(),
|
|
||||||
[layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); });
|
|
||||||
if (it == layer_properties->end()) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer);
|
|
||||||
layer_it = layers.erase(layer_it);
|
|
||||||
} else {
|
|
||||||
++layer_it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit the maximum version of Vulkan to avoid using untested version.
|
|
||||||
const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1));
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
|
||||||
}
|
|
||||||
return std::make_pair(std::move(instance), version);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
||||||
|
@ -194,7 +88,6 @@ std::string GetDriverVersion(const VKDevice& device) {
|
||||||
const u32 minor = version & 0x3fff;
|
const u32 minor = version & 0x3fff;
|
||||||
return fmt::format("{}.{}", major, minor);
|
return fmt::format("{}.{}", major, minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetReadableVersion(version);
|
return GetReadableVersion(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +126,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
|
||||||
if (!framebuffer) {
|
if (!framebuffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& layout = render_window.GetFramebufferLayout();
|
const auto& layout = render_window.GetFramebufferLayout();
|
||||||
if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {
|
if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {
|
||||||
const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
|
const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
|
||||||
|
@ -429,12 +321,10 @@ std::vector<std::string> RendererVulkan::EnumerateDevices() {
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional physical_devices = instance.EnumeratePhysicalDevices();
|
const std::optional physical_devices = instance.EnumeratePhysicalDevices();
|
||||||
if (!physical_devices) {
|
if (!physical_devices) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
names.reserve(physical_devices->size());
|
names.reserve(physical_devices->size());
|
||||||
for (const auto& device : *physical_devices) {
|
for (const auto& device : *physical_devices) {
|
||||||
|
|
152
src/video_core/vulkan_common/vulkan_instance.cpp
Normal file
152
src/video_core/vulkan_common/vulkan_instance.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
|
#include <span>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
// Include these late to avoid polluting previous headers
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
// ensure include order
|
||||||
|
#include <vulkan/vulkan_win32.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <vulkan/vulkan_wayland.h>
|
||||||
|
#include <vulkan/vulkan_xlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
namespace {
|
||||||
|
[[nodiscard]] std::vector<const char*> RequiredExtensions(
|
||||||
|
Core::Frontend::WindowSystemType window_type, bool enable_debug_utils) {
|
||||||
|
std::vector<const char*> extensions;
|
||||||
|
extensions.reserve(6);
|
||||||
|
switch (window_type) {
|
||||||
|
case Core::Frontend::WindowSystemType::Headless:
|
||||||
|
break;
|
||||||
|
#ifdef _WIN32
|
||||||
|
case Core::Frontend::WindowSystemType::Windows:
|
||||||
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||||
|
case Core::Frontend::WindowSystemType::X11:
|
||||||
|
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
case Core::Frontend::WindowSystemType::Wayland:
|
||||||
|
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (window_type != Core::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_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
|
||||||
|
std::span<const char* const> extensions) {
|
||||||
|
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
|
||||||
|
if (!properties) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const char* extension : extensions) {
|
||||||
|
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
|
||||||
|
return std::strcmp(extension, prop.extensionName) == 0;
|
||||||
|
});
|
||||||
|
if (it == properties->end()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<const char*> Layers(bool enable_layers) {
|
||||||
|
std::vector<const char*> layers;
|
||||||
|
if (enable_layers) {
|
||||||
|
layers.push_back("VK_LAYER_KHRONOS_validation");
|
||||||
|
}
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector<const char*>& layers) {
|
||||||
|
const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld);
|
||||||
|
if (!layer_properties) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers");
|
||||||
|
layers.clear();
|
||||||
|
}
|
||||||
|
std::erase_if(layers, [&layer_properties](const char* layer) {
|
||||||
|
const auto comp = [layer](const VkLayerProperties& layer_property) {
|
||||||
|
return std::strcmp(layer, layer_property.layerName) == 0;
|
||||||
|
};
|
||||||
|
const auto it = std::ranges::find_if(*layer_properties, comp);
|
||||||
|
if (it == layer_properties->end()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
|
||||||
|
vk::InstanceDispatch& dld,
|
||||||
|
Core::Frontend::WindowSystemType window_type,
|
||||||
|
bool enable_debug_utils, bool enable_layers) {
|
||||||
|
if (!library.IsOpen()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Vulkan library not available");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!vk::Load(dld)) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils);
|
||||||
|
if (!AreExtensionsSupported(dld, extensions)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> layers = Layers(enable_layers);
|
||||||
|
RemoveUnavailableLayers(dld, layers);
|
||||||
|
|
||||||
|
// Limit the maximum version of Vulkan to avoid using untested version.
|
||||||
|
const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1);
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
||||||
|
}
|
||||||
|
return std::make_pair(std::move(instance), version);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
21
src/video_core/vulkan_common/vulkan_instance.h
Normal file
21
src/video_core/vulkan_common/vulkan_instance.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/dynamic_library.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
[[nodiscard]] std::pair<vk::Instance, u32> CreateInstance(
|
||||||
|
Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
|
||||||
|
Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless,
|
||||||
|
bool enable_debug_utils = false, bool enable_layers = false);
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
Loading…
Reference in a new issue