diff --git a/src/xenia/ui/vk/vulkan_context.cc b/src/xenia/ui/vk/vulkan_context.cc index bfb41d6e1..ebcc079e4 100644 --- a/src/xenia/ui/vk/vulkan_context.cc +++ b/src/xenia/ui/vk/vulkan_context.cc @@ -10,8 +10,10 @@ #include "xenia/ui/vk/vulkan_context.h" #include "xenia/base/logging.h" +#include "xenia/base/platform.h" #include "xenia/ui/vk/vulkan_immediate_drawer.h" #include "xenia/ui/vk/vulkan_util.h" +#include "xenia/ui/window.h" namespace xe { namespace ui { @@ -23,7 +25,9 @@ VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window) VulkanContext::~VulkanContext() { Shutdown(); } bool VulkanContext::Initialize() { - auto device = GetVulkanProvider()->GetDevice(); + auto provider = GetVulkanProvider(); + auto instance = provider->GetInstance(); + auto device = provider->GetDevice(); context_lost_ = false; @@ -49,6 +53,43 @@ bool VulkanContext::Initialize() { } if (target_window_) { + // Create the surface. + VkResult surface_create_result; +#if XE_PLATFORM_WIN32 + VkWin32SurfaceCreateInfoKHR surface_create_info; + surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surface_create_info.pNext = nullptr; + surface_create_info.flags = 0; + surface_create_info.hinstance = + static_cast(target_window_->native_platform_handle()); + surface_create_info.hwnd = + static_cast(target_window_->native_handle()); + surface_create_result = vkCreateWin32SurfaceKHR( + instance, &surface_create_info, nullptr, &surface_); +#else +#error No Vulkan surface creation for the platform implemented yet. +#endif + if (surface_create_result != VK_SUCCESS) { + XELOGE("Failed to create a Vulkan surface"); + Shutdown(); + return false; + } + + // Check if the graphics queue can present to the surface. + // FIXME(Triang3l): Separate present queue not supported - would require + // deferring VkDevice creation because vkCreateDevice needs all used queues. + VkBool32 surface_supported = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(provider->GetPhysicalDevice(), + provider->GetGraphicsQueueFamily(), + surface_, &surface_supported); + if (!surface_supported) { + XELOGE( + "Surface not supported by the graphics queue of the Vulkan physical " + "device"); + Shutdown(); + return false; + } + // Initialize the immediate mode drawer if not offscreen. immediate_drawer_ = std::make_unique(this); if (!immediate_drawer_->Initialize()) { @@ -61,7 +102,9 @@ bool VulkanContext::Initialize() { } void VulkanContext::Shutdown() { - auto device = GetVulkanProvider()->GetDevice(); + auto provider = GetVulkanProvider(); + auto instance = provider->GetInstance(); + auto device = provider->GetDevice(); if (initialized_fully_ && !context_lost_) { AwaitAllFramesCompletion(); @@ -71,6 +114,8 @@ void VulkanContext::Shutdown() { immediate_drawer_.reset(); + util::DestroyAndNullHandle(vkDestroySurfaceKHR, instance, surface_); + for (uint32_t i = 0; i < kQueuedFrames; ++i) { util::DestroyAndNullHandle(vkDestroyFence, device, fences_[i]); } diff --git a/src/xenia/ui/vk/vulkan_context.h b/src/xenia/ui/vk/vulkan_context.h index c3d960517..ce79ba423 100644 --- a/src/xenia/ui/vk/vulkan_context.h +++ b/src/xenia/ui/vk/vulkan_context.h @@ -71,6 +71,8 @@ class VulkanContext : public GraphicsContext { uint32_t current_queue_frame_ = 1; VkFence fences_[kQueuedFrames] = {}; + VkSurfaceKHR surface_ = VK_NULL_HANDLE; + std::unique_ptr immediate_drawer_ = nullptr; }; diff --git a/src/xenia/ui/vk/vulkan_provider.h b/src/xenia/ui/vk/vulkan_provider.h index 6c39b9c85..71285b5ee 100644 --- a/src/xenia/ui/vk/vulkan_provider.h +++ b/src/xenia/ui/vk/vulkan_provider.h @@ -16,13 +16,8 @@ #include "xenia/base/platform.h" #include "xenia/ui/graphics_provider.h" -#ifndef VK_NO_PROTOTYPES -#define VK_NO_PROTOTYPES -#endif -#include "third_party/vulkan/vulkan.h" -#if XE_PLATFORM_WIN32 -#include "third_party/vulkan/vulkan_win32.h" -#include "xenia/base/platform_win.h" +#if XE_PLATFORM_WIN32 && !defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_USE_PLATFORM_WIN32_KHR 1 #endif #include "third_party/volk/volk.h" @@ -44,6 +39,8 @@ class VulkanProvider : public GraphicsProvider { Window* target_window) override; std::unique_ptr CreateOffscreenContext() override; + VkInstance GetInstance() const { return instance_; } + VkPhysicalDevice GetPhysicalDevice() const { return physical_device_; } const VkPhysicalDeviceFeatures& GetPhysicalDeviceFeatures() const { return physical_device_features_; } diff --git a/src/xenia/ui/vk/vulkan_util.h b/src/xenia/ui/vk/vulkan_util.h index f334b6619..55fb55fa2 100644 --- a/src/xenia/ui/vk/vulkan_util.h +++ b/src/xenia/ui/vk/vulkan_util.h @@ -27,11 +27,10 @@ inline bool DestroyAndNullHandle(F* destroy_function, T& handle) { return false; } -template -inline bool DestroyAndNullHandle(F* destroy_function, VkDevice device, - T& handle) { +template +inline bool DestroyAndNullHandle(F* destroy_function, P parent, T& handle) { if (handle != VK_NULL_HANDLE) { - destroy_function(device, handle, nullptr); + destroy_function(parent, handle, nullptr); handle = VK_NULL_HANDLE; return true; }