From 09b3a07e3c2f00ae0aabaa6510c5d448788fd3ae Mon Sep 17 00:00:00 2001 From: DrChat Date: Tue, 19 Dec 2017 16:02:09 -0600 Subject: [PATCH] Support rendering windowless (tested on the Vulkan backend) --- src/xenia/emulator.cc | 12 +-- src/xenia/gpu/graphics_system.cc | 42 +++++---- src/xenia/gpu/vulkan/texture_cache.cc | 4 +- .../gpu/vulkan/vulkan_command_processor.cc | 4 +- .../gpu/vulkan/vulkan_graphics_system.cc | 11 ++- src/xenia/ui/vulkan/vulkan_device.cc | 86 ++++++++++++------- src/xenia/ui/vulkan/vulkan_device.h | 6 +- src/xenia/ui/vulkan/vulkan_instance.cc | 58 +------------ src/xenia/ui/vulkan/vulkan_instance.h | 5 +- src/xenia/ui/vulkan/vulkan_provider.cc | 6 +- src/xenia/ui/vulkan/vulkan_provider.h | 2 +- src/xenia/ui/vulkan/vulkan_swap_chain.cc | 63 +++++++++----- src/xenia/ui/vulkan/vulkan_swap_chain.h | 2 + src/xenia/ui/vulkan/vulkan_util.h | 1 - 14 files changed, 156 insertions(+), 146 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index a7d6d9281..a38e87149 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -191,11 +191,13 @@ X_STATUS Emulator::Setup( // Initialize emulator fallback exception handling last. ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this); - // Finish initializing the display. - display_window_->loop()->PostSynchronous([this]() { - xe::ui::GraphicsContextLock context_lock(display_window_->context()); - Profiler::set_window(display_window_); - }); + if (display_window_) { + // Finish initializing the display. + display_window_->loop()->PostSynchronous([this]() { + xe::ui::GraphicsContextLock context_lock(display_window_->context()); + Profiler::set_window(display_window_); + }); + } return result; } diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index d15cd279e..44576333b 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -51,16 +51,21 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, // This must happen on the UI thread. std::unique_ptr processor_context = nullptr; if (provider_) { - target_window_->loop()->PostSynchronous([&]() { - // Create the context used for presentation. - assert_null(target_window->context()); - target_window_->set_context(provider_->CreateContext(target_window_)); + if (target_window_) { + target_window_->loop()->PostSynchronous([&]() { + // Create the context used for presentation. + assert_null(target_window->context()); + target_window_->set_context(provider_->CreateContext(target_window_)); - // Setup the context the command processor will do all its drawing in. - // It's shared with the display context so that we can resolve - // framebuffers from it. + // Setup the context the command processor will do all its drawing in. + // It's shared with the display context so that we can resolve + // framebuffers from it. + processor_context = provider()->CreateOffscreenContext(); + }); + } else { processor_context = provider()->CreateOffscreenContext(); - }); + } + if (!processor_context) { xe::FatalError( "Unable to initialize graphics context. Xenia requires OpenGL 4.5 or " @@ -78,16 +83,21 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor, XELOGE("Unable to initialize command processor"); return X_STATUS_UNSUCCESSFUL; } - command_processor_->set_swap_request_handler( - [this]() { target_window_->Invalidate(); }); - // Watch for paint requests to do our swap. - target_window->on_painting.AddListener( - [this](xe::ui::UIEvent* e) { Swap(e); }); + if (target_window) { + command_processor_->set_swap_request_handler( + [this]() { target_window_->Invalidate(); }); - // Watch for context lost events. - target_window->on_context_lost.AddListener( - [this](xe::ui::UIEvent* e) { Reset(); }); + // Watch for paint requests to do our swap. + target_window->on_painting.AddListener( + [this](xe::ui::UIEvent* e) { Swap(e); }); + + // Watch for context lost events. + target_window->on_context_lost.AddListener( + [this](xe::ui::UIEvent* e) { Reset(); }); + } else { + command_processor_->set_swap_request_handler([]() {}); + } // Let the processor know we want register access callbacks. memory_->AddVirtualMappedRange( diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 7983efdd2..bd96f6bb3 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -212,13 +212,13 @@ VkResult TextureCache::Initialize() { invalidated_textures_sets_[1].reserve(64); invalidated_textures_ = &invalidated_textures_sets_[0]; - device_queue_ = device_->AcquireQueue(); + device_queue_ = device_->AcquireQueue(device_->queue_family_index()); return VK_SUCCESS; } void TextureCache::Shutdown() { if (device_queue_) { - device_->ReleaseQueue(device_queue_); + device_->ReleaseQueue(device_queue_, device_->queue_family_index()); } // Free all textures allocated. diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 6f23254f4..3289426b8 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -62,7 +62,7 @@ bool VulkanCommandProcessor::SetupContext() { // Acquire our device and queue. auto context = static_cast(context_.get()); device_ = context->device(); - queue_ = device_->AcquireQueue(); + queue_ = device_->AcquireQueue(device_->queue_family_index()); if (!queue_) { // Need to reuse primary queue (with locks). queue_ = device_->primary_queue(); @@ -159,7 +159,7 @@ void VulkanCommandProcessor::ShutdownContext() { // Release queue, if we were using an acquired one. if (!queue_mutex_) { - device_->ReleaseQueue(queue_); + device_->ReleaseQueue(queue_, device_->queue_family_index()); queue_ = nullptr; } diff --git a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc index 1e199fbba..af280d8d3 100644 --- a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc +++ b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc @@ -37,16 +37,19 @@ X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor, kernel::KernelState* kernel_state, ui::Window* target_window) { // Must create the provider so we can create contexts. - provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window); + auto provider = xe::ui::vulkan::VulkanProvider::Create(target_window); + device_ = provider->device(); + provider_ = std::move(provider); auto result = GraphicsSystem::Setup(processor, kernel_state, target_window); if (result) { return result; } - display_context_ = reinterpret_cast( - target_window->context()); - device_ = display_context_->device(); + if (target_window) { + display_context_ = reinterpret_cast( + target_window->context()); + } // Create our own command pool we can use for captures. VkCommandPoolCreateInfo create_info = { diff --git a/src/xenia/ui/vulkan/vulkan_device.cc b/src/xenia/ui/vulkan/vulkan_device.cc index b8ded460e..b865a5aa9 100644 --- a/src/xenia/ui/vulkan/vulkan_device.cc +++ b/src/xenia/ui/vulkan/vulkan_device.cc @@ -124,12 +124,9 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) { uint32_t queue_count = 1; for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) { auto queue_flags = device_info.queue_family_properties[i].queueFlags; - if (!device_info.queue_family_supports_present[i]) { - // Can't present from this queue, so ignore it. - continue; - } - if (queue_flags & VK_QUEUE_GRAPHICS_BIT) { - // Can do graphics and present - good! + if (queue_flags & VK_QUEUE_GRAPHICS_BIT && + queue_flags & VK_QUEUE_TRANSFER_BIT) { + // Can do graphics and transfer - good! ideal_queue_family_index = static_cast(i); // Grab all the queues we can. queue_count = device_info.queue_family_properties[i].queueCount; @@ -138,7 +135,7 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) { } if (ideal_queue_family_index == UINT_MAX) { FatalVulkanError( - "No queue families available that can both do graphics and present"); + "No queue families available that can both do graphics and transfer"); return false; } @@ -147,23 +144,36 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) { queue_count = 1; } - VkDeviceQueueCreateInfo queue_info; - queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_info.pNext = nullptr; - queue_info.flags = 0; - queue_info.queueFamilyIndex = ideal_queue_family_index; - queue_info.queueCount = queue_count; - std::vector queue_priorities(queue_count); - // Prioritize the primary queue. - queue_priorities[0] = 1.0f; - queue_info.pQueuePriorities = queue_priorities.data(); + std::vector queue_infos; + queue_infos.resize(device_info.queue_family_properties.size()); + for (int i = 0; i < queue_infos.size(); i++) { + VkDeviceQueueCreateInfo& queue_info = queue_infos[i]; + VkQueueFamilyProperties& family_props = + device_info.queue_family_properties[i]; + + queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_info.pNext = nullptr; + queue_info.flags = 0; + queue_info.queueFamilyIndex = i; + queue_info.queueCount = family_props.queueCount; + + std::vector queue_priorities(queue_count); + if (i == ideal_queue_family_index) { + // Prioritize the first queue on the primary queue family. + queue_priorities[0] = 1.0f; + } else { + queue_priorities[0] = 0.f; + } + + queue_info.pQueuePriorities = queue_priorities.data(); + } VkDeviceCreateInfo create_info; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.pNext = nullptr; create_info.flags = 0; - create_info.queueCreateInfoCount = 1; - create_info.pQueueCreateInfos = &queue_info; + create_info.queueCreateInfoCount = static_cast(queue_infos.size()); + create_info.pQueueCreateInfos = queue_infos.data(); create_info.enabledLayerCount = static_cast(enabled_layers.size()); create_info.ppEnabledLayerNames = enabled_layers.data(); create_info.enabledExtensionCount = @@ -205,31 +215,49 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) { // Get the primary queue used for most submissions/etc. vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_); + if (!primary_queue_) { + XELOGE("vkGetDeviceQueue returned nullptr!"); + return false; + } // Get all additional queues, if we got any. - for (uint32_t i = 0; i < queue_count - 1; ++i) { - VkQueue queue; - vkGetDeviceQueue(handle, queue_family_index_, i, &queue); - free_queues_.push_back(queue); + free_queues_.resize(device_info_.queue_family_properties.size()); + for (uint32_t i = 0; i < device_info_.queue_family_properties.size(); i++) { + VkQueueFamilyProperties& family_props = + device_info_.queue_family_properties[i]; + + for (uint32_t j = 0; j < family_props.queueCount; j++) { + VkQueue queue = nullptr; + if (i == queue_family_index_ && j == 0) { + // Already retrieved the primary queue index. + continue; + } + + vkGetDeviceQueue(handle, i, j, &queue); + if (queue) { + free_queues_[i].push_back(queue); + } + } } XELOGVK("Device initialized successfully!"); return true; } -VkQueue VulkanDevice::AcquireQueue() { +VkQueue VulkanDevice::AcquireQueue(uint32_t queue_family_index) { std::lock_guard lock(queue_mutex_); - if (free_queues_.empty()) { + if (free_queues_[queue_family_index].empty()) { return nullptr; } - auto queue = free_queues_.back(); - free_queues_.pop_back(); + + auto queue = free_queues_[queue_family_index].back(); + free_queues_[queue_family_index].pop_back(); return queue; } -void VulkanDevice::ReleaseQueue(VkQueue queue) { +void VulkanDevice::ReleaseQueue(VkQueue queue, uint32_t queue_family_index) { std::lock_guard lock(queue_mutex_); - free_queues_.push_back(queue); + free_queues_[queue_family_index].push_back(queue); } void VulkanDevice::DbgSetObjectName(VkDevice device, uint64_t object, diff --git a/src/xenia/ui/vulkan/vulkan_device.h b/src/xenia/ui/vulkan/vulkan_device.h index 0916a7909..ee7d1ec97 100644 --- a/src/xenia/ui/vulkan/vulkan_device.h +++ b/src/xenia/ui/vulkan/vulkan_device.h @@ -70,10 +70,10 @@ class VulkanDevice { // returns null the primary_queue should be used with the // primary_queue_mutex. // This method is thread safe. - VkQueue AcquireQueue(); + VkQueue AcquireQueue(uint32_t queue_family_index); // Releases a queue back to the device pool. // This method is thread safe. - void ReleaseQueue(VkQueue queue); + void ReleaseQueue(VkQueue queue, uint32_t queue_family_index); static void DbgSetObjectName(VkDevice device, uint64_t object, VkDebugReportObjectTypeEXT object_type, @@ -108,7 +108,7 @@ class VulkanDevice { uint32_t queue_family_index_ = 0; std::mutex queue_mutex_; VkQueue primary_queue_ = nullptr; - std::vector free_queues_; + std::vector> free_queues_; }; } // namespace vulkan diff --git a/src/xenia/ui/vulkan/vulkan_instance.cc b/src/xenia/ui/vulkan/vulkan_instance.cc index 3c51dfa1a..f0de3df67 100644 --- a/src/xenia/ui/vulkan/vulkan_instance.cc +++ b/src/xenia/ui/vulkan/vulkan_instance.cc @@ -69,7 +69,7 @@ VulkanInstance::VulkanInstance() { VulkanInstance::~VulkanInstance() { DestroyInstance(); } -bool VulkanInstance::Initialize(Window* any_target_window) { +bool VulkanInstance::Initialize() { auto version = Version::Parse(VK_API_VERSION); XELOGVK("Initializing Vulkan %s...", version.pretty_string.c_str()); @@ -87,7 +87,7 @@ bool VulkanInstance::Initialize(Window* any_target_window) { } // Query available devices so that we can pick one. - if (!QueryDevices(any_target_window)) { + if (!QueryDevices()) { XELOGE("Failed to query devices"); return false; } @@ -347,7 +347,7 @@ void VulkanInstance::DisableDebugValidation() { dbg_report_callback_ = nullptr; } -bool VulkanInstance::QueryDevices(Window* any_target_window) { +bool VulkanInstance::QueryDevices() { // Get handles to all devices. uint32_t count = 0; std::vector device_handles; @@ -376,56 +376,6 @@ bool VulkanInstance::QueryDevices(Window* any_target_window) { vkGetPhysicalDeviceQueueFamilyProperties( device_handle, &count, device_info.queue_family_properties.data()); - // Gather queue family presentation support. - // TODO(benvanik): move to swap chain? - VkSurfaceKHR any_surface = nullptr; -#if XE_PLATFORM_WIN32 - VkWin32SurfaceCreateInfoKHR create_info; - create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.hinstance = - static_cast(any_target_window->native_platform_handle()); - create_info.hwnd = static_cast(any_target_window->native_handle()); - err = vkCreateWin32SurfaceKHR(handle, &create_info, nullptr, &any_surface); - CheckResult(err, "vkCreateWin32SurfaceKHR"); -#elif XE_PLATFORM_LINUX -#ifdef GDK_WINDOWING_X11 - GtkWidget* window_handle = - static_cast(any_target_window->native_handle()); - GdkDisplay* gdk_display = gtk_widget_get_display(window_handle); - assert(GDK_IS_X11_DISPLAY(gdk_display)); - xcb_connection_t* connection = - XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display)); - xcb_window_t window = - gdk_x11_window_get_xid(gtk_widget_get_window(window_handle)); - VkXcbSurfaceCreateInfoKHR create_info; - create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.connection = static_cast( - any_target_window->native_platform_handle()); - create_info.window = static_cast(window); - auto err = - vkCreateXcbSurfaceKHR(handle, &create_info, nullptr, &any_surface); - CheckResult(err, "vkCreateXcbSurfaceKHR"); -#else -#error Unsupported GDK Backend on Linux. -#endif // GDK_WINDOWING_X11 -#else -#error Platform not yet implemented. -#endif // XE_PLATFORM_WIN32 - device_info.queue_family_supports_present.resize( - device_info.queue_family_properties.size()); - for (size_t j = 0; j < device_info.queue_family_supports_present.size(); - ++j) { - err = vkGetPhysicalDeviceSurfaceSupportKHR( - device_handle, static_cast(j), any_surface, - &device_info.queue_family_supports_present[j]); - CheckResult(err, "vkGetPhysicalDeviceSurfaceSupportKHR"); - } - vkDestroySurfaceKHR(handle, any_surface, nullptr); - // Gather layers. std::vector layer_properties; err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr); @@ -552,8 +502,6 @@ void VulkanInstance::DumpDeviceInfo(const DeviceInfo& device_info) { : ""); XELOGVK(" queueCount = %u", queue_props.queueCount); XELOGVK(" timestampValidBits = %u", queue_props.timestampValidBits); - XELOGVK(" supportsPresent = %s", - device_info.queue_family_supports_present[j] ? "true" : "false"); } XELOGVK(" Layers:"); diff --git a/src/xenia/ui/vulkan/vulkan_instance.h b/src/xenia/ui/vulkan/vulkan_instance.h index 88ad1bef4..6a86933bc 100644 --- a/src/xenia/ui/vulkan/vulkan_instance.h +++ b/src/xenia/ui/vulkan/vulkan_instance.h @@ -50,8 +50,7 @@ class VulkanInstance { // preparing the instance for general use. // If initialization succeeds it's likely that no more failures beyond runtime // issues will occur. - // TODO(benvanik): remove need for any_target_window - it's just for queries. - bool Initialize(Window* any_target_window); + bool Initialize(); // Returns a list of all available devices as detected during initialization. const std::vector& available_devices() const { @@ -79,7 +78,7 @@ class VulkanInstance { void DisableDebugValidation(); // Queries all available physical devices. - bool QueryDevices(Window* any_target_window); + bool QueryDevices(); void DumpLayers(const std::vector& layers, const char* indent); void DumpExtensions(const std::vector& extensions, diff --git a/src/xenia/ui/vulkan/vulkan_provider.cc b/src/xenia/ui/vulkan/vulkan_provider.cc index 300604bfb..3a7abcd5a 100644 --- a/src/xenia/ui/vulkan/vulkan_provider.cc +++ b/src/xenia/ui/vulkan/vulkan_provider.cc @@ -25,7 +25,7 @@ namespace xe { namespace ui { namespace vulkan { -std::unique_ptr VulkanProvider::Create(Window* main_window) { +std::unique_ptr VulkanProvider::Create(Window* main_window) { std::unique_ptr provider(new VulkanProvider(main_window)); if (!provider->Initialize()) { xe::FatalError( @@ -35,7 +35,7 @@ std::unique_ptr VulkanProvider::Create(Window* main_window) { "list of supported GPUs."); return nullptr; } - return std::unique_ptr(provider.release()); + return provider; } VulkanProvider::VulkanProvider(Window* main_window) @@ -56,7 +56,7 @@ bool VulkanProvider::Initialize() { Version::Make(0, 0, 0), false); // Attempt initialization and device query. - if (!instance_->Initialize(main_window_)) { + if (!instance_->Initialize()) { XELOGE("Failed to initialize vulkan instance"); return false; } diff --git a/src/xenia/ui/vulkan/vulkan_provider.h b/src/xenia/ui/vulkan/vulkan_provider.h index efc174614..f4a8080e3 100644 --- a/src/xenia/ui/vulkan/vulkan_provider.h +++ b/src/xenia/ui/vulkan/vulkan_provider.h @@ -25,7 +25,7 @@ class VulkanProvider : public GraphicsProvider { public: ~VulkanProvider() override; - static std::unique_ptr Create(Window* main_window); + static std::unique_ptr Create(Window* main_window); VulkanInstance* instance() const { return instance_.get(); } VulkanDevice* device() const { return device_.get(); } diff --git a/src/xenia/ui/vulkan/vulkan_swap_chain.cc b/src/xenia/ui/vulkan/vulkan_swap_chain.cc index 49c6e3fde..91c8d1d7b 100644 --- a/src/xenia/ui/vulkan/vulkan_swap_chain.cc +++ b/src/xenia/ui/vulkan/vulkan_swap_chain.cc @@ -36,14 +36,40 @@ VulkanSwapChain::~VulkanSwapChain() { Shutdown(); } VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) { surface_ = surface; + VkResult status; + // Find a queue family that supports presentation. VkBool32 surface_supported = false; - auto status = vkGetPhysicalDeviceSurfaceSupportKHR( - *device_, device_->queue_family_index(), surface, &surface_supported); - assert_true(surface_supported); - CheckResult(status, "vkGetPhysicalDeviceSurfaceSupportKHR"); - if (status != VK_SUCCESS) { - return status; + uint32_t queue_family_index = -1; + for (uint32_t i = 0; + i < device_->device_info().queue_family_properties.size(); i++) { + const VkQueueFamilyProperties& family_props = + device_->device_info().queue_family_properties[i]; + if (!(family_props.queueFlags & VK_QUEUE_GRAPHICS_BIT) || + !(family_props.queueFlags & VK_QUEUE_TRANSFER_BIT)) { + continue; + } + + status = vkGetPhysicalDeviceSurfaceSupportKHR(*device_, i, surface, + &surface_supported); + if (status == VK_SUCCESS && surface_supported == VK_TRUE) { + queue_family_index = i; + break; + } + } + + if (!surface_supported) { + XELOGE( + "Physical device does not have a queue that supports " + "graphics/transfer/presentation!"); + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + + presentation_queue_family_ = queue_family_index; + presentation_queue_ = device_->AcquireQueue(queue_family_index); + if (!presentation_queue_) { + XELOGE("Failed to acquire swap chain presentation queue!"); + return VK_ERROR_INITIALIZATION_FAILED; } // Query supported target formats. @@ -190,7 +216,7 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) { cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_pool_info.pNext = nullptr; cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - cmd_pool_info.queueFamilyIndex = device_->queue_family_index(); + cmd_pool_info.queueFamilyIndex = presentation_queue_family_; status = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_); CheckResult(status, "vkCreateCommandPool"); if (status != VK_SUCCESS) { @@ -432,6 +458,11 @@ void VulkanSwapChain::Shutdown() { vkDestroyCommandPool(*device_, cmd_pool_, nullptr); cmd_pool_ = nullptr; } + if (presentation_queue_) { + device_->ReleaseQueue(presentation_queue_, presentation_queue_family_); + presentation_queue_ = nullptr; + presentation_queue_family_ = -1; + } // images_ doesn't need to be cleaned up as the swapchain does it implicitly. if (handle) { vkDestroySwapchainKHR(*device_, handle, nullptr); @@ -471,11 +502,7 @@ VkResult VulkanSwapChain::Begin() { wait_submit_info.pCommandBuffers = nullptr; wait_submit_info.signalSemaphoreCount = 1; wait_submit_info.pSignalSemaphores = &image_usage_semaphore_; - { - std::lock_guard queue_lock(device_->primary_queue_mutex()); - status = - vkQueueSubmit(device_->primary_queue(), 1, &wait_submit_info, nullptr); - } + status = vkQueueSubmit(presentation_queue_, 1, &wait_submit_info, nullptr); if (status != VK_SUCCESS) { return status; } @@ -687,12 +714,7 @@ VkResult VulkanSwapChain::End() { render_submit_info.pCommandBuffers = &cmd_buffer_; render_submit_info.signalSemaphoreCount = uint32_t(semaphores.size()) - 1; render_submit_info.pSignalSemaphores = semaphores.data(); - { - std::lock_guard queue_lock(device_->primary_queue_mutex()); - status = vkQueueSubmit(device_->primary_queue(), 1, &render_submit_info, - nullptr); - } - + status = vkQueueSubmit(presentation_queue_, 1, &render_submit_info, nullptr); if (status != VK_SUCCESS) { return status; } @@ -709,10 +731,7 @@ VkResult VulkanSwapChain::End() { present_info.pSwapchains = swap_chains; present_info.pImageIndices = swap_chain_image_indices; present_info.pResults = nullptr; - { - std::lock_guard queue_lock(device_->primary_queue_mutex()); - status = vkQueuePresentKHR(device_->primary_queue(), &present_info); - } + status = vkQueuePresentKHR(presentation_queue_, &present_info); switch (status) { case VK_SUCCESS: break; diff --git a/src/xenia/ui/vulkan/vulkan_swap_chain.h b/src/xenia/ui/vulkan/vulkan_swap_chain.h index 72ac395e2..8a819400a 100644 --- a/src/xenia/ui/vulkan/vulkan_swap_chain.h +++ b/src/xenia/ui/vulkan/vulkan_swap_chain.h @@ -78,6 +78,8 @@ class VulkanSwapChain { VulkanInstance* instance_ = nullptr; VulkanDevice* device_ = nullptr; + VkQueue presentation_queue_ = nullptr; + uint32_t presentation_queue_family_ = -1; VkSurfaceKHR surface_ = nullptr; uint32_t surface_width_ = 0; uint32_t surface_height_ = 0; diff --git a/src/xenia/ui/vulkan/vulkan_util.h b/src/xenia/ui/vulkan/vulkan_util.h index f9528e6b6..62419429e 100644 --- a/src/xenia/ui/vulkan/vulkan_util.h +++ b/src/xenia/ui/vulkan/vulkan_util.h @@ -95,7 +95,6 @@ struct DeviceInfo { VkPhysicalDeviceFeatures features; VkPhysicalDeviceMemoryProperties memory_properties; std::vector queue_family_properties; - std::vector queue_family_supports_present; std::vector layers; std::vector extensions; };