Merge pull request #5230 from ReinUsesLisp/vulkan-common

vulkan_common: Move reusable Vulkan abstractions to a separate directory
master
Rodrigo Locatti 2021-01-03 17:38:29 +07:00 committed by GitHub
commit 7265e80c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 577 additions and 489 deletions

@ -167,8 +167,6 @@ add_library(video_core STATIC
renderer_vulkan/vk_texture_cache.h renderer_vulkan/vk_texture_cache.h
renderer_vulkan/vk_update_descriptor.cpp renderer_vulkan/vk_update_descriptor.cpp
renderer_vulkan/vk_update_descriptor.h renderer_vulkan/vk_update_descriptor.h
renderer_vulkan/wrapper.cpp
renderer_vulkan/wrapper.h
shader_cache.h shader_cache.h
shader_notify.cpp shader_notify.cpp
shader_notify.h shader_notify.h
@ -257,6 +255,16 @@ 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.h
vulkan_common/vulkan_library.cpp
vulkan_common/vulkan_library.h
vulkan_common/vulkan_surface.cpp
vulkan_common/vulkan_surface.h
vulkan_common/vulkan_wrapper.cpp
vulkan_common/vulkan_wrapper.h
) )
create_target_directory_groups(video_core) create_target_directory_groups(video_core)

@ -17,8 +17,8 @@
#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_state_tracker.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,8 +8,8 @@
#include "video_core/engines/fermi_2d.h" #include "video_core/engines/fermi_2d.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/texture_cache/types.h" #include "video_core/texture_cache/types.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -10,8 +10,8 @@
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan::MaxwellToVK { namespace Vulkan::MaxwellToVK {

@ -7,9 +7,9 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/textures/texture.h" #include "video_core/textures/texture.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan::MaxwellToVK { namespace Vulkan::MaxwellToVK {

@ -12,8 +12,6 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "common/dynamic_library.h"
#include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/telemetry.h" #include "common/telemetry.h"
#include "core/core.h" #include "core/core.h"
@ -31,169 +29,14 @@
#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/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_debug_callback.h"
#include "video_core/vulkan_common/vulkan_instance.h"
// Include these late to avoid polluting previous headers #include "video_core/vulkan_common/vulkan_library.h"
#ifdef _WIN32 #include "video_core/vulkan_common/vulkan_surface.h"
#include <windows.h> #include "video_core/vulkan_common/vulkan_wrapper.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 Vulkan {
namespace { namespace {
using Core::Frontend::WindowSystemType;
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;
}
Common::DynamicLibrary OpenVulkanLibrary() {
Common::DynamicLibrary library;
#ifdef __APPLE__
// Check if a path to a specific Vulkan library has been specified.
char* libvulkan_env = getenv("LIBVULKAN_PATH");
if (!libvulkan_env || !library.Open(libvulkan_env)) {
// Use the libvulkan.dylib from the application bundle.
const std::string filename =
Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
library.Open(filename.c_str());
}
#else
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
if (!library.Open(filename.c_str())) {
// Android devices may not have libvulkan.so.1, only libvulkan.so.
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
(void)library.Open(filename.c_str());
}
#endif
return library;
}
std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
vk::InstanceDispatch& dld, 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 {};
}
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));
@ -216,7 +59,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);
} }
@ -255,7 +97,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;
@ -284,14 +125,16 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
render_window.OnFrameDisplayed(); render_window.OnFrameDisplayed();
} }
bool RendererVulkan::Init() { bool RendererVulkan::Init() try {
library = OpenVulkanLibrary(); library = OpenLibrary();
std::tie(instance, instance_version) = CreateInstance( instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); true, Settings::values.renderer_debug);
if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { if (Settings::values.renderer_debug) {
return false; debug_callback = CreateDebugCallback(instance);
} }
surface = CreateSurface(instance, render_window);
InitializeDevice();
Report(); Report();
memory_manager = std::make_unique<VKMemoryManager>(*device); memory_manager = std::make_unique<VKMemoryManager>(*device);
@ -311,8 +154,11 @@ bool RendererVulkan::Init() {
blit_screen = blit_screen =
std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
*memory_manager, *swapchain, *scheduler, screen_info); *memory_manager, *swapchain, *scheduler, screen_info);
return true; return true;
} catch (const vk::Exception& exception) {
LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
return false;
} }
void RendererVulkan::ShutDown() { void RendererVulkan::ShutDown() {
@ -322,7 +168,6 @@ void RendererVulkan::ShutDown() {
if (const auto& dev = device->GetLogical()) { if (const auto& dev = device->GetLogical()) {
dev.WaitIdle(); dev.WaitIdle();
} }
rasterizer.reset(); rasterizer.reset();
blit_screen.reset(); blit_screen.reset();
scheduler.reset(); scheduler.reset();
@ -331,95 +176,15 @@ void RendererVulkan::ShutDown() {
device.reset(); device.reset();
} }
bool RendererVulkan::CreateDebugCallback() { void RendererVulkan::InitializeDevice() {
if (!Settings::values.renderer_debug) { const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
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() {
[[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
VkSurfaceKHR unsafe_surface = nullptr;
#ifdef _WIN32
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
nullptr, 0, nullptr, hWnd};
const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR"));
if (!vkCreateWin32SurfaceKHR ||
vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface");
return false;
}
}
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
static_cast<Display*>(window_info.display_connection),
reinterpret_cast<Window>(window_info.render_surface)};
const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR"));
if (!vkCreateXlibSurfaceKHR ||
vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
return false;
}
}
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
static_cast<wl_display*>(window_info.display_connection),
static_cast<wl_surface*>(window_info.render_surface)};
const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR"));
if (!vkCreateWaylandSurfaceKHR ||
vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) !=
VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
return false;
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
return false;
}
surface = vk::SurfaceKHR(unsafe_surface, *instance, dld);
return true;
}
bool RendererVulkan::PickDevices() {
const auto devices = instance.EnumeratePhysicalDevices();
if (!devices) {
LOG_ERROR(Render_Vulkan, "Failed to enumerate physical devices");
return false;
}
const s32 device_index = Settings::values.vulkan_device.GetValue(); const s32 device_index = Settings::values.vulkan_device.GetValue();
if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) { if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
return false; throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
} }
const vk::PhysicalDevice physical_device((*devices)[static_cast<std::size_t>(device_index)], const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld);
dld); device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld);
if (!VKDevice::IsSuitable(physical_device, *surface)) {
return false;
}
device =
std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld);
return device->Create();
} }
void RendererVulkan::Report() const { void RendererVulkan::Report() const {
@ -444,26 +209,21 @@ void RendererVulkan::Report() const {
telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
} }
std::vector<std::string> RendererVulkan::EnumerateDevices() { std::vector<std::string> RendererVulkan::EnumerateDevices() try {
vk::InstanceDispatch dld; vk::InstanceDispatch dld;
Common::DynamicLibrary library = OpenVulkanLibrary(); const Common::DynamicLibrary library = OpenLibrary();
vk::Instance instance = const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
CreateInstance(library, dld, WindowSystemType::Headless, false, false).first; const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
if (!instance) {
return {};
}
const std::optional physical_devices = instance.EnumeratePhysicalDevices();
if (!physical_devices) {
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 VkPhysicalDevice device : physical_devices) {
names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName);
} }
return names; return names;
} catch (const vk::Exception& exception) {
LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what());
return {};
} }
} // namespace Vulkan } // namespace Vulkan

@ -11,7 +11,7 @@
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core { namespace Core {
class TelemetrySession; class TelemetrySession;
@ -56,11 +56,7 @@ public:
static std::vector<std::string> EnumerateDevices(); static std::vector<std::string> EnumerateDevices();
private: private:
bool CreateDebugCallback(); void InitializeDevice();
bool CreateSurface();
bool PickDevices();
void Report() const; void Report() const;
@ -72,13 +68,12 @@ private:
vk::InstanceDispatch dld; vk::InstanceDispatch dld;
vk::Instance instance; vk::Instance instance;
u32 instance_version{};
vk::SurfaceKHR surface; vk::SurfaceKHR surface;
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;

@ -27,9 +27,9 @@
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/vk_swapchain.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/textures/decoders.h" #include "video_core/textures/decoders.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -7,7 +7,7 @@
#include <memory> #include <memory>
#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core { namespace Core {
class System; class System;

@ -12,7 +12,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -11,7 +11,7 @@
#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -6,7 +6,7 @@
#include "video_core/renderer_vulkan/vk_command_pool.h" #include "video_core/renderer_vulkan/vk_command_pool.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,7 +8,7 @@
#include <vector> #include <vector>
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -19,7 +19,7 @@
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -11,7 +11,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -11,7 +11,7 @@
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -7,7 +7,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -9,7 +9,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -7,7 +7,7 @@
#include <vector> #include <vector>
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -14,7 +14,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "core/settings.h" #include "core/settings.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {
@ -206,17 +206,14 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
} // Anonymous namespace } // Anonymous namespace
VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, VKDevice::VKDevice(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) const vk::InstanceDispatch& dld_)
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { format_properties{GetFormatProperties(physical, dld)} {
CheckSuitability();
SetupFamilies(surface); SetupFamilies(surface);
SetupFeatures(); SetupFeatures();
}
VKDevice::~VKDevice() = default;
bool VKDevice::Create() {
const auto queue_cis = GetDeviceQueueCreateInfos(); const auto queue_cis = GetDeviceQueueCreateInfos();
const std::vector extensions = LoadExtensions(); const std::vector extensions = LoadExtensions();
@ -426,12 +423,7 @@ bool VKDevice::Create() {
}; };
first_next = &diagnostics_nv; first_next = &diagnostics_nv;
} }
logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld); logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
if (!logical) {
LOG_ERROR(Render_Vulkan, "Failed to create logical device");
return false;
}
CollectTelemetryParameters(); CollectTelemetryParameters();
CollectToolingInfo(); CollectToolingInfo();
@ -455,9 +447,10 @@ bool VKDevice::Create() {
present_queue = logical.GetQueue(present_family); present_queue = logical.GetQueue(present_family);
use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
return true;
} }
VKDevice::~VKDevice() = default;
VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
FormatType format_type) const { FormatType format_type) const {
if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { if (IsFormatSupported(wanted_format, wanted_usage, format_type)) {
@ -556,64 +549,45 @@ bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wa
return (supported_usage & wanted_usage) == wanted_usage; return (supported_usage & wanted_usage) == wanted_usage;
} }
bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { void VKDevice::CheckSuitability() const {
bool is_suitable = true;
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) {
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
if (available_extensions[i]) { if (available_extensions[i]) {
continue; continue;
} }
const std::string_view name{prop.extensionName}; const std::string_view name{property.extensionName};
available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
} }
} }
if (!available_extensions.all()) { for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
if (available_extensions[i]) { if (available_extensions[i]) {
continue; continue;
} }
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
is_suitable = false; throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
}
struct LimitTuple {
u32 minimum;
u32 value;
const char* name;
};
const VkPhysicalDeviceLimits& limits{properties.limits};
const std::array limits_report{
LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
LimitTuple{16, limits.maxViewports, "maxViewports"},
LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"},
LimitTuple{8, limits.maxClipDistances, "maxClipDistances"},
};
for (const auto& tuple : limits_report) {
if (tuple.value < tuple.minimum) {
LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name,
tuple.minimum, tuple.value);
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
} }
} }
const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
bool has_graphics{}, has_present{}; const std::array feature_report{
const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
const auto& family = queue_family_properties[i];
if (family.queueCount == 0) {
continue;
}
has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT;
has_present |= physical.GetSurfaceSupportKHR(i, surface);
}
if (!has_graphics || !has_present) {
LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue");
is_suitable = false;
}
// TODO(Rodrigo): Check if the device matches all requeriments.
const auto properties{physical.GetProperties()};
const auto& limits{properties.limits};
constexpr u32 required_ubo_size = 65536;
if (limits.maxUniformBufferRange < required_ubo_size) {
LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required",
limits.maxUniformBufferRange, required_ubo_size);
is_suitable = false;
}
constexpr u32 required_num_viewports = 16;
if (limits.maxViewports < required_num_viewports) {
LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
limits.maxViewports, required_num_viewports);
is_suitable = false;
}
const auto features{physical.GetFeatures()};
const std::array feature_report = {
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
std::make_pair(features.imageCubeArray, "imageCubeArray"), std::make_pair(features.imageCubeArray, "imageCubeArray"),
std::make_pair(features.independentBlend, "independentBlend"), std::make_pair(features.independentBlend, "independentBlend"),
@ -631,19 +605,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
std::make_pair(features.shaderStorageImageWriteWithoutFormat, std::make_pair(features.shaderStorageImageWriteWithoutFormat,
"shaderStorageImageWriteWithoutFormat"), "shaderStorageImageWriteWithoutFormat"),
}; };
for (const auto& [supported, name] : feature_report) { for (const auto& [is_supported, name] : feature_report) {
if (supported) { if (is_supported) {
continue; continue;
} }
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
is_suitable = false; throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
} }
if (!is_suitable) {
LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName);
}
return is_suitable;
} }
std::vector<const char*> VKDevice::LoadExtensions() { std::vector<const char*> VKDevice::LoadExtensions() {
@ -685,9 +653,7 @@ std::vector<const char*> VKDevice::LoadExtensions() {
test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false); test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false);
if (instance_version >= VK_API_VERSION_1_1) {
test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
}
if (Settings::values.renderer_debug) { if (Settings::values.renderer_debug) {
test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
true); true);
@ -802,28 +768,34 @@ std::vector<const char*> VKDevice::LoadExtensions() {
} }
void VKDevice::SetupFamilies(VkSurfaceKHR surface) { void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
std::optional<u32> graphics_family_, present_family_;
const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { std::optional<u32> graphics;
if (graphics_family_ && present_family_) std::optional<u32> present;
for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) {
if (graphics && present) {
break; break;
}
const auto& queue_family = queue_family_properties[i]; const VkQueueFamilyProperties& queue_family = queue_family_properties[index];
if (queue_family.queueCount == 0) if (queue_family.queueCount == 0) {
continue; continue;
}
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphics_family_ = i; graphics = index;
} }
if (physical.GetSurfaceSupportKHR(i, surface)) { if (physical.GetSurfaceSupportKHR(index, surface)) {
present_family_ = i; present = index;
} }
} }
ASSERT(graphics_family_ && present_family_); if (!graphics) {
LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue");
graphics_family = *graphics_family_; throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
present_family = *present_family_; }
if (!present) {
LOG_ERROR(Render_Vulkan, "Device lacks a present queue");
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
}
graphics_family = *graphics;
present_family = *present;
} }
void VKDevice::SetupFeatures() { void VKDevice::SetupFeatures() {

@ -11,7 +11,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" #include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {
@ -24,13 +24,10 @@ const u32 GuestWarpSize = 32;
/// Handles data specific to a physical device. /// Handles data specific to a physical device.
class VKDevice final { class VKDevice final {
public: public:
explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
VkSurfaceKHR surface, const vk::InstanceDispatch& dld); const vk::InstanceDispatch& dld);
~VKDevice(); ~VKDevice();
/// Initializes the device. Returns true on success.
bool Create();
/** /**
* Returns a format supported by the device for the passed requeriments. * Returns a format supported by the device for the passed requeriments.
* @param wanted_format The ideal format to be returned. It may not be the returned format. * @param wanted_format The ideal format to be returned. It may not be the returned format.
@ -82,11 +79,6 @@ public:
return present_family; return present_family;
} }
/// Returns the current instance Vulkan API version in Vulkan-formatted version numbers.
u32 InstanceApiVersion() const {
return instance_version;
}
/// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
u32 ApiVersion() const { u32 ApiVersion() const {
return properties.apiVersion; return properties.apiVersion;
@ -232,10 +224,10 @@ public:
return use_asynchronous_shaders; return use_asynchronous_shaders;
} }
/// Checks if the physical device is suitable.
static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface);
private: private:
/// Checks if the physical device is suitable.
void CheckSuitability() const;
/// Loads extensions into a vector and stores available ones in this object. /// Loads extensions into a vector and stores available ones in this object.
std::vector<const char*> LoadExtensions(); std::vector<const char*> LoadExtensions();

@ -10,7 +10,7 @@
#include "video_core/renderer_vulkan/vk_fence_manager.h" #include "video_core/renderer_vulkan/vk_fence_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -9,7 +9,7 @@
#include "video_core/fence_manager.h" #include "video_core/fence_manager.h"
#include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core { namespace Core {
class System; class System;

@ -17,7 +17,7 @@
#include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -13,7 +13,7 @@
#include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,7 +8,7 @@
#include "core/settings.h" #include "core/settings.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,7 +8,7 @@
#include <thread> #include <thread>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -13,7 +13,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -9,7 +9,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -25,11 +25,11 @@
#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/shader/compiler_settings.h" #include "video_core/shader/compiler_settings.h"
#include "video_core/shader/memory_util.h" #include "video_core/shader/memory_util.h"
#include "video_core/shader_cache.h" #include "video_core/shader_cache.h"
#include "video_core/shader_notify.h" #include "video_core/shader_notify.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -20,12 +20,12 @@
#include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/fixed_pipeline_state.h"
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
#include "video_core/renderer_vulkan/vk_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/shader/async_shaders.h" #include "video_core/shader/async_shaders.h"
#include "video_core/shader/memory_util.h" #include "video_core/shader/memory_util.h"
#include "video_core/shader/registry.h" #include "video_core/shader/registry.h"
#include "video_core/shader/shader_ir.h" #include "video_core/shader/shader_ir.h"
#include "video_core/shader_cache.h" #include "video_core/shader_cache.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core { namespace Core {
class System; class System;

@ -11,7 +11,7 @@
#include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_query_cache.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -12,7 +12,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/query_cache.h" #include "video_core/query_cache.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace VideoCore { namespace VideoCore {
class RasterizerInterface; class RasterizerInterface;

@ -36,9 +36,9 @@
#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_state_tracker.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/shader_cache.h" #include "video_core/shader_cache.h"
#include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/texture_cache.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -29,8 +29,8 @@
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/shader/async_shaders.h" #include "video_core/shader/async_shaders.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core { namespace Core {
class System; class System;

@ -17,7 +17,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_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -12,7 +12,7 @@
#include <utility> #include <utility>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/threadsafe_queue.h" #include "common/threadsafe_queue.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -272,19 +272,12 @@ bool IsPrecise(Operation operand) {
return false; return false;
} }
u32 ShaderVersion(const VKDevice& device) {
if (device.InstanceApiVersion() < VK_API_VERSION_1_1) {
return 0x00010000;
}
return 0x00010300;
}
class SPIRVDecompiler final : public Sirit::Module { class SPIRVDecompiler final : public Sirit::Module {
public: public:
explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_, explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_,
const Registry& registry_, const Specialization& specialization_) const Registry& registry_, const Specialization& specialization_)
: Module(ShaderVersion(device_)), device{device_}, ir{ir_}, stage{stage_}, : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()},
header{ir_.GetHeader()}, registry{registry_}, specialization{specialization_} { registry{registry_}, specialization{specialization_} {
if (stage_ != ShaderType::Compute) { if (stage_ != ShaderType::Compute) {
transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo()); transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo());
} }

@ -9,7 +9,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -7,7 +7,7 @@
#include <span> #include <span>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -12,7 +12,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -10,7 +10,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -13,7 +13,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -9,7 +9,7 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -14,7 +14,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.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 "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -7,7 +7,7 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Layout { namespace Layout {
struct FramebufferLayout; struct FramebufferLayout;

@ -14,7 +14,7 @@
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,8 +8,8 @@
#include <span> #include <span>
#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_memory_manager.h"
#include "video_core/renderer_vulkan/wrapper.h"
#include "video_core/texture_cache/texture_cache.h" #include "video_core/texture_cache/texture_cache.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -10,7 +10,7 @@
#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_device.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

@ -8,7 +8,7 @@
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {

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

@ -0,0 +1,151 @@
// 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
vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
u32 required_version, Core::Frontend::WindowSystemType window_type,
bool enable_debug_utils, bool enable_layers) {
if (!library.IsOpen()) {
LOG_ERROR(Render_Vulkan, "Vulkan library not available");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
if (!vk::Load(dld)) {
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils);
if (!AreExtensionsSupported(dld, extensions)) {
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
}
std::vector<const char*> layers = Layers(enable_layers);
RemoveUnavailableLayers(dld, layers);
const u32 available_version = vk::AvailableVersion(dld);
if (available_version < required_version) {
LOG_ERROR(Render_Vulkan, "Vulkan {}.{} is not supported, {}.{} is required",
VK_VERSION_MAJOR(available_version), VK_VERSION_MINOR(available_version),
VK_VERSION_MAJOR(required_version), VK_VERSION_MINOR(required_version));
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
}
vk::Instance instance = vk::Instance::Create(required_version, layers, extensions, dld);
if (!vk::Load(*instance, dld)) {
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
return instance;
}
} // namespace Vulkan

@ -0,0 +1,32 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#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 {
/**
* Create a Vulkan instance
*
* @param library Dynamic library to load the Vulkan instance from
* @param dld Dispatch table to load function pointers into
* @param required_version Required Vulkan version (for example, VK_API_VERSION_1_1)
* @param window_type Window system type's enabled extension
* @param enable_debug_utils Whether to enable VK_EXT_debug_utils_extension_name or not
* @param enable_layers Whether to enable Vulkan validation layers or not
*
* @return A new Vulkan instance
* @throw vk::Exception on failure
*/
[[nodiscard]] vk::Instance CreateInstance(
const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, u32 required_version,
Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless,
bool enable_debug_utils = false, bool enable_layers = false);
} // namespace Vulkan

@ -0,0 +1,36 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstdlib>
#include <string>
#include "common/dynamic_library.h"
#include "common/file_util.h"
#include "video_core/vulkan_common/vulkan_library.h"
namespace Vulkan {
Common::DynamicLibrary OpenLibrary() {
Common::DynamicLibrary library;
#ifdef __APPLE__
// Check if a path to a specific Vulkan library has been specified.
char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
if (!libvulkan_env || !library.Open(libvulkan_env)) {
// Use the libvulkan.dylib from the application bundle.
const std::string filename =
Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
library.Open(filename.c_str());
}
#else
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
if (!library.Open(filename.c_str())) {
// Android devices may not have libvulkan.so.1, only libvulkan.so.
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
void(library.Open(filename.c_str()));
}
#endif
return library;
}
} // namespace Vulkan

@ -0,0 +1,13 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/dynamic_library.h"
namespace Vulkan {
Common::DynamicLibrary OpenLibrary();
} // namespace Vulkan

@ -0,0 +1,81 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/frontend/emu_window.h"
#include "video_core/vulkan_common/vulkan_surface.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 {
vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
const Core::Frontend::EmuWindow& emu_window) {
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
[[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo();
VkSurfaceKHR unsafe_surface = nullptr;
#ifdef _WIN32
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
nullptr, 0, nullptr, hWnd};
const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR"));
if (!vkCreateWin32SurfaceKHR ||
vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
static_cast<Display*>(window_info.display_connection),
reinterpret_cast<Window>(window_info.render_surface)};
const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR"));
if (!vkCreateXlibSurfaceKHR ||
vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
static_cast<wl_display*>(window_info.display_connection),
static_cast<wl_surface*>(window_info.render_surface)};
const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR"));
if (!vkCreateWaylandSurfaceKHR ||
vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) !=
VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
return vk::SurfaceKHR(unsafe_surface, *instance, dld);
}
} // namespace Vulkan

@ -0,0 +1,18 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Core::Frontend {
class EmuWindow;
}
namespace Vulkan {
[[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
const Core::Frontend::EmuWindow& emu_window);
} // namespace Vulkan

@ -13,7 +13,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan::vk { namespace Vulkan::vk {
@ -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,55 +455,30 @@ 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::vector<VkPhysicalDevice> Instance::EnumeratePhysicalDevices() const {
u32 num; u32 num;
if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { Check(dld->vkEnumeratePhysicalDevices(handle, &num, nullptr));
return std::nullopt;
}
std::vector<VkPhysicalDevice> physical_devices(num); std::vector<VkPhysicalDevice> physical_devices(num);
if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { Check(dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()));
return std::nullopt;
}
SortPhysicalDevices(physical_devices, *dld); SortPhysicalDevices(physical_devices, *dld);
return std::make_optional(std::move(physical_devices)); return 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 {
@ -605,7 +580,7 @@ void Semaphore::SetObjectNameEXT(const char* name) const {
Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
Span<const char*> enabled_extensions, const void* next, Span<const char*> enabled_extensions, const void* next,
DeviceDispatch& dispatch) noexcept { DeviceDispatch& dispatch) {
const VkDeviceCreateInfo ci{ const VkDeviceCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = next, .pNext = next,
@ -618,11 +593,8 @@ Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreate
.ppEnabledExtensionNames = enabled_extensions.data(), .ppEnabledExtensionNames = enabled_extensions.data(),
.pEnabledFeatures = nullptr, .pEnabledFeatures = nullptr,
}; };
VkDevice device; VkDevice device;
if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { Check(dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device));
return {};
}
Load(device, dispatch); Load(device, dispatch);
return Device(device, dispatch); return Device(device, dispatch);
} }

@ -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,25 @@ 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(); /// @throw Exception on Vulkan error.
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;
/// Returns dispatch table.
const InstanceDispatch& Dispatch() const noexcept {
return *dld;
}
}; };
class Queue { class Queue {
@ -787,7 +796,7 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
public: public:
static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
Span<const char*> enabled_extensions, const void* next, Span<const char*> enabled_extensions, const void* next,
DeviceDispatch& dispatch) noexcept; DeviceDispatch& dispatch);
Queue GetQueue(u32 family_index) const noexcept; Queue GetQueue(u32 family_index) const noexcept;