From 3cca4b421b98159a38b77881eb43a3a4b7d549df Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 1 Jun 2023 02:32:08 +0300 Subject: [PATCH] renderer_vulkan: Implement DXGI swapchain --- src/common/settings.cpp | 3 + src/common/settings.h | 1 + src/video_core/CMakeLists.txt | 4 + .../renderer_vulkan/renderer_vulkan.cpp | 2 +- .../renderer_vulkan/vk_present_manager.cpp | 4 +- .../renderer_vulkan/vk_swapchain.cpp | 271 +++++++++++++++++- src/video_core/renderer_vulkan/vk_swapchain.h | 43 ++- .../vulkan_common/vulkan_wrapper.cpp | 1 + src/video_core/vulkan_common/vulkan_wrapper.h | 10 + src/yuzu/configuration/config.cpp | 2 + .../configure_graphics_advanced.cpp | 13 + .../configure_graphics_advanced.h | 1 + .../configure_graphics_advanced.ui | 86 +++--- 13 files changed, 390 insertions(+), 51 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index ff53e80bb4..330381a60a 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -66,6 +66,8 @@ void LogSettings() { log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue()); log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); + log_setting("Renderer_AsyncPresentation", values.async_presentation.GetValue()); + log_setting("Renderer_UseDXGISwapchain", values.use_dxgi_swapchain.GetValue()); log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); log_setting("Audio_OutputEngine", values.sink_id.GetValue()); log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue()); @@ -209,6 +211,7 @@ void RestoreGlobalState(bool is_powered_on) { values.fsr_sharpening_slider.SetGlobal(true); values.renderer_backend.SetGlobal(true); values.async_presentation.SetGlobal(true); + values.use_dxgi_swapchain.SetGlobal(true); values.renderer_force_max_clock.SetGlobal(true); values.vulkan_device.SetGlobal(true); values.fullscreen_mode.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 7f865b2a75..17a8ab3a84 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -437,6 +437,7 @@ struct Values { SwitchableSetting renderer_backend{ RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"}; SwitchableSetting async_presentation{false, "async_presentation"}; + SwitchableSetting use_dxgi_swapchain{false, "use_dxgi_swapchain"}; SwitchableSetting renderer_force_max_clock{false, "force_max_clock"}; Setting renderer_debug{false, "debug"}; Setting renderer_shader_feedback{false, "shader_feedback"}; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 308d013d63..93423e9916 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -293,6 +293,10 @@ add_dependencies(video_core host_shaders) target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) target_link_libraries(video_core PRIVATE sirit Vulkan::Headers) +if (WIN32) + target_link_libraries(video_core PRIVATE DXGI.lib DXGUID.lib D3D12.lib) +endif() + if (ENABLE_NSIGHT_AFTERMATH) if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) message(FATAL_ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided") diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 8e31eba34a..f45f40862e 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -91,7 +91,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, surface(CreateSurface(instance, render_window.GetWindowInfo())), device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), state_tracker(), scheduler(device, state_tracker), - swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, + swapchain(*surface, emu_window, device, scheduler, render_window.GetFramebufferLayout().width, render_window.GetFramebufferLayout().height, false), present_manager(render_window, device, memory_allocator, scheduler, swapchain), blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index c495830136..a79dc17a04 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -415,7 +415,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) { const VkSemaphore present_semaphore = swapchain.CurrentPresentSemaphore(); const VkSemaphore render_semaphore = swapchain.CurrentRenderSemaphore(); - const std::array wait_semaphores = {present_semaphore, *frame->render_ready}; + const std::array wait_semaphores = {*frame->render_ready, present_semaphore}; static constexpr std::array wait_stage_masks{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, @@ -425,7 +425,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) { const VkSubmitInfo submit_info{ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .pNext = nullptr, - .waitSemaphoreCount = 2U, + .waitSemaphoreCount = swapchain.IsDXGI() ? 1U : 2U, .pWaitSemaphores = wait_semaphores.data(), .pWaitDstStageMask = wait_stage_masks.data(), .commandBufferCount = 1, diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 8c0dec5900..f598e2cd20 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -5,11 +5,13 @@ #include #include #include - +#include +#include "common/assert.h" #include "common/logging/log.h" #include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/core.h" +#include "core/frontend/emu_window.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/vulkan_common/vulkan_device.h" @@ -104,10 +106,17 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap } // Anonymous namespace -Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, - u32 width_, u32 height_, bool srgb) - : surface{surface_}, device{device_}, scheduler{scheduler_} { +Swapchain::Swapchain(VkSurfaceKHR surface_, const Core::Frontend::EmuWindow& emu_window_, + const Device& device_, Scheduler& scheduler_, u32 width_, u32 height_, + bool srgb) + : surface{surface_}, emu_window{emu_window_}, device{device_}, scheduler{scheduler_}, + use_dxgi{Settings::values.use_dxgi_swapchain.GetValue()} { Create(width_, height_, srgb); +#ifdef WIN32 + if (use_dxgi) { + CreateDXGIFactory(); + } +#endif } Swapchain::~Swapchain() = default; @@ -124,16 +133,36 @@ void Swapchain::Create(u32 width_, u32 height_, bool srgb) { return; } +#ifdef WIN32 + if (dxgi_factory && use_dxgi) { + const UINT buffer_count = static_cast(image_count); + dxgi_swapchain->ResizeBuffers(buffer_count, capabilities.currentExtent.width, + capabilities.currentExtent.height, DXGI_FORMAT_B8G8R8A8_UNORM, + 0U); + } +#endif + Destroy(); CreateSwapchain(capabilities, srgb); CreateSemaphores(); +#ifdef WIN32 + if (dxgi_factory && use_dxgi) { + ImportDXGIImages(); + } +#endif resource_ticks.clear(); resource_ticks.resize(image_count); } bool Swapchain::AcquireNextImage() { +#ifdef WIN32 + if (use_dxgi) { + image_index = dxgi_swapchain->GetCurrentBackBufferIndex(); + return is_suboptimal || is_outdated; + } +#endif const VkResult result = device.GetLogical().AcquireNextImageKHR( *swapchain, std::numeric_limits::max(), *present_semaphores[frame_index], VK_NULL_HANDLE, &image_index); @@ -158,6 +187,11 @@ bool Swapchain::AcquireNextImage() { } void Swapchain::Present(VkSemaphore render_semaphore) { +#ifdef WIN32 + if (use_dxgi) { + return PresentDXGI(render_semaphore); + } +#endif const auto present_queue{device.GetPresentQueue()}; const VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -199,6 +233,8 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end(); has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != present_modes.end(); + current_srgb = srgb; + image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; surface_format = ChooseSwapSurfaceFormat(formats); @@ -262,11 +298,8 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); extent = swapchain_ci.imageExtent; - current_srgb = srgb; - images = swapchain.GetImages(); image_count = static_cast(images.size()); - image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; } void Swapchain::CreateSemaphores() { @@ -280,8 +313,19 @@ void Swapchain::CreateSemaphores() { void Swapchain::Destroy() { frame_index = 0; - present_semaphores.clear(); swapchain.reset(); +#ifdef WIN32 + if (!use_dxgi) { + return; + } + for (HANDLE handle : shared_handles) { + CloseHandle(handle); + } + shared_handles.clear(); + present_semaphores.clear(); + imported_memories.clear(); + dx_vk_images.clear(); +#endif } bool Swapchain::NeedsPresentModeUpdate() const { @@ -289,4 +333,215 @@ bool Swapchain::NeedsPresentModeUpdate() const { return present_mode != requested_mode; } +#ifdef WIN32 +void Swapchain::CreateDXGIFactory() { + UINT create_factory_flags = 0; + CreateDXGIFactory2(create_factory_flags, IID_PPV_ARGS(&dxgi_factory)); + + VkPhysicalDeviceIDProperties device_id_props = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR, + .pNext = nullptr, + }; + VkPhysicalDeviceProperties2 device_props_2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, + .pNext = &device_id_props, + }; + + device.GetPhysical().GetProperties2(device_props_2); + if (!device_id_props.deviceLUIDValid) { + LOG_ERROR(Render_Vulkan, "Device LUID not valid, DXGI interop not possible"); + return; + } + + const LUID* pluid = reinterpret_cast(&device_id_props.deviceLUID); + dxgi_factory->EnumAdapterByLuid(*pluid, IID_PPV_ARGS(&dxgi_adapter)); + D3D12CreateDevice(dxgi_adapter.Get(), D3D_FEATURE_LEVEL_11_1, IID_PPV_ARGS(&dx_device)); + + const UINT node_count = dx_device->GetNodeCount(); + const UINT node_mask = node_count <= 1 ? 0 : device_id_props.deviceNodeMask; + + const D3D12_COMMAND_QUEUE_DESC dxQDesc = {D3D12_COMMAND_LIST_TYPE_DIRECT, + D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, + D3D12_COMMAND_QUEUE_FLAG_NONE, node_mask}; + dx_device->CreateCommandQueue(&dxQDesc, IID_PPV_ARGS(&dx_command_queue)); + + const UINT buffer_count = static_cast(image_count); + const DXGI_SWAP_CHAIN_DESC1 swapchain_desc = { + .Width = extent.width, + .Height = extent.height, + .Format = DXGI_FORMAT_B8G8R8A8_UNORM, + .Stereo = FALSE, + .SampleDesc = {1, 0}, + .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT, + .BufferCount = buffer_count, + .Scaling = DXGI_SCALING_NONE, + .SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, + .AlphaMode = DXGI_ALPHA_MODE_IGNORE, + .Flags = 0, + }; + + const HWND hWnd = static_cast(emu_window.GetWindowInfo().render_surface); + dxgi_factory->CreateSwapChainForHwnd(dx_command_queue.Get(), hWnd, &swapchain_desc, nullptr, + nullptr, &dxgi_swapchain1); + dxgi_factory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); + dxgi_swapchain1.As(&dxgi_swapchain); + + present_fence = device.GetLogical().CreateFence({ + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }); +} + +void Swapchain::ImportDXGIImages() { + if (!dxgi_factory) { + return; + } + + const auto& dld = device.GetLogical(); + std::vector> dx_images(image_count); + + images.clear(); + images.resize(image_count); + imported_memories.resize(image_count); + shared_handles.resize(image_count); + dx_vk_images.resize(image_count); + + for (UINT i = 0; i < dx_images.size(); i++) { + dxgi_swapchain->GetBuffer(i, IID_PPV_ARGS(&dx_images[i])); + } + + for (size_t i = 0; i < dx_images.size(); i++) { + const auto& dxImage = dx_images[i]; + const auto dxImageDesc = dxImage->GetDesc(); + + D3D12_HEAP_PROPERTIES dx_image_heap; + D3D12_HEAP_FLAGS dx_image_heap_flags; + dxImage->GetHeapProperties(&dx_image_heap, &dx_image_heap_flags); + + const VkExternalMemoryImageCreateInfoKHR eii = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR, + .pNext = nullptr, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR}; + + const VkImageCreateInfo image_ci = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = &eii, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = VK_FORMAT_B8G8R8A8_UNORM, + .extent = + { + .width = static_cast(dxImageDesc.Width), + .height = static_cast(dxImageDesc.Height), + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + dx_vk_images[i] = dld.CreateImage(image_ci); + images[i] = *dx_vk_images[i]; + + const std::wstring handle_name = fmt::format(L"DXImage{}", i); + dx_device->CreateSharedHandle(dxImage.Get(), NULL, GENERIC_ALL, handle_name.data(), + &shared_handles[i]); + + static constexpr u32 BAD_BITS = 0xcdcdcdcd; + + VkMemoryWin32HandlePropertiesKHR win32_memory_props = { + .sType = VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR, + .pNext = nullptr, + .memoryTypeBits = BAD_BITS, + }; + dld.GetMemoryWin32HandlePropertiesKHR(VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, + shared_handles[i], win32_memory_props); + + const auto requirements = dld.GetImageMemoryRequirements(images[i]); + if (win32_memory_props.memoryTypeBits == BAD_BITS) [[unlikely]] { + win32_memory_props.memoryTypeBits = requirements.memoryTypeBits; + } else { + win32_memory_props.memoryTypeBits &= requirements.memoryTypeBits; + } + + // Find the memory type the image should be placed in. + int mem_type_index = -1; + const auto properties = device.GetPhysical().GetMemoryProperties().memoryProperties; + for (u32 im = 0; im < properties.memoryTypeCount; ++im) { + const u32 current_bit = 0x1 << im; + if (win32_memory_props.memoryTypeBits == current_bit) { + if (properties.memoryTypes[im].propertyFlags & + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + mem_type_index = im; + break; + } + } + } + ASSERT_MSG(mem_type_index != -1, "Device local import memory not found!"); + + // DX12 resources need to be dedicated per the vulkan spec. + const VkMemoryDedicatedAllocateInfoKHR dii = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = nullptr, + .image = images[i], + .buffer = VK_NULL_HANDLE, + }; + + const VkImportMemoryWin32HandleInfoKHR imi = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR, + .pNext = &dii, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR, + .handle = shared_handles[i], + .name = nullptr}; + + const VkMemoryAllocateInfo alloc_info = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &imi, + .allocationSize = requirements.size, + .memoryTypeIndex = + static_cast(mem_type_index)}; + + // Bind imported memory to created image + imported_memories[i] = dld.AllocateMemory(alloc_info); + dx_vk_images[i].BindMemory(*imported_memories[i], 0); + } +} + +void Swapchain::PresentDXGI(VkSemaphore render_semaphore) { + const VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + const VkSubmitInfo submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &render_semaphore, + .pWaitDstStageMask = &wait_stage, + .commandBufferCount = 0, + .pCommandBuffers = nullptr, + .signalSemaphoreCount = 0, + .pSignalSemaphores = nullptr, + }; + const auto present_queue{device.GetPresentQueue()}; + present_queue.Submit(submit, *present_fence); + + // Wait for the generated image to be rendered before calling present from D3D. + // TODO: Is there any better way to sync? Call vulkan semaphore from D3D? + present_fence.Wait(); + present_fence.Reset(); + + const DXGI_PRESENT_PARAMETERS present_params = {}; + dxgi_swapchain->Present1(1, 0, &present_params); + + ++frame_index; + if (frame_index >= image_count) { + frame_index = 0; + } +} +#endif + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index bf1ea7254c..9894d0b729 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -5,6 +5,14 @@ #include +#ifdef WIN32 +#include +#include +#include +#include +using namespace Microsoft::WRL; +#endif + #include "common/common_types.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -12,6 +20,10 @@ namespace Layout { struct FramebufferLayout; } +namespace Core::Frontend { +class EmuWindow; +} + namespace Vulkan { class Device; @@ -19,8 +31,9 @@ class Scheduler; class Swapchain { public: - explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, - u32 height, bool srgb); + explicit Swapchain(VkSurfaceKHR surface, const Core::Frontend::EmuWindow& emu_window, + const Device& device, Scheduler& scheduler, u32 width, u32 height, + bool srgb); ~Swapchain(); /// Creates (or recreates) the swapchain with a given size. @@ -57,6 +70,11 @@ public: return current_srgb; } + /// Returns true when images are presented to DXGI swapchain. + bool IsDXGI() const { + return use_dxgi; + } + VkExtent2D GetSize() const { return extent; } @@ -118,7 +136,14 @@ private: bool NeedsPresentModeUpdate() const; +#ifdef WIN32 + void CreateDXGIFactory(); + void ImportDXGIImages(); + void PresentDXGI(VkSemaphore render_semaphore); +#endif + const VkSurfaceKHR surface; + const Core::Frontend::EmuWindow& emu_window; const Device& device; Scheduler& scheduler; @@ -130,6 +155,19 @@ private: std::vector present_semaphores; std::vector render_semaphores; +#ifdef WIN32 + ComPtr dxgi_factory; + ComPtr dxgi_adapter; + ComPtr dx_device; + ComPtr dx_command_queue; + ComPtr dxgi_swapchain1; + ComPtr dxgi_swapchain; + std::vector imported_memories; + std::vector shared_handles; + std::vector dx_vk_images; + vk::Fence present_fence; +#endif + u32 width; u32 height; @@ -147,6 +185,7 @@ private: bool current_srgb{}; bool is_outdated{}; bool is_suboptimal{}; + bool use_dxgi{}; }; } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 336f537007..1d274bcfb3 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -194,6 +194,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkGetMemoryFdKHR); #ifdef _WIN32 X(vkGetMemoryWin32HandleKHR); + X(vkGetMemoryWin32HandlePropertiesKHR); #endif X(vkGetQueryPoolResults); X(vkGetPipelineExecutablePropertiesKHR); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 4ff328a21e..6fef05362d 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -312,6 +312,7 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR{}; #ifdef _WIN32 PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{}; + PFN_vkGetMemoryWin32HandlePropertiesKHR vkGetMemoryWin32HandlePropertiesKHR{}; #endif PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{}; PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{}; @@ -930,6 +931,15 @@ public: return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, flags); } + +#ifdef _WIN32 + VkResult GetMemoryWin32HandlePropertiesKHR( + VkExternalMemoryHandleTypeFlagBits handle_type, HANDLE w_handle, + VkMemoryWin32HandlePropertiesKHR& handle_properties) const { + return dld->vkGetMemoryWin32HandlePropertiesKHR(handle, handle_type, w_handle, + &handle_properties); + } +#endif }; class PhysicalDevice { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 662651196d..3db9d5b8cd 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -695,6 +695,7 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.renderer_backend); ReadGlobalSetting(Settings::values.async_presentation); + ReadGlobalSetting(Settings::values.use_dxgi_swapchain); ReadGlobalSetting(Settings::values.renderer_force_max_clock); ReadGlobalSetting(Settings::values.vulkan_device); ReadGlobalSetting(Settings::values.fullscreen_mode); @@ -1323,6 +1324,7 @@ void Config::SaveRendererValues() { static_cast(Settings::values.renderer_backend.GetDefault()), Settings::values.renderer_backend.UsingGlobal()); WriteGlobalSetting(Settings::values.async_presentation); + WriteGlobalSetting(Settings::values.use_dxgi_swapchain); WriteGlobalSetting(Settings::values.renderer_force_max_clock); WriteGlobalSetting(Settings::values.vulkan_device); WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()), diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 896863f871..d6dec9bc89 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -14,6 +14,13 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_ SetupPerGameUI(); +#ifdef WIN32 + static constexpr bool is_win32 = true; +#else + static constexpr bool is_win32 = false; +#endif + ui->dxgi_swapchain->setVisible(is_win32); + SetConfiguration(); ui->enable_compute_pipelines_checkbox->setVisible(false); @@ -33,6 +40,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { ui->enable_compute_pipelines_checkbox->setEnabled(runtime_lock); ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); + ui->dxgi_swapchain->setChecked(Settings::values.use_dxgi_swapchain.GetValue()); ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); ui->use_reactive_flushing->setChecked(Settings::values.use_reactive_flushing.GetValue()); ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); @@ -91,6 +99,8 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines, ui->enable_compute_pipelines_checkbox, enable_compute_pipelines); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_dxgi_swapchain, + ui->dxgi_swapchain, dxgi_swapchain); } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -110,6 +120,7 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); + ui->dxgi_swapchain->setEnabled(Settings::values.use_dxgi_swapchain.UsingGlobal()); ui->renderer_force_max_clock->setEnabled( Settings::values.renderer_force_max_clock.UsingGlobal()); ui->use_reactive_flushing->setEnabled(Settings::values.use_reactive_flushing.UsingGlobal()); @@ -131,6 +142,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->async_present, Settings::values.async_presentation, async_present); + ConfigurationShared::SetColoredTristate(ui->dxgi_swapchain, Settings::values.use_dxgi_swapchain, + dxgi_swapchain); ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, Settings::values.renderer_force_max_clock, renderer_force_max_clock); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 1c7b636b96..112c879962 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -39,6 +39,7 @@ private: std::unique_ptr ui; ConfigurationShared::CheckState async_present; + ConfigurationShared::CheckState dxgi_swapchain; ConfigurationShared::CheckState renderer_force_max_clock; ConfigurationShared::CheckState use_vsync; ConfigurationShared::CheckState async_astc; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 37757a918a..ae318461e4 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -6,8 +6,8 @@ 0 0 - 404 - 376 + 418 + 444 @@ -72,44 +72,44 @@ - - 0 - - - 0 - - - 0 - - - 0 - - - + + 0 + + + 0 + + + 0 + + + 0 + + + + + ASTC recompression: + + + + + + - ASTC recompression: + Uncompressed (Best quality) - - - - - - - Uncompressed (Best quality) - - - - - BC1 (Low quality) - - - - - BC3 (Medium quality) - - - - + + + + BC1 (Low quality) + + + + + BC3 (Medium quality) + + + + @@ -191,6 +191,16 @@ Compute pipelines are always enabled on all other drivers. + + + + <html><head/><body><p>Presents frames with a D3D12 swapchain when using Vulkan.</p></body></html> + + + Use DXGI swapchain (Vulkan only) + + +