diff options
60 files changed, 574 insertions, 486 deletions
| diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e050f9aed..4bd48f706 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -167,8 +167,6 @@ add_library(video_core STATIC      renderer_vulkan/vk_texture_cache.h      renderer_vulkan/vk_update_descriptor.cpp      renderer_vulkan/vk_update_descriptor.h -    renderer_vulkan/wrapper.cpp -    renderer_vulkan/wrapper.h      shader_cache.h      shader_notify.cpp      shader_notify.h @@ -257,6 +255,16 @@ add_library(video_core STATIC      textures/texture.h      video_core.cpp      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) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 87c8e5693..504492cac 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -17,8 +17,8 @@  #include "video_core/renderer_vulkan/vk_state_tracker.h"  #include "video_core/renderer_vulkan/vk_texture_cache.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/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index 2c2790bf9..1a4f66336 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h @@ -8,8 +8,8 @@  #include "video_core/engines/fermi_2d.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/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 4c988429f..ed4fce714 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -10,8 +10,8 @@  #include "video_core/engines/maxwell_3d.h"  #include "video_core/renderer_vulkan/maxwell_to_vk.h"  #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h"  #include "video_core/surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan::MaxwellToVK { diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 1a90f192e..8cf5aa711 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h @@ -7,9 +7,9 @@  #include "common/common_types.h"  #include "video_core/engines/maxwell_3d.h"  #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h"  #include "video_core/surface.h"  #include "video_core/textures/texture.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan::MaxwellToVK { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 7f521cb9b..5b35cb407 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -12,8 +12,6 @@  #include <fmt/format.h> -#include "common/dynamic_library.h" -#include "common/file_util.h"  #include "common/logging/log.h"  #include "common/telemetry.h"  #include "core/core.h" @@ -31,169 +29,14 @@  #include "video_core/renderer_vulkan/vk_scheduler.h"  #include "video_core/renderer_vulkan/vk_state_tracker.h"  #include "video_core/renderer_vulkan/vk_swapchain.h" -#include "video_core/renderer_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 +#include "video_core/vulkan_common/vulkan_debug_callback.h" +#include "video_core/vulkan_common/vulkan_instance.h" +#include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { -  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) {      return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),                         VK_VERSION_PATCH(version)); @@ -216,7 +59,6 @@ std::string GetDriverVersion(const VKDevice& device) {          const u32 minor = version & 0x3fff;          return fmt::format("{}.{}", major, minor);      } -      return GetReadableVersion(version);  } @@ -255,7 +97,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {      if (!framebuffer) {          return;      } -      const auto& layout = render_window.GetFramebufferLayout();      if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {          const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; @@ -284,14 +125,16 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {      render_window.OnFrameDisplayed();  } -bool RendererVulkan::Init() { -    library = OpenVulkanLibrary(); -    std::tie(instance, instance_version) = CreateInstance( -        library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); -    if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { -        return false; +bool RendererVulkan::Init() try { +    library = OpenLibrary(); +    instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, +                              true, Settings::values.renderer_debug); +    if (Settings::values.renderer_debug) { +        debug_callback = CreateDebugCallback(instance);      } +    surface = CreateSurface(instance, render_window); +    InitializeDevice();      Report();      memory_manager = std::make_unique<VKMemoryManager>(*device); @@ -311,8 +154,11 @@ bool RendererVulkan::Init() {      blit_screen =          std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,                                         *memory_manager, *swapchain, *scheduler, screen_info); -      return true; + +} catch (const vk::Exception& exception) { +    LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); +    return false;  }  void RendererVulkan::ShutDown() { @@ -322,7 +168,6 @@ void RendererVulkan::ShutDown() {      if (const auto& dev = device->GetLogical()) {          dev.WaitIdle();      } -      rasterizer.reset();      blit_screen.reset();      scheduler.reset(); @@ -331,95 +176,15 @@ void RendererVulkan::ShutDown() {      device.reset();  } -bool RendererVulkan::CreateDebugCallback() { -    if (!Settings::values.renderer_debug) { -        return true; -    } -    debug_callback = instance.TryCreateDebugCallback(DebugCallback); -    if (!debug_callback) { -        LOG_ERROR(Render_Vulkan, "Failed to create debug callback"); -        return false; -    } -    return true; -} - -bool RendererVulkan::CreateSurface() { -    [[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; -    } - +void RendererVulkan::InitializeDevice() { +    const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();      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); -        return false; -    } -    const vk::PhysicalDevice physical_device((*devices)[static_cast<std::size_t>(device_index)], -                                             dld); -    if (!VKDevice::IsSuitable(physical_device, *surface)) { -        return false; +        throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);      } - -    device = -        std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld); -    return device->Create(); +    const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld); +    device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld);  }  void RendererVulkan::Report() const { @@ -444,26 +209,21 @@ void RendererVulkan::Report() const {      telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);  } -std::vector<std::string> RendererVulkan::EnumerateDevices() { +std::vector<std::string> RendererVulkan::EnumerateDevices() try {      vk::InstanceDispatch dld; -    Common::DynamicLibrary library = OpenVulkanLibrary(); -    vk::Instance instance = -        CreateInstance(library, dld, WindowSystemType::Headless, false, false).first; -    if (!instance) { -        return {}; -    } - -    const std::optional physical_devices = instance.EnumeratePhysicalDevices(); -    if (!physical_devices) { -        return {}; -    } - +    const Common::DynamicLibrary library = OpenLibrary(); +    const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); +    const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();      std::vector<std::string> names; -    names.reserve(physical_devices->size()); -    for (const auto& device : *physical_devices) { +    names.reserve(physical_devices.size()); +    for (const VkPhysicalDevice device : physical_devices) {          names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName);      }      return names; + +} catch (const vk::Exception& exception) { +    LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what()); +    return {};  }  } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 74642fba4..f22f50709 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -11,7 +11,7 @@  #include "common/dynamic_library.h"  #include "video_core/renderer_base.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Core {  class TelemetrySession; @@ -56,11 +56,7 @@ public:      static std::vector<std::string> EnumerateDevices();  private: -    bool CreateDebugCallback(); - -    bool CreateSurface(); - -    bool PickDevices(); +    void InitializeDevice();      void Report() const; @@ -72,13 +68,12 @@ private:      vk::InstanceDispatch dld;      vk::Instance instance; -    u32 instance_version{};      vk::SurfaceKHR surface;      VKScreenInfo screen_info; -    vk::DebugCallback debug_callback; +    vk::DebugUtilsMessenger debug_callback;      std::unique_ptr<VKDevice> device;      std::unique_ptr<VKMemoryManager> memory_manager;      std::unique_ptr<StateTracker> state_tracker; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index d3a83f22f..a205cd151 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -27,9 +27,9 @@  #include "video_core/renderer_vulkan/vk_scheduler.h"  #include "video_core/renderer_vulkan/vk_shader_util.h"  #include "video_core/renderer_vulkan/vk_swapchain.h" -#include "video_core/renderer_vulkan/wrapper.h"  #include "video_core/surface.h"  #include "video_core/textures/decoders.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 2ee374247..cc56c4560 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -7,7 +7,7 @@  #include <memory>  #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 {  class System; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 10d296c2f..79131f819 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -12,7 +12,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index daf498222..3ab77a00b 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -11,7 +11,7 @@  #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_stream_buffer.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp index 8f7d6410e..ccae04929 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp @@ -6,7 +6,7 @@  #include "video_core/renderer_vulkan/vk_command_pool.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 { diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h index 62a7ce3f1..ce0e34515 100644 --- a/src/video_core/renderer_vulkan/vk_command_pool.h +++ b/src/video_core/renderer_vulkan/vk_command_pool.h @@ -8,7 +8,7 @@  #include <vector>  #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 { diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 2c030e910..5d4543bae 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -19,7 +19,7 @@  #include "video_core/renderer_vulkan/vk_scheduler.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/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index abdf61e2c..1b7502a4f 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -11,7 +11,7 @@  #include "common/common_types.h"  #include "video_core/engines/maxwell_3d.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 { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 62f44d6da..9966dd14a 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -11,7 +11,7 @@  #include "video_core/renderer_vulkan/vk_scheduler.h"  #include "video_core/renderer_vulkan/vk_shader_decompiler.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 { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 49e2113a2..a7197536c 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -7,7 +7,7 @@  #include "common/common_types.h"  #include "video_core/renderer_vulkan/vk_descriptor_pool.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 { diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index f38e089d5..4dea03239 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -9,7 +9,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_resource_pool.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 { diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h index 544f32a20..2abcaeddd 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h @@ -7,7 +7,7 @@  #include <vector>  #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 { diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 85b4f0dff..9008530d5 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -14,7 +14,7 @@  #include "common/assert.h"  #include "core/settings.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 { @@ -206,17 +206,14 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(  } // Anonymous namespace -VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, -                   VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) +VKDevice::VKDevice(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, +                   const vk::InstanceDispatch& dld_)      : 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);      SetupFeatures(); -} - -VKDevice::~VKDevice() = default; -bool VKDevice::Create() {      const auto queue_cis = GetDeviceQueueCreateInfos();      const std::vector extensions = LoadExtensions(); @@ -426,12 +423,7 @@ bool VKDevice::Create() {          };          first_next = &diagnostics_nv;      } -      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();      CollectToolingInfo(); @@ -455,9 +447,10 @@ bool VKDevice::Create() {      present_queue = logical.GetQueue(present_family);      use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); -    return true;  } +VKDevice::~VKDevice() = default; +  VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,                                        FormatType format_type) const {      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;  } -bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { -    bool is_suitable = true; +void VKDevice::CheckSuitability() const {      std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; - -    for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) { +    for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {          for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {              if (available_extensions[i]) {                  continue;              } -            const std::string_view name{prop.extensionName}; +            const std::string_view name{property.extensionName};              available_extensions[i] = name == REQUIRED_EXTENSIONS[i];          }      } -    if (!available_extensions.all()) { -        for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { -            if (available_extensions[i]) { -                continue; -            } -            LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); -            is_suitable = false; -        } -    } - -    bool has_graphics{}, has_present{}; -    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) { +    for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { +        if (available_extensions[i]) {              continue;          } -        has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT; -        has_present |= physical.GetSurfaceSupportKHR(i, surface); +        LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); +        throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);      } -    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; +    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 auto features{physical.GetFeatures()}; -    const std::array feature_report = { +    const VkPhysicalDeviceFeatures features{physical.GetFeatures()}; +    const std::array feature_report{          std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),          std::make_pair(features.imageCubeArray, "imageCubeArray"),          std::make_pair(features.independentBlend, "independentBlend"), @@ -631,19 +605,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {          std::make_pair(features.shaderStorageImageWriteWithoutFormat,                         "shaderStorageImageWriteWithoutFormat"),      }; -    for (const auto& [supported, name] : feature_report) { -        if (supported) { +    for (const auto& [is_supported, name] : feature_report) { +        if (is_supported) {              continue;          }          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() { @@ -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_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_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) {              test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,                   true); @@ -802,28 +768,34 @@ std::vector<const char*> VKDevice::LoadExtensions() {  }  void VKDevice::SetupFamilies(VkSurfaceKHR surface) { -    std::optional<u32> graphics_family_, present_family_; -      const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); -    for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { -        if (graphics_family_ && present_family_) +    std::optional<u32> graphics; +    std::optional<u32> present; +    for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) { +        if (graphics && present) {              break; - -        const auto& queue_family = queue_family_properties[i]; -        if (queue_family.queueCount == 0) +        } +        const VkQueueFamilyProperties& queue_family = queue_family_properties[index]; +        if (queue_family.queueCount == 0) {              continue; - +        }          if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { -            graphics_family_ = i; +            graphics = index;          } -        if (physical.GetSurfaceSupportKHR(i, surface)) { -            present_family_ = i; +        if (physical.GetSurfaceSupportKHR(index, surface)) { +            present = index;          }      } -    ASSERT(graphics_family_ && present_family_); - -    graphics_family = *graphics_family_; -    present_family = *present_family_; +    if (!graphics) { +        LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue"); +        throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); +    } +    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() { diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 995dcfc0f..146acbe24 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -11,7 +11,7 @@  #include "common/common_types.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 { @@ -24,13 +24,10 @@ const u32 GuestWarpSize = 32;  /// Handles data specific to a physical device.  class VKDevice final {  public: -    explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, -                      VkSurfaceKHR surface, const vk::InstanceDispatch& dld); +    explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, +                      const vk::InstanceDispatch& dld);      ~VKDevice(); -    /// Initializes the device. Returns true on success. -    bool Create(); -      /**       * 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. @@ -82,11 +79,6 @@ public:          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.      u32 ApiVersion() const {          return properties.apiVersion; @@ -232,10 +224,10 @@ public:          return use_asynchronous_shaders;      } +private:      /// Checks if the physical device is suitable. -    static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface); +    void CheckSuitability() const; -private:      /// Loads extensions into a vector and stores available ones in this object.      std::vector<const char*> LoadExtensions(); diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 774a12a53..cd044c187 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp @@ -10,7 +10,7 @@  #include "video_core/renderer_vulkan/vk_fence_manager.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index c2869e8e3..272ae6d29 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h @@ -9,7 +9,7 @@  #include "video_core/fence_manager.h"  #include "video_core/renderer_vulkan/vk_buffer_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 {  class System; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 7979df3a8..d9c1ed553 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -17,7 +17,7 @@  #include "video_core/renderer_vulkan/vk_pipeline_cache.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 214d06b4c..3bc93bc2a 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -13,7 +13,7 @@  #include "video_core/renderer_vulkan/fixed_pipeline_state.h"  #include "video_core/renderer_vulkan/vk_descriptor_pool.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 { diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index ae26e558d..ed6ea0805 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -8,7 +8,7 @@  #include "core/settings.h"  #include "video_core/renderer_vulkan/vk_device.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 { diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 0e93706d7..747d2f3bc 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -8,7 +8,7 @@  #include <thread>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp index 56b24b70f..35f859f77 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp @@ -13,7 +13,7 @@  #include "common/logging/log.h"  #include "video_core/renderer_vulkan/vk_device.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 { diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h index 318f8b43e..20463ecad 100644 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ b/src/video_core/renderer_vulkan/vk_memory_manager.h @@ -9,7 +9,7 @@  #include <utility>  #include <vector>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 083796d05..b44fd6159 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -25,11 +25,11 @@  #include "video_core/renderer_vulkan/vk_rasterizer.h"  #include "video_core/renderer_vulkan/vk_scheduler.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/memory_util.h"  #include "video_core/shader_cache.h"  #include "video_core/shader_notify.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index fbaa8257c..5ce1b17f3 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -20,12 +20,12 @@  #include "video_core/renderer_vulkan/fixed_pipeline_state.h"  #include "video_core/renderer_vulkan/vk_graphics_pipeline.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/memory_util.h"  #include "video_core/shader/registry.h"  #include "video_core/shader/shader_ir.h"  #include "video_core/shader_cache.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Core {  class System; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 038760de3..7852178b6 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -11,7 +11,7 @@  #include "video_core/renderer_vulkan/vk_query_cache.h"  #include "video_core/renderer_vulkan/vk_resource_pool.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 { diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index 837fe9ebf..b4fb6b3b0 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h @@ -12,7 +12,7 @@  #include "common/common_types.h"  #include "video_core/query_cache.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 {  class RasterizerInterface; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 04c5c859c..1c174e7ec 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -36,9 +36,9 @@  #include "video_core/renderer_vulkan/vk_state_tracker.h"  #include "video_core/renderer_vulkan/vk_texture_cache.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/texture_cache/texture_cache.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 990f9e031..7b9ec3bb8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -29,8 +29,8 @@  #include "video_core/renderer_vulkan/vk_stream_buffer.h"  #include "video_core/renderer_vulkan/vk_texture_cache.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/vulkan_common/vulkan_wrapper.h"  namespace Core {  class System; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index c104c6fe3..f7b79e74c 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -17,7 +17,7 @@  #include "video_core/renderer_vulkan/vk_scheduler.h"  #include "video_core/renderer_vulkan/vk_state_tracker.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 { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 0a36c8fad..1172ec622 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -12,7 +12,7 @@  #include <utility>  #include "common/common_types.h"  #include "common/threadsafe_queue.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 09d6f9f35..571460c2f 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -272,19 +272,12 @@ bool IsPrecise(Operation operand) {      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 {  public:      explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_,                               const Registry& registry_, const Specialization& specialization_) -        : Module(ShaderVersion(device_)), device{device_}, ir{ir_}, stage{stage_}, -          header{ir_.GetHeader()}, registry{registry_}, specialization{specialization_} { +        : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()}, +          registry{registry_}, specialization{specialization_} {          if (stage_ != ShaderType::Compute) {              transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo());          } diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp index 38a0be7f2..630306077 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp @@ -9,7 +9,7 @@  #include "common/common_types.h"  #include "video_core/renderer_vulkan/vk_device.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 { diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h index dce34a140..98ee5e668 100644 --- a/src/video_core/renderer_vulkan/vk_shader_util.h +++ b/src/video_core/renderer_vulkan/vk_shader_util.h @@ -7,7 +7,7 @@  #include <span>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 2fd3b7f39..e5155e886 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -12,7 +12,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 2dd5049ac..97ed1118a 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -10,7 +10,7 @@  #include "common/common_types.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 { diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 419cb154d..aae50bf25 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp @@ -13,7 +13,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h index 1428f77bf..aebd68728 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h @@ -9,7 +9,7 @@  #include <vector>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 9636a7c65..458aa4532 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -14,7 +14,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 6b39befdf..25eb20832 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -7,7 +7,7 @@  #include <vector>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Layout {  struct FramebufferLayout; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 261808391..e04dd23ef 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -14,7 +14,7 @@  #include "video_core/renderer_vulkan/vk_scheduler.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/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index edc3d80c0..576515bcc 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -8,8 +8,8 @@  #include <span>  #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/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp index 8826da325..c0603ac22 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp @@ -10,7 +10,7 @@  #include "video_core/renderer_vulkan/vk_device.h"  #include "video_core/renderer_vulkan/vk_scheduler.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 { diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h index f098a8540..d0ae49010 100644 --- a/src/video_core/renderer_vulkan/vk_update_descriptor.h +++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h @@ -8,7 +8,7 @@  #include <boost/container/static_vector.hpp>  #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp new file mode 100644 index 000000000..ea7af8ad4 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h new file mode 100644 index 000000000..2efcd244c --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_debug_callback.h @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp new file mode 100644 index 000000000..889ecda0c --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_instance.h b/src/video_core/vulkan_common/vulkan_instance.h new file mode 100644 index 000000000..e5e3a7144 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.h @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp new file mode 100644 index 000000000..27c958221 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_library.cpp @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_library.h b/src/video_core/vulkan_common/vulkan_library.h new file mode 100644 index 000000000..8b28b0e17 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_library.h @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp new file mode 100644 index 000000000..3c3238f96 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -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 diff --git a/src/video_core/vulkan_common/vulkan_surface.h b/src/video_core/vulkan_common/vulkan_surface.h new file mode 100644 index 000000000..05a169e32 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_surface.h @@ -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 diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 2a21e850d..5e15ad607 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -13,7 +13,7 @@  #include "common/common_types.h"  #include "common/logging/log.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h"  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, -                          InstanceDispatch& dispatch) noexcept { +                          InstanceDispatch& dispatch) {      const VkApplicationInfo application_info{          .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,          .pNext = nullptr, @@ -455,55 +455,30 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char          .enabledExtensionCount = extensions.size(),          .ppEnabledExtensionNames = extensions.data(),      }; -      VkInstance instance; -    if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { -        // Failed to create the instance. -        return {}; -    } +    Check(dispatch.vkCreateInstance(&ci, nullptr, &instance));      if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) {          // We successfully created an instance but the destroy function couldn't be loaded.          // This is a good moment to panic. -        return {}; +        throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);      } -      return Instance(instance, dispatch);  } -std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() { +std::vector<VkPhysicalDevice> Instance::EnumeratePhysicalDevices() const {      u32 num; -    if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { -        return std::nullopt; -    } +    Check(dld->vkEnumeratePhysicalDevices(handle, &num, nullptr));      std::vector<VkPhysicalDevice> physical_devices(num); -    if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { -        return std::nullopt; -    } +    Check(dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()));      SortPhysicalDevices(physical_devices, *dld); -    return std::make_optional(std::move(physical_devices)); +    return physical_devices;  } -DebugCallback Instance::TryCreateDebugCallback( -    PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { -    const VkDebugUtilsMessengerCreateInfoEXT ci{ -        .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, -        .pfnUserCallback = callback, -        .pUserData = nullptr, -    }; - -    VkDebugUtilsMessengerEXT messenger; -    if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { -        return {}; -    } -    return DebugCallback(messenger, handle, *dld); +DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( +    const VkDebugUtilsMessengerCreateInfoEXT& create_info) const { +    VkDebugUtilsMessengerEXT object; +    Check(dld->vkCreateDebugUtilsMessengerEXT(handle, &create_info, nullptr, &object)); +    return DebugUtilsMessenger(object, handle, *dld);  }  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,                        Span<const char*> enabled_extensions, const void* next, -                      DeviceDispatch& dispatch) noexcept { +                      DeviceDispatch& dispatch) {      const VkDeviceCreateInfo ci{          .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,          .pNext = next, @@ -618,11 +593,8 @@ Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreate          .ppEnabledExtensionNames = enabled_extensions.data(),          .pEnabledFeatures = nullptr,      }; -      VkDevice device; -    if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { -        return {}; -    } +    Check(dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device));      Load(device, dispatch);      return Device(device, dispatch);  } diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index f9a184e00..912cab46c 100644 --- a/src/video_core/renderer_vulkan/wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -555,7 +555,7 @@ private:      const DeviceDispatch* dld = nullptr;  }; -using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; +using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;  using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;  using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, 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;  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, -                           InstanceDispatch& dispatch) noexcept; +                           InstanceDispatch& dispatch);      /// Enumerates physical devices.      /// @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. -    DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; +    /// Creates a debug callback messenger. +    /// @throw Exception on creation failure. +    DebugUtilsMessenger CreateDebugUtilsMessenger( +        const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; + +    /// Returns dispatch table. +    const InstanceDispatch& Dispatch() const noexcept { +        return *dld; +    }  };  class Queue { @@ -787,7 +796,7 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {  public:      static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,                           Span<const char*> enabled_extensions, const void* next, -                         DeviceDispatch& dispatch) noexcept; +                         DeviceDispatch& dispatch);      Queue GetQueue(u32 family_index) const noexcept; | 
