diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index 6dc18d695..dfa086cd5 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -58,10 +58,12 @@ add_executable(duckstation-qt settingsdialog.cpp settingsdialog.h settingsdialog.ui + vulkanhostdisplay.cpp + vulkanhostdisplay.h ) target_include_directories(duckstation-qt PRIVATE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}") -target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui glad minizip scmversion Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) +target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui glad minizip scmversion vulkan-loader Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network) if(WIN32) target_sources(duckstation-qt PRIVATE diff --git a/src/duckstation-qt/d3d11hostdisplay.cpp b/src/duckstation-qt/d3d11hostdisplay.cpp index a3781b478..1e5ad79be 100644 --- a/src/duckstation-qt/d3d11hostdisplay.cpp +++ b/src/duckstation-qt/d3d11hostdisplay.cpp @@ -214,7 +214,7 @@ bool D3D11HostDisplay::createDeviceContext(bool debug_device) m_allow_tearing_supported = (allow_tearing_supported == TRUE); } - return true; + return createSwapChain(); } void D3D11HostDisplay::destroyDeviceContext() @@ -232,7 +232,7 @@ bool D3D11HostDisplay::shouldUseFlipModelSwapChain() const return m_widget->parent() == nullptr; } -bool D3D11HostDisplay::createSurface() +bool D3D11HostDisplay::createSwapChain() { m_using_flip_model_swap_chain = shouldUseFlipModelSwapChain(); @@ -282,11 +282,7 @@ bool D3D11HostDisplay::createSurface() if (FAILED(hr)) Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed"); - if (!createSwapChainRTV()) - return false; - - emit m_widget->windowResizedEvent(m_window_width, m_window_height); - return true; + return createSwapChainRTV(); } bool D3D11HostDisplay::createSwapChainRTV() @@ -314,6 +310,11 @@ bool D3D11HostDisplay::createSwapChainRTV() return true; } +bool D3D11HostDisplay::recreateSurface() +{ + return createSwapChain(); +} + void D3D11HostDisplay::destroySurface() { m_swap_chain_rtv.Reset(); diff --git a/src/duckstation-qt/d3d11hostdisplay.h b/src/duckstation-qt/d3d11hostdisplay.h index 4659e92c3..fa5bf1c65 100644 --- a/src/duckstation-qt/d3d11hostdisplay.h +++ b/src/duckstation-qt/d3d11hostdisplay.h @@ -22,7 +22,7 @@ public: bool hasDeviceContext() const override; bool createDeviceContext(bool debug_device) override; void destroyDeviceContext() override; - bool createSurface() override; + bool recreateSurface() override; void destroySurface() override; RenderAPI GetRenderAPI() const override; @@ -50,6 +50,7 @@ private: void destroyDeviceResources() override; bool shouldUseFlipModelSwapChain() const; + bool createSwapChain(); bool createSwapChainRTV(); void renderDisplay(); diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 111ace081..1b55b2df5 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -59,8 +59,10 @@ + + @@ -97,6 +99,9 @@ {8bda439c-6358-45fb-9994-2ff083babe06} + + {9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035} + {ee054e08-3799-4a59-a422-18259c105ffd} @@ -335,7 +340,7 @@ WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -356,7 +361,7 @@ WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -377,7 +382,7 @@ WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) Default true false @@ -400,7 +405,7 @@ WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) Default true false @@ -422,7 +427,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -445,7 +450,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories) true true stdcpp17 @@ -469,7 +474,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) true false stdcpp17 @@ -492,7 +497,7 @@ MaxSpeed true WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) - $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories) true true stdcpp17 @@ -512,4 +517,4 @@ - + \ No newline at end of file diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index 5cf95dab4..1b30ee96e 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -16,7 +16,6 @@ - @@ -39,6 +38,13 @@ + + + + + + + @@ -48,6 +54,7 @@ + @@ -74,6 +81,8 @@ + + @@ -85,6 +94,7 @@ + @@ -95,4 +105,4 @@ - + \ No newline at end of file diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 8b6bceea3..4d208127a 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -103,13 +103,6 @@ void MainWindow::createDisplay(QThread* worker_thread, bool use_debug_device, bo return; } - if (!m_host_display->createSurface()) - { - reportError(tr("Failed to create host display surface.")); - m_host_display->destroyDeviceContext(); - return; - } - m_host_display->deactivateDeviceContext(); } @@ -151,7 +144,7 @@ void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool ren // we need the surface visible.. this might be able to be replaced with something else QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - if (!m_host_display->createSurface()) + if (!m_host_display->recreateSurface()) Panic("Failed to recreate surface on new widget."); m_display_widget->setFocus(); diff --git a/src/duckstation-qt/openglhostdisplay.cpp b/src/duckstation-qt/openglhostdisplay.cpp index 4feaca1fc..c6234e7c6 100644 --- a/src/duckstation-qt/openglhostdisplay.cpp +++ b/src/duckstation-qt/openglhostdisplay.cpp @@ -4,15 +4,10 @@ #include "imgui.h" #include "qtdisplaywidget.h" #include "qthostinterface.h" -#include -#include #include #include #include #include -#if !defined(WIN32) && !defined(APPLE) -#include -#endif #include Log_SetChannel(OpenGLHostDisplay); @@ -193,49 +188,16 @@ bool OpenGLHostDisplay::hasDeviceContext() const return static_cast(m_gl_context); } -WindowInfo OpenGLHostDisplay::getWindowInfo() const -{ - WindowInfo wi; - - // Windows and Apple are easy here since there's no display connection. -#if defined(WIN32) - wi.type = WindowInfo::Type::Win32; - wi.window_handle = reinterpret_cast(m_widget->winId()); -#elif defined(__APPLE__) - wi.type = WindowInfo::Type::MacOS; - wi.window_handle = reinterpret_cast(m_widget->winId()); -#else - QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); - const QString platform_name = QGuiApplication::platformName(); - if (platform_name == QStringLiteral("xcb")) - { - wi.type = WindowInfo::Type::X11; - wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle()); - wi.window_handle = reinterpret_cast(m_widget->winId()); - } - else if (platform_name == QStringLiteral("wayland")) - { - wi.type = WindowInfo::Type::Wayland; - wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle()); - wi.window_handle = pni->nativeResourceForWindow("surface", m_widget->windowHandle()); - } - else - { - qCritical() << "Unknown PNI platform " << platform_name; - return wi; - } -#endif - - wi.surface_width = m_widget->width(); - wi.surface_height = m_widget->height(); - wi.surface_format = WindowInfo::SurfaceFormat::RGB8; - - return wi; -} - bool OpenGLHostDisplay::createDeviceContext(bool debug_device) { - m_gl_context = GL::Context::Create(getWindowInfo()); + m_window_width = m_widget->scaledWindowWidth(); + m_window_height = m_widget->scaledWindowHeight(); + + std::optional wi = getWindowInfo(); + if (!wi.has_value()) + return false; + + m_gl_context = GL::Context::Create(wi.value()); if (!m_gl_context) { Log_ErrorPrintf("Failed to create any GL context"); @@ -245,7 +207,7 @@ bool OpenGLHostDisplay::createDeviceContext(bool debug_device) return true; } -bool OpenGLHostDisplay::initializeDeviceContext(bool debug_device) +bool OpenGLHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) { if (debug_device && GLAD_GL_KHR_debug) { @@ -254,7 +216,7 @@ bool OpenGLHostDisplay::initializeDeviceContext(bool debug_device) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); } - if (!QtHostDisplay::initializeDeviceContext(debug_device)) + if (!QtHostDisplay::initializeDeviceContext(shader_cache_directory, debug_device)) { m_gl_context->DoneCurrent(); return false; @@ -286,14 +248,17 @@ void OpenGLHostDisplay::destroyDeviceContext() m_gl_context.reset(); } -bool OpenGLHostDisplay::createSurface() +bool OpenGLHostDisplay::recreateSurface() { m_window_width = m_widget->scaledWindowWidth(); m_window_height = m_widget->scaledWindowHeight(); - emit m_widget->windowResizedEvent(m_window_width, m_window_height); if (m_gl_context) - m_gl_context->ChangeSurface(getWindowInfo()); + { + std::optional wi = getWindowInfo(); + if (!wi.has_value() || !m_gl_context->ChangeSurface(wi.value())) + return false; + } return true; } diff --git a/src/duckstation-qt/openglhostdisplay.h b/src/duckstation-qt/openglhostdisplay.h index 6ec94678f..9342ae9f4 100644 --- a/src/duckstation-qt/openglhostdisplay.h +++ b/src/duckstation-qt/openglhostdisplay.h @@ -27,11 +27,11 @@ public: bool hasDeviceContext() const override; bool createDeviceContext(bool debug_device) override; - bool initializeDeviceContext(bool debug_device) override; + bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override; bool activateDeviceContext() override; void deactivateDeviceContext() override; void destroyDeviceContext() override; - bool createSurface() override; + bool recreateSurface() override; void destroySurface(); RenderAPI GetRenderAPI() const override; @@ -54,8 +54,6 @@ private: const char* GetGLSLVersionString() const; std::string GetGLSLVersionHeader() const; - WindowInfo getWindowInfo() const; - bool createImGuiContext() override; void destroyImGuiContext() override; bool createDeviceResources() override; diff --git a/src/duckstation-qt/qthostdisplay.cpp b/src/duckstation-qt/qthostdisplay.cpp index c343611df..d7d0df492 100644 --- a/src/duckstation-qt/qthostdisplay.cpp +++ b/src/duckstation-qt/qthostdisplay.cpp @@ -4,7 +4,12 @@ #include "imgui.h" #include "qtdisplaywidget.h" #include "qthostinterface.h" +#include +#include #include +#if !defined(WIN32) && !defined(APPLE) +#include +#endif QtHostDisplay::QtHostDisplay(QtHostInterface* host_interface) : m_host_interface(host_interface) {} @@ -42,7 +47,7 @@ bool QtHostDisplay::createDeviceContext(bool debug_device) return false; } -bool QtHostDisplay::initializeDeviceContext(bool debug_device) +bool QtHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) { if (!createImGuiContext() || !createDeviceResources()) return false; @@ -63,7 +68,7 @@ void QtHostDisplay::destroyDeviceContext() destroyDeviceResources(); } -bool QtHostDisplay::createSurface() +bool QtHostDisplay::recreateSurface() { return false; } @@ -118,3 +123,43 @@ void QtHostDisplay::updateImGuiDisplaySize() io.DisplaySize.x = static_cast(m_window_width); io.DisplaySize.y = static_cast(m_window_height); } + +std::optional QtHostDisplay::getWindowInfo() const +{ + WindowInfo wi; + + // Windows and Apple are easy here since there's no display connection. +#if defined(WIN32) + wi.type = WindowInfo::Type::Win32; + wi.window_handle = reinterpret_cast(m_widget->winId()); +#elif defined(__APPLE__) + wi.type = WindowInfo::Type::MacOS; + wi.window_handle = reinterpret_cast(m_widget->winId()); +#else + QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); + const QString platform_name = QGuiApplication::platformName(); + if (platform_name == QStringLiteral("xcb")) + { + wi.type = WindowInfo::Type::X11; + wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle()); + wi.window_handle = reinterpret_cast(m_widget->winId()); + } + else if (platform_name == QStringLiteral("wayland")) + { + wi.type = WindowInfo::Type::Wayland; + wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle()); + wi.window_handle = pni->nativeResourceForWindow("surface", m_widget->windowHandle()); + } + else + { + qCritical() << "Unknown PNI platform " << platform_name; + return std::nullopt; + } +#endif + + wi.surface_width = m_widget->width(); + wi.surface_height = m_widget->height(); + wi.surface_format = WindowInfo::SurfaceFormat::RGB8; + + return wi; +} diff --git a/src/duckstation-qt/qthostdisplay.h b/src/duckstation-qt/qthostdisplay.h index 285291ad9..dbf337406 100644 --- a/src/duckstation-qt/qthostdisplay.h +++ b/src/duckstation-qt/qthostdisplay.h @@ -1,6 +1,9 @@ #pragma once #include "common/types.h" +#include "common/window_info.h" #include "core/host_display.h" +#include +#include class QThread; class QWidget; @@ -22,11 +25,11 @@ public: virtual bool hasDeviceContext() const; virtual bool createDeviceContext(bool debug_device); - virtual bool initializeDeviceContext(bool debug_device); + virtual bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device); virtual bool activateDeviceContext(); virtual void deactivateDeviceContext(); virtual void destroyDeviceContext(); - virtual bool createSurface(); + virtual bool recreateSurface(); virtual void destroySurface(); virtual void WindowResized(s32 new_window_width, s32 new_window_height) override; @@ -39,6 +42,8 @@ protected: virtual bool createDeviceResources(); virtual void destroyDeviceResources(); + std::optional getWindowInfo() const; + QtHostInterface* m_host_interface; QtDisplayWidget* m_widget = nullptr; }; diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index 18233d813..5f56492ae 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -15,6 +15,7 @@ #include "qtprogresscallback.h" #include "qtsettingsinterface.h" #include "qtutils.h" +#include "vulkanhostdisplay.h" #include #include #include @@ -327,7 +328,7 @@ bool QtHostInterface::AcquireHostDisplay() } if (!getHostDisplay()->activateDeviceContext() || - !getHostDisplay()->initializeDeviceContext(m_settings.gpu_use_debug_device)) + !getHostDisplay()->initializeDeviceContext(GetShaderCacheDirectory(), m_settings.gpu_use_debug_device)) { getHostDisplay()->destroyDeviceContext(); emit destroyDisplayRequested(); @@ -343,14 +344,26 @@ QtHostDisplay* QtHostInterface::createHostDisplay() { Assert(!getHostDisplay()); -#ifdef WIN32 - if (m_settings.gpu_renderer == GPURenderer::HardwareOpenGL) - m_display = new OpenGLHostDisplay(this); - else - m_display = new D3D11HostDisplay(this); -#else - m_display = new OpenGLHostDisplay(this); + switch (m_settings.gpu_renderer) + { + case GPURenderer::HardwareVulkan: + m_display = new VulkanHostDisplay(this); + break; + + case GPURenderer::HardwareOpenGL: +#ifndef WIN32 + default: #endif + m_display = new OpenGLHostDisplay(this); + break; + +#ifdef WIN32 + case GPURenderer::HardwareD3D11: + default: + m_display = new D3D11HostDisplay(this); + break; +#endif + } return getHostDisplay(); } diff --git a/src/duckstation-qt/vulkanhostdisplay.cpp b/src/duckstation-qt/vulkanhostdisplay.cpp new file mode 100644 index 000000000..ba86e0a1f --- /dev/null +++ b/src/duckstation-qt/vulkanhostdisplay.cpp @@ -0,0 +1,168 @@ +#include "vulkanhostdisplay.h" +#include "common/assert.h" +#include "common/log.h" +#include "imgui.h" +#include "qtdisplaywidget.h" +Log_SetChannel(VulkanHostDisplay); + +VulkanHostDisplay::VulkanHostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {} + +VulkanHostDisplay::~VulkanHostDisplay() = default; + +HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const +{ + return m_vulkan_display.GetRenderAPI(); +} + +void* VulkanHostDisplay::GetRenderDevice() const +{ + return m_vulkan_display.GetRenderDevice(); +} + +void* VulkanHostDisplay::GetRenderContext() const +{ + return m_vulkan_display.GetRenderContext(); +} + +std::unique_ptr VulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data, + u32 initial_data_stride, bool dynamic) +{ + return m_vulkan_display.CreateTexture(width, height, initial_data, initial_data_stride, dynamic); +} + +void VulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, + const void* texture_data, u32 texture_data_stride) +{ + m_vulkan_display.UpdateTexture(texture, x, y, width, height, texture_data, texture_data_stride); +} + +bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data, + u32 out_data_stride) +{ + return m_vulkan_display.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride); +} + +void VulkanHostDisplay::SetVSync(bool enabled) +{ + m_vulkan_display.SetVSync(enabled); +} + +bool VulkanHostDisplay::hasDeviceContext() const +{ + return m_vulkan_display.HasContext(); +} + +bool VulkanHostDisplay::createDeviceContext(bool debug_device) +{ + std::optional wi = getWindowInfo(); + if (!wi || !m_vulkan_display.CreateContextAndSwapChain(wi.value(), debug_device)) + return false; + + m_window_width = static_cast(m_vulkan_display.GetSwapChainWidth()); + m_window_height = static_cast(m_vulkan_display.GetSwapChainHeight()); + return true; +} + +bool VulkanHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) +{ + m_vulkan_display.CreateShaderCache(shader_cache_directory, debug_device); + + return QtHostDisplay::initializeDeviceContext(shader_cache_directory, debug_device); +} + +bool VulkanHostDisplay::activateDeviceContext() +{ + return true; +} + +void VulkanHostDisplay::deactivateDeviceContext() {} + +void VulkanHostDisplay::destroyDeviceContext() +{ + QtHostDisplay::destroyDeviceContext(); + m_vulkan_display.DestroyShaderCache(); + m_vulkan_display.DestroySwapChain(); + m_vulkan_display.DestroyContext(); +} + +bool VulkanHostDisplay::recreateSurface() +{ + std::optional wi = getWindowInfo(); + if (!wi.has_value()) + return false; + + if (!m_vulkan_display.RecreateSwapChain(wi.value())) + return false; + + m_window_width = static_cast(m_vulkan_display.GetSwapChainWidth()); + m_window_height = static_cast(m_vulkan_display.GetSwapChainHeight()); + return true; +} + +void VulkanHostDisplay::destroySurface() +{ + m_vulkan_display.DestroySwapChain(); +} + +void VulkanHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height) +{ + QtHostDisplay::WindowResized(new_window_width, new_window_height); + + m_vulkan_display.ResizeSwapChain(static_cast(new_window_width), static_cast(new_window_height)); + m_window_width = static_cast(m_vulkan_display.GetSwapChainWidth()); + m_window_height = static_cast(m_vulkan_display.GetSwapChainHeight()); +} + +bool VulkanHostDisplay::createDeviceResources() +{ + if (!QtHostDisplay::createDeviceResources()) + return false; + + return m_vulkan_display.CreateResources(); +} + +void VulkanHostDisplay::destroyDeviceResources() +{ + QtHostDisplay::destroyDeviceResources(); + m_vulkan_display.DestroyResources(); +} + +bool VulkanHostDisplay::createImGuiContext() +{ + if (!QtHostDisplay::createImGuiContext() || !m_vulkan_display.CreateImGuiContext()) + return false; + + ImGui::NewFrame(); + return true; +} + +void VulkanHostDisplay::destroyImGuiContext() +{ + m_vulkan_display.DestroyImGuiContext(); + QtHostDisplay::destroyImGuiContext(); +} + +void VulkanHostDisplay::Render() +{ + if (!m_vulkan_display.HasSwapChain() || !m_vulkan_display.BeginRender()) + return; + + if (HasDisplayTexture()) + { + const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin); + m_vulkan_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_vulkan_display.RenderImGui(); + + if (HasSoftwareCursor()) + { + const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect(); + m_vulkan_display.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get()); + } + + m_vulkan_display.EndRenderAndPresent(); +} diff --git a/src/duckstation-qt/vulkanhostdisplay.h b/src/duckstation-qt/vulkanhostdisplay.h new file mode 100644 index 000000000..dcd496cab --- /dev/null +++ b/src/duckstation-qt/vulkanhostdisplay.h @@ -0,0 +1,49 @@ +#pragma once +#include "common/window_info.h" +#include "core/host_display.h" +#include "qtdisplaywidget.h" +#include "qthostdisplay.h" +#include "frontend-common/vulkan_host_display.h" +#include + +class QtHostInterface; + +class VulkanHostDisplay final : public QtHostDisplay +{ +public: + VulkanHostDisplay(QtHostInterface* host_interface); + ~VulkanHostDisplay(); + + bool hasDeviceContext() const override; + bool createDeviceContext(bool debug_device) override; + bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override; + bool activateDeviceContext() override; + void deactivateDeviceContext() override; + void destroyDeviceContext() override; + bool recreateSurface() override; + void destroySurface(); + + 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* initial_data, + u32 initial_data_stride, bool dynamic) override; + void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, + u32 texture_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 createImGuiContext() override; + void destroyImGuiContext() override; + bool createDeviceResources() override; + void destroyDeviceResources() override; + + FrontendCommon::VulkanHostDisplay m_vulkan_display; +};