From d168947ae4a0ec27ceee2cf1907cc2c761898df4 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 19 Jun 2020 00:18:51 +1000 Subject: [PATCH] SDL: Support Vulkan --- src/duckstation-sdl/CMakeLists.txt | 6 +- src/duckstation-sdl/d3d11_host_display.cpp | 1 + src/duckstation-sdl/duckstation-sdl.vcxproj | 20 +-- .../duckstation-sdl.vcxproj.filters | 4 + src/duckstation-sdl/opengl_host_display.cpp | 60 +------- src/duckstation-sdl/sdl_host_interface.cpp | 63 +++++--- src/duckstation-sdl/sdl_host_interface.h | 6 - src/duckstation-sdl/sdl_util.cpp | 68 +++++++++ src/duckstation-sdl/sdl_util.h | 10 ++ .../sdl_vulkan_host_display.cpp | 134 ++++++++++++++++++ src/duckstation-sdl/sdl_vulkan_host_display.h | 40 ++++++ 11 files changed, 326 insertions(+), 86 deletions(-) create mode 100644 src/duckstation-sdl/sdl_util.cpp create mode 100644 src/duckstation-sdl/sdl_util.h create mode 100644 src/duckstation-sdl/sdl_vulkan_host_display.cpp create mode 100644 src/duckstation-sdl/sdl_vulkan_host_display.h diff --git a/src/duckstation-sdl/CMakeLists.txt b/src/duckstation-sdl/CMakeLists.txt index 4c5d5f29f..ba0029bbb 100644 --- a/src/duckstation-sdl/CMakeLists.txt +++ b/src/duckstation-sdl/CMakeLists.txt @@ -7,10 +7,14 @@ add_executable(duckstation-sdl sdl_host_interface.cpp sdl_host_interface.h sdl_key_names.h + sdl_util.cpp + sdl_util.h + sdl_vulkan_host_display.cpp + sdl_vulkan_host_display.h ) target_include_directories(duckstation-sdl PRIVATE ${SDL2_INCLUDE_DIRS}) -target_link_libraries(duckstation-sdl PRIVATE core common imgui nativefiledialog glad frontend-common scmversion ${SDL2_LIBRARIES}) +target_link_libraries(duckstation-sdl PRIVATE core common imgui nativefiledialog glad frontend-common scmversion vulkan-loader ${SDL2_LIBRARIES}) if(WIN32) target_sources(duckstation-sdl PRIVATE diff --git a/src/duckstation-sdl/d3d11_host_display.cpp b/src/duckstation-sdl/d3d11_host_display.cpp index e660e2305..9100d407a 100644 --- a/src/duckstation-sdl/d3d11_host_display.cpp +++ b/src/duckstation-sdl/d3d11_host_display.cpp @@ -381,6 +381,7 @@ bool D3D11HostDisplay::CreateImGuiContext() ImGui_ImplDX11_NewFrame(); ImGui_ImplSDL2_NewFrame(m_window); + ImGui::NewFrame(); return true; } diff --git a/src/duckstation-sdl/duckstation-sdl.vcxproj b/src/duckstation-sdl/duckstation-sdl.vcxproj index 9041db343..aa8d1d4fa 100644 --- a/src/duckstation-sdl/duckstation-sdl.vcxproj +++ b/src/duckstation-sdl/duckstation-sdl.vcxproj @@ -60,6 +60,8 @@ + + @@ -68,6 +70,8 @@ + + @@ -227,7 +231,7 @@ WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -248,7 +252,7 @@ WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -269,7 +273,7 @@ WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default true false @@ -293,7 +297,7 @@ WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default true false @@ -316,7 +320,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -339,7 +343,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17 @@ -363,7 +367,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -386,7 +390,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17 diff --git a/src/duckstation-sdl/duckstation-sdl.vcxproj.filters b/src/duckstation-sdl/duckstation-sdl.vcxproj.filters index cb46bd830..58924d54d 100644 --- a/src/duckstation-sdl/duckstation-sdl.vcxproj.filters +++ b/src/duckstation-sdl/duckstation-sdl.vcxproj.filters @@ -6,6 +6,8 @@ + + @@ -14,6 +16,8 @@ + + diff --git a/src/duckstation-sdl/opengl_host_display.cpp b/src/duckstation-sdl/opengl_host_display.cpp index bb5cb4ceb..9ea69e2ed 100644 --- a/src/duckstation-sdl/opengl_host_display.cpp +++ b/src/duckstation-sdl/opengl_host_display.cpp @@ -2,6 +2,7 @@ #include "common/assert.h" #include "common/log.h" #include "imgui_impl_sdl.h" +#include "sdl_util.h" #include #include #include @@ -9,17 +10,6 @@ #include Log_SetChannel(OpenGLHostDisplay); -#ifdef __APPLE__ -#include -struct NSView; - -static NSView* GetContentViewFromWindow(NSWindow* window) -{ - // window.contentView - return reinterpret_cast(objc_msgSend)(reinterpret_cast(window), sel_getUid("contentView")); -} -#endif - class OpenGLDisplayWidgetTexture : public HostDisplayTexture { public: @@ -220,52 +210,11 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen bool OpenGLHostDisplay::CreateGLContext(bool debug_device) { - SDL_SysWMinfo syswm = {}; - SDL_VERSION(&syswm.version); - if (!SDL_GetWindowWMInfo(m_window, &syswm)) - { - Log_ErrorPrintf("SDL_GetWindowWMInfo failed"); + std::optional wi = SDLUtil::GetWindowInfoForSDLWindow(m_window); + if (!wi) return false; - } - int window_width, window_height; - SDL_GetWindowSize(m_window, &window_width, &window_height); - - WindowInfo wi; - wi.surface_width = static_cast(window_width); - wi.surface_height = static_cast(window_height); - wi.surface_format = WindowInfo::SurfaceFormat::RGB8; - - switch (syswm.subsystem) - { -#ifdef SDL_VIDEO_DRIVER_WINDOWS - case SDL_SYSWM_WINDOWS: - wi.type = WindowInfo::Type::Win32; - wi.window_handle = syswm.info.win.window; - break; -#endif - -#ifdef SDL_VIDEO_DRIVER_COCOA - case SDL_SYSWM_COCOA: - wi.type = WindowInfo::Type::MacOS; - wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window); - break; -#endif - -#ifdef SDL_VIDEO_DRIVER_X11 - case SDL_SYSWM_X11: - wi.type = WindowInfo::Type::X11; - wi.window_handle = reinterpret_cast(static_cast(syswm.info.x11.window)); - wi.display_connection = syswm.info.x11.display; - break; -#endif - - default: - Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast(syswm.subsystem)); - return false; - } - - m_gl_context = GL::Context::Create(wi); + m_gl_context = GL::Context::Create(wi.value()); if (!m_gl_context) { Log_ErrorPrintf("Failed to create a GL context of any kind."); @@ -298,6 +247,7 @@ bool OpenGLHostDisplay::CreateImGuiContext() ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(m_window); + ImGui::NewFrame(); return true; } diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 912247aba..49260089e 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -17,6 +17,7 @@ #include "opengl_host_display.h" #include "scmversion/scmversion.h" #include "sdl_key_names.h" +#include "sdl_vulkan_host_display.h" #include #include #include @@ -129,13 +130,29 @@ void SDLHostInterface::DestroySDLWindow() bool SDLHostInterface::CreateDisplay() { const bool debug_device = m_settings.gpu_use_debug_device; + const std::string shader_cache_directory(GetShaderCacheDirectory()); std::unique_ptr display; -#ifdef WIN32 - display = UseOpenGLRenderer() ? OpenGLHostDisplay::Create(m_window, debug_device) : - D3D11HostDisplay::Create(m_window, debug_device); -#else - display = OpenGLHostDisplay::Create(m_window, debug_device); + + switch (m_settings.gpu_renderer) + { + case GPURenderer::HardwareVulkan: + display = SDLVulkanHostDisplay::Create(m_window, shader_cache_directory, debug_device); + break; + + case GPURenderer::HardwareOpenGL: +#ifndef WIN32 + default: #endif + display = OpenGLHostDisplay::Create(m_window, debug_device); + break; + +#ifdef WIN32 + case GPURenderer::HardwareD3D11: + default: + display = D3D11HostDisplay::Create(m_window, debug_device); + break; +#endif + } if (!display) return false; @@ -181,13 +198,32 @@ void SDLHostInterface::UpdateFramebufferScale() bool SDLHostInterface::AcquireHostDisplay() { - // Handle renderer switch if required on Windows. -#ifdef WIN32 + // Handle renderer switch if required. const HostDisplay::RenderAPI render_api = m_display->GetRenderAPI(); - const bool render_api_is_gl = - render_api == HostDisplay::RenderAPI::OpenGL || render_api == HostDisplay::RenderAPI::OpenGLES; - const bool render_api_wants_gl = UseOpenGLRenderer(); - if (render_api_is_gl != render_api_wants_gl) + bool needs_switch = false; + switch (m_settings.gpu_renderer) + { +#ifdef WIN32 + case GPURenderer::HardwareD3D11: + needs_switch = (render_api != HostDisplay::RenderAPI::D3D11); + break; +#endif + + case GPURenderer::HardwareVulkan: + needs_switch = (render_api != HostDisplay::RenderAPI::Vulkan); + break; + + case GPURenderer::HardwareOpenGL: + needs_switch = (render_api != HostDisplay::RenderAPI::OpenGL && render_api != HostDisplay::RenderAPI::OpenGLES); + break; + + case GPURenderer::Software: + default: + needs_switch = false; + break; + } + + if (needs_switch) { ImGui::EndFrame(); DestroyDisplay(); @@ -198,10 +234,7 @@ bool SDLHostInterface::AcquireHostDisplay() if (!CreateDisplay()) Panic("Failed to recreate display on GPU renderer switch"); - - ImGui::NewFrame(); } -#endif return true; } @@ -358,8 +391,6 @@ bool SDLHostInterface::Initialize() RegisterHotkeys(); - ImGui::NewFrame(); - // process events to pick up controllers before updating input map ProcessEvents(); UpdateInputMap(); diff --git a/src/duckstation-sdl/sdl_host_interface.h b/src/duckstation-sdl/sdl_host_interface.h index 3625b4de0..ad019fbcd 100644 --- a/src/duckstation-sdl/sdl_host_interface.h +++ b/src/duckstation-sdl/sdl_host_interface.h @@ -58,12 +58,6 @@ protected: private: bool HasSystem() const { return static_cast(m_system); } -#ifdef WIN32 - bool UseOpenGLRenderer() const { return m_settings.gpu_renderer == GPURenderer::HardwareOpenGL; } -#else - bool UseOpenGLRenderer() const { return true; } -#endif - static float GetDPIScaleFactor(SDL_Window* window); bool CreateSDLWindow(); diff --git a/src/duckstation-sdl/sdl_util.cpp b/src/duckstation-sdl/sdl_util.cpp new file mode 100644 index 000000000..82a1b33cf --- /dev/null +++ b/src/duckstation-sdl/sdl_util.cpp @@ -0,0 +1,68 @@ +#include "sdl_util.h" +#include "common/log.h" +#include +Log_SetChannel(SDLUtil); + +#ifdef __APPLE__ +#include +struct NSView; + +static NSView* GetContentViewFromWindow(NSWindow* window) +{ + // window.contentView + return reinterpret_cast(objc_msgSend)(reinterpret_cast(window), sel_getUid("contentView")); +} +#endif + +namespace SDLUtil { + +std::optional GetWindowInfoForSDLWindow(SDL_Window* window) +{ + SDL_SysWMinfo syswm = {}; + SDL_VERSION(&syswm.version); + if (!SDL_GetWindowWMInfo(window, &syswm)) + { + Log_ErrorPrintf("SDL_GetWindowWMInfo failed"); + return std::nullopt; + } + + int window_width, window_height; + SDL_GetWindowSize(window, &window_width, &window_height); + + WindowInfo wi; + wi.surface_width = static_cast(window_width); + wi.surface_height = static_cast(window_height); + wi.surface_format = WindowInfo::SurfaceFormat::RGB8; + + switch (syswm.subsystem) + { +#ifdef SDL_VIDEO_DRIVER_WINDOWS + case SDL_SYSWM_WINDOWS: + wi.type = WindowInfo::Type::Win32; + wi.window_handle = syswm.info.win.window; + break; +#endif + +#ifdef SDL_VIDEO_DRIVER_COCOA + case SDL_SYSWM_COCOA: + wi.type = WindowInfo::Type::MacOS; + wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window); + break; +#endif + +#ifdef SDL_VIDEO_DRIVER_X11 + case SDL_SYSWM_X11: + wi.type = WindowInfo::Type::X11; + wi.window_handle = reinterpret_cast(static_cast(syswm.info.x11.window)); + wi.display_connection = syswm.info.x11.display; + break; +#endif + + default: + Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast(syswm.subsystem)); + return std::nullopt; + } + + return wi; +} +} // namespace SDLUtil \ No newline at end of file diff --git a/src/duckstation-sdl/sdl_util.h b/src/duckstation-sdl/sdl_util.h new file mode 100644 index 000000000..ce00e7818 --- /dev/null +++ b/src/duckstation-sdl/sdl_util.h @@ -0,0 +1,10 @@ +#pragma once +#include "common/types.h" +#include "common/window_info.h" +#include + +struct SDL_Window; + +namespace SDLUtil { +std::optional GetWindowInfoForSDLWindow(SDL_Window* window); +} \ No newline at end of file diff --git a/src/duckstation-sdl/sdl_vulkan_host_display.cpp b/src/duckstation-sdl/sdl_vulkan_host_display.cpp new file mode 100644 index 000000000..9262b211e --- /dev/null +++ b/src/duckstation-sdl/sdl_vulkan_host_display.cpp @@ -0,0 +1,134 @@ +#include "sdl_vulkan_host_display.h" +#include "common/assert.h" +#include "common/log.h" +#include "imgui.h" +#include "imgui_impl_sdl.h" +#include "imgui_impl_vulkan.h" +#include "sdl_util.h" +#include +#include +Log_SetChannel(VulkanHostDisplay); + +SDLVulkanHostDisplay::SDLVulkanHostDisplay(SDL_Window* window) : m_window(window) +{ + SDL_GetWindowSize(window, &m_window_width, &m_window_height); +} + +SDLVulkanHostDisplay::~SDLVulkanHostDisplay() +{ + ImGui_ImplSDL2_Shutdown(); + m_display.DestroyImGuiContext(); + m_display.DestroyResources(); + m_display.DestroyShaderCache(); + m_display.DestroySwapChain(); + m_display.DestroyContext(); + + if (m_window) + SDL_DestroyWindow(m_window); +} + +std::unique_ptr SDLVulkanHostDisplay::Create(SDL_Window* window, std::string_view shader_cache_directory, + bool debug_device) +{ + std::unique_ptr display = std::make_unique(window); + if (!display->Initialize(shader_cache_directory, debug_device)) + return nullptr; + + return display; +} + +HostDisplay::RenderAPI SDLVulkanHostDisplay::GetRenderAPI() const +{ + return m_display.GetRenderAPI(); +} + +void* SDLVulkanHostDisplay::GetRenderDevice() const +{ + return m_display.GetRenderDevice(); +} + +void* SDLVulkanHostDisplay::GetRenderContext() const +{ + return m_display.GetRenderContext(); +} + +void SDLVulkanHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height) +{ + m_display.ResizeSwapChain(static_cast(new_window_width), static_cast(new_window_height)); + m_window_width = static_cast(m_display.GetSwapChainWidth()); + m_window_height = static_cast(m_display.GetSwapChainHeight()); +} + +std::unique_ptr SDLVulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* data, + u32 data_stride, bool dynamic /*= false*/) +{ + return m_display.CreateTexture(width, height, data, data_stride, dynamic); +} + +void SDLVulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, + const void* data, u32 data_stride) +{ + m_display.UpdateTexture(texture, x, y, width, height, data, data_stride); +} + +bool SDLVulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, + void* out_data, u32 out_data_stride) +{ + return m_display.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride); +} + +void SDLVulkanHostDisplay::SetVSync(bool enabled) +{ + m_display.SetVSync(enabled); +} + +bool SDLVulkanHostDisplay::Initialize(std::string_view shader_cache_directory, bool debug_device) +{ + std::optional wi = SDLUtil::GetWindowInfoForSDLWindow(m_window); + if (!wi.has_value()) + { + Log_ErrorPrintf("Failed to get window info for SDL window"); + return false; + } + + if (!m_display.CreateContextAndSwapChain(wi.value(), debug_device)) + return false; + + m_display.CreateShaderCache(shader_cache_directory, debug_device); + + if (!m_display.CreateResources()) + return false; + + if (!m_display.CreateImGuiContext() || !ImGui_ImplSDL2_InitForVulkan(m_window)) + return false; + + ImGui_ImplSDL2_NewFrame(m_window); + ImGui::NewFrame(); + return true; +} + +void SDLVulkanHostDisplay::Render() +{ + if (!m_display.BeginRender()) + return; + + if (HasDisplayTexture()) + { + const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin); + m_display.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, + m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y, + m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering); + } + + m_display.RenderImGui(); + + if (HasSoftwareCursor()) + { + const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect(); + m_display.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get()); + } + + m_display.EndRenderAndPresent(); + + ImGui_ImplSDL2_NewFrame(m_window); +} diff --git a/src/duckstation-sdl/sdl_vulkan_host_display.h b/src/duckstation-sdl/sdl_vulkan_host_display.h new file mode 100644 index 000000000..76032e945 --- /dev/null +++ b/src/duckstation-sdl/sdl_vulkan_host_display.h @@ -0,0 +1,40 @@ +#pragma once +#include "core/host_display.h" +#include "frontend-common/vulkan_host_display.h" +#include +#include + +class SDLVulkanHostDisplay final : public HostDisplay +{ +public: + SDLVulkanHostDisplay(SDL_Window* window); + ~SDLVulkanHostDisplay(); + + static std::unique_ptr Create(SDL_Window* window, std::string_view shader_cache_directory, + bool debug_device); + + RenderAPI GetRenderAPI() const override; + void* GetRenderDevice() const override; + void* GetRenderContext() const override; + + void WindowResized(s32 new_window_width, s32 new_window_height) override; + + std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, + bool dynamic = false) override; + + void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, + u32 data_stride) override; + + bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) override; + + void SetVSync(bool enabled) override; + + void Render() override; + +private: + bool Initialize(std::string_view shader_cache_directory, bool debug_device); + + SDL_Window* m_window = nullptr; + FrontendCommon::VulkanHostDisplay m_display; +};