Qt: Support Vulkan

This commit is contained in:
Connor McLaughlin 2020-06-19 00:18:53 +10:00
parent d168947ae4
commit 49a9f01327
13 changed files with 350 additions and 95 deletions

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -59,8 +59,10 @@
<ClCompile Include="qtsettingsinterface.cpp" />
<ClCompile Include="qtutils.cpp" />
<ClCompile Include="settingsdialog.cpp" />
<ClCompile Include="vulkanhostdisplay.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="vulkanhostdisplay.h" />
<QtMoc Include="aboutdialog.h" />
<QtMoc Include="audiosettingswidget.h" />
<QtMoc Include="controllersettingswidget.h" />
@ -97,6 +99,9 @@
<ProjectReference Include="..\..\dep\minizip\minizip.vcxproj">
<Project>{8bda439c-6358-45fb-9994-2ff083babe06}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\vulkan-loader\vulkan-loader.vcxproj">
<Project>{9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
</ProjectReference>
@ -335,7 +340,7 @@
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -356,7 +361,7 @@
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -377,7 +382,7 @@
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
@ -400,7 +405,7 @@
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
@ -422,7 +427,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -445,7 +450,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -469,7 +474,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -492,7 +497,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -512,4 +517,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\dep\msvc\vsprops\QtCompile.targets" />
</ImportGroup>
</Project>
</Project>

View file

@ -16,7 +16,6 @@
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_settingsdialog.cpp" />
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
<ClCompile Include="gpusettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gpusettingswidget.cpp" />
<ClCompile Include="inputbindingwidgets.cpp" />
@ -39,6 +38,13 @@
<ClCompile Include="gamepropertiesdialog.cpp" />
<ClCompile Include="$(IntDir)moc_gamepropertiesdialog.cpp" />
<ClCompile Include="controllersettingswidget.cpp" />
<ClCompile Include="aboutdialog.cpp" />
<ClCompile Include="memorycardsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_aboutdialog.cpp" />
<ClCompile Include="$(IntDir)moc_controllersettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" />
<ClCompile Include="$(IntDir)qrc_icons.cpp" />
<ClCompile Include="vulkanhostdisplay.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="qtsettingsinterface.h" />
@ -48,6 +54,7 @@
<ClInclude Include="d3d11hostdisplay.h" />
<ClInclude Include="openglhostdisplay.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="vulkanhostdisplay.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="resources">
@ -74,6 +81,8 @@
<QtMoc Include="advancedsettingswidget.h" />
<QtMoc Include="gamepropertiesdialog.h" />
<QtMoc Include="controllersettingswidget.h" />
<QtMoc Include="aboutdialog.h" />
<QtMoc Include="memorycardsettingswidget.h" />
</ItemGroup>
<ItemGroup>
<QtUi Include="consolesettingswidget.ui" />
@ -85,6 +94,7 @@
<QtUi Include="generalsettingswidget.ui" />
<QtUi Include="advancedsettingswidget.ui" />
<QtUi Include="gamepropertiesdialog.ui" />
<QtUi Include="aboutdialog.ui" />
</ItemGroup>
<ItemGroup>
<Natvis Include="qt5.natvis" />
@ -95,4 +105,4 @@
<ItemGroup>
<Image Include="duckstation-qt.ico" />
</ItemGroup>
</Project>
</Project>

View file

@ -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();

View file

@ -4,15 +4,10 @@
#include "imgui.h"
#include "qtdisplaywidget.h"
#include "qthostinterface.h"
#include <QtCore/QDebug>
#include <QtGui/QGuiApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QWindow>
#include <array>
#include <imgui_impl_opengl3.h>
#if !defined(WIN32) && !defined(APPLE)
#include <qpa/qplatformnativeinterface.h>
#endif
#include <tuple>
Log_SetChannel(OpenGLHostDisplay);
@ -193,49 +188,16 @@ bool OpenGLHostDisplay::hasDeviceContext() const
return static_cast<bool>(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<void*>(m_widget->winId());
#elif defined(__APPLE__)
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = reinterpret_cast<void*>(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<void*>(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<WindowInfo> 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<WindowInfo> wi = getWindowInfo();
if (!wi.has_value() || !m_gl_context->ChangeSurface(wi.value()))
return false;
}
return true;
}

View file

@ -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;

View file

@ -4,7 +4,12 @@
#include "imgui.h"
#include "qtdisplaywidget.h"
#include "qthostinterface.h"
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
#include <cmath>
#if !defined(WIN32) && !defined(APPLE)
#include <qpa/qplatformnativeinterface.h>
#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<float>(m_window_width);
io.DisplaySize.y = static_cast<float>(m_window_height);
}
std::optional<WindowInfo> 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<void*>(m_widget->winId());
#elif defined(__APPLE__)
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = reinterpret_cast<void*>(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<void*>(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;
}

View file

@ -1,6 +1,9 @@
#pragma once
#include "common/types.h"
#include "common/window_info.h"
#include "core/host_display.h"
#include <optional>
#include <string_view>
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<WindowInfo> getWindowInfo() const;
QtHostInterface* m_host_interface;
QtDisplayWidget* m_widget = nullptr;
};

View file

@ -15,6 +15,7 @@
#include "qtprogresscallback.h"
#include "qtsettingsinterface.h"
#include "qtutils.h"
#include "vulkanhostdisplay.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
@ -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();
}

View file

@ -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<HostDisplayTexture> 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<WindowInfo> wi = getWindowInfo();
if (!wi || !m_vulkan_display.CreateContextAndSwapChain(wi.value(), debug_device))
return false;
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
m_window_height = static_cast<s32>(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<WindowInfo> wi = getWindowInfo();
if (!wi.has_value())
return false;
if (!m_vulkan_display.RecreateSwapChain(wi.value()))
return false;
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
m_window_height = static_cast<s32>(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<u32>(new_window_width), static_cast<u32>(new_window_height));
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
m_window_height = static_cast<s32>(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();
}

View file

@ -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 <memory>
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<HostDisplayTexture> 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;
};