From 2480624cbe87824e0049abfa3ef1b05e86031ef8 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 12 Mar 2020 13:53:51 +1000 Subject: [PATCH] Qt: Replace QWindow for display with QWidget base Not as elegant, but it solves the input focus issue. --- src/duckstation-qt/CMakeLists.txt | 12 +- ...splaywindow.cpp => d3d11displaywidget.cpp} | 269 ++++++++++-------- ...11displaywindow.h => d3d11displaywidget.h} | 24 +- src/duckstation-qt/duckstation-qt.vcxproj | 18 +- .../duckstation-qt.vcxproj.filters | 18 +- src/duckstation-qt/mainwindow.cpp | 9 +- src/duckstation-qt/mainwindow.h | 3 +- ...playwindow.cpp => opengldisplaywidget.cpp} | 112 ++++---- ...ldisplaywindow.h => opengldisplaywidget.h} | 18 +- src/duckstation-qt/qtdisplaywidget.cpp | 145 ++++++++++ .../{qtdisplaywindow.h => qtdisplaywidget.h} | 21 +- src/duckstation-qt/qtdisplaywindow.cpp | 107 ------- src/duckstation-qt/qthostinterface.cpp | 45 +-- src/duckstation-qt/qthostinterface.h | 9 +- src/duckstation-sdl/opengl_host_display.cpp | 14 +- 15 files changed, 449 insertions(+), 375 deletions(-) rename src/duckstation-qt/{d3d11displaywindow.cpp => d3d11displaywidget.cpp} (71%) rename src/duckstation-qt/{d3d11displaywindow.h => d3d11displaywidget.h} (77%) rename src/duckstation-qt/{opengldisplaywindow.cpp => opengldisplaywidget.cpp} (76%) rename src/duckstation-qt/{opengldisplaywindow.h => opengldisplaywidget.h} (77%) create mode 100644 src/duckstation-qt/qtdisplaywidget.cpp rename src/duckstation-qt/{qtdisplaywindow.h => qtdisplaywidget.h} (55%) delete mode 100644 src/duckstation-qt/qtdisplaywindow.cpp diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index f17787d7f..84920c0ed 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -26,12 +26,12 @@ add_executable(duckstation-qt mainwindow.cpp mainwindow.h mainwindow.ui - opengldisplaywindow.cpp - opengldisplaywindow.h + opengldisplaywidget.cpp + opengldisplaywidget.h portsettingswidget.cpp portsettingswidget.h - qtdisplaywindow.cpp - qtdisplaywindow.h + qtdisplaywidget.cpp + qtdisplaywidget.h qthostinterface.cpp qthostinterface.h qtsettingsinterface.cpp @@ -47,8 +47,8 @@ target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui g if(WIN32) target_sources(duckstation-qt PRIVATE - d3d11displaywindow.cpp - d3d11displaywindow.h + d3d11displaywidget.cpp + d3d11displaywidget.h ) target_link_libraries(duckstation PRIVATE d3d11.lib dxgi.lib) endif() diff --git a/src/duckstation-qt/d3d11displaywindow.cpp b/src/duckstation-qt/d3d11displaywidget.cpp similarity index 71% rename from src/duckstation-qt/d3d11displaywindow.cpp rename to src/duckstation-qt/d3d11displaywidget.cpp index 87c397d87..68667cffb 100644 --- a/src/duckstation-qt/d3d11displaywindow.cpp +++ b/src/duckstation-qt/d3d11displaywidget.cpp @@ -1,4 +1,4 @@ -#include "d3d11displaywindow.h" +#include "d3d11displaywidget.h" #include "common/assert.h" #include "common/d3d11/shader_compiler.h" #include "common/log.h" @@ -8,20 +8,20 @@ #include #include #include -Log_SetChannel(D3D11DisplayWindow); +Log_SetChannel(D3D11DisplayWidget); -class D3D11DisplayWindowTexture : public HostDisplayTexture +class D3D11DisplayWidgetTexture : public HostDisplayTexture { public: template using ComPtr = Microsoft::WRL::ComPtr; - D3D11DisplayWindowTexture(ComPtr texture, ComPtr srv, u32 width, + D3D11DisplayWidgetTexture(ComPtr texture, ComPtr srv, u32 width, u32 height, bool dynamic) : m_texture(std::move(texture)), m_srv(std::move(srv)), m_width(width), m_height(height), m_dynamic(dynamic) { } - ~D3D11DisplayWindowTexture() override = default; + ~D3D11DisplayWidgetTexture() override = default; void* GetHandle() const override { return m_srv.Get(); } u32 GetWidth() const override { return m_width; } @@ -31,7 +31,7 @@ public: ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } bool IsDynamic() const { return m_dynamic; } - static std::unique_ptr Create(ID3D11Device* device, u32 width, u32 height, + static std::unique_ptr Create(ID3D11Device* device, u32 width, u32 height, const void* data, u32 data_stride, bool dynamic) { const CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, width, height, 1, 1, D3D11_BIND_SHADER_RESOURCE, @@ -50,7 +50,7 @@ public: if (FAILED(hr)) return {}; - return std::make_unique(std::move(texture), std::move(srv), width, height, dynamic); + return std::make_unique(std::move(texture), std::move(srv), width, height, dynamic); } private: @@ -61,76 +61,58 @@ private: bool m_dynamic; }; -D3D11DisplayWindow::D3D11DisplayWindow(QtHostInterface* host_interface, QWindow* parent) - : QtDisplayWindow(host_interface, parent) +D3D11DisplayWidget::D3D11DisplayWidget(QtHostInterface* host_interface, QWidget* parent) + : QtDisplayWidget(host_interface, parent) { } -D3D11DisplayWindow::~D3D11DisplayWindow() = default; +D3D11DisplayWidget::~D3D11DisplayWidget() = default; -HostDisplay* D3D11DisplayWindow::getHostDisplayInterface() +HostDisplay* D3D11DisplayWidget::getHostDisplayInterface() { return this; } -HostDisplay::RenderAPI D3D11DisplayWindow::GetRenderAPI() const +HostDisplay::RenderAPI D3D11DisplayWidget::GetRenderAPI() const { return HostDisplay::RenderAPI::D3D11; } -void* D3D11DisplayWindow::GetRenderDevice() const +void* D3D11DisplayWidget::GetRenderDevice() const { return m_device.Get(); } -void* D3D11DisplayWindow::GetRenderContext() const +void* D3D11DisplayWidget::GetRenderContext() const { return m_context.Get(); } -void* D3D11DisplayWindow::GetRenderWindow() const +void* D3D11DisplayWidget::GetRenderWindow() const { - return const_cast(static_cast(this)); + return const_cast(static_cast(this)); } -void D3D11DisplayWindow::ChangeRenderWindow(void* new_window) +void D3D11DisplayWidget::ChangeRenderWindow(void* new_window) { Panic("Not supported"); } -void D3D11DisplayWindow::WindowResized(s32 new_window_width, s32 new_window_height) +std::unique_ptr D3D11DisplayWidget::CreateTexture(u32 width, u32 height, const void* initial_data, + u32 initial_data_stride, bool dynamic) { - QtDisplayWindow::WindowResized(new_window_width, new_window_height); - HostDisplay::WindowResized(new_window_width, new_window_height); - - if (!m_swap_chain) - return; - - m_swap_chain_rtv.Reset(); - - HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, - m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); - if (FAILED(hr)) - Log_ErrorPrintf("ResizeBuffers() failed: 0x%08X", hr); - - if (!createSwapChainRTV()) - Panic("Failed to recreate swap chain RTV after resize"); + return D3D11DisplayWidgetTexture::Create(m_device.Get(), width, height, initial_data, initial_data_stride, dynamic); } -std::unique_ptr D3D11DisplayWindow::CreateTexture(u32 width, u32 height, const void* data, - u32 data_stride, bool dynamic) +void D3D11DisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, + const void* texture_data, u32 texture_data_stride) { - return D3D11DisplayWindowTexture::Create(m_device.Get(), width, height, data, data_stride, dynamic); -} - -void D3D11DisplayWindow::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, - const void* data, u32 data_stride) -{ - D3D11DisplayWindowTexture* d3d11_texture = static_cast(texture); + D3D11DisplayWidgetTexture* d3d11_texture = static_cast(texture); if (!d3d11_texture->IsDynamic()) { const CD3D11_BOX dst_box(x, y, 0, x + width, y + height, 1); - m_context->UpdateSubresource(d3d11_texture->GetD3DTexture(), 0, &dst_box, data, data_stride, data_stride * height); + m_context->UpdateSubresource(d3d11_texture->GetD3DTexture(), 0, &dst_box, texture_data, texture_data_stride, + texture_data_stride * height); } else { @@ -140,17 +122,17 @@ void D3D11DisplayWindow::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y Panic("Failed to map dynamic host display texture"); char* dst_ptr = static_cast(sr.pData) + (y * sr.RowPitch) + (x * sizeof(u32)); - const char* src_ptr = static_cast(data); - if (sr.RowPitch == data_stride) + const char* src_ptr = static_cast(texture_data); + if (sr.RowPitch == texture_data_stride) { - std::memcpy(dst_ptr, src_ptr, data_stride * height); + std::memcpy(dst_ptr, src_ptr, texture_data_stride * height); } else { for (u32 row = 0; row < height; row++) { std::memcpy(dst_ptr, src_ptr, width * sizeof(u32)); - src_ptr += data_stride; + src_ptr += texture_data_stride; dst_ptr += sr.RowPitch; } } @@ -159,44 +141,24 @@ void D3D11DisplayWindow::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y } } -void D3D11DisplayWindow::SetVSync(bool enabled) +void D3D11DisplayWidget::SetVSync(bool enabled) { m_vsync = enabled; } -bool D3D11DisplayWindow::hasDeviceContext() const +bool D3D11DisplayWidget::hasDeviceContext() const { return static_cast(m_device); } -bool D3D11DisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_device) +bool D3D11DisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device) { - ComPtr dxgi_factory; - HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(dxgi_factory.GetAddressOf())); - if (FAILED(hr)) - { - Log_ErrorPrintf("Failed to create DXGI factory: 0x%08X", hr); - return false; - } - - m_allow_tearing_supported = false; - ComPtr dxgi_factory5; - hr = dxgi_factory.As(&dxgi_factory5); - if (SUCCEEDED(hr)) - { - BOOL allow_tearing_supported = false; - hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, - sizeof(allow_tearing_supported)); - if (SUCCEEDED(hr)) - m_allow_tearing_supported = (allow_tearing_supported == TRUE); - } - UINT create_flags = 0; if (debug_device) create_flags |= D3D11_CREATE_DEVICE_DEBUG; - hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, nullptr, 0, D3D11_SDK_VERSION, - m_device.GetAddressOf(), nullptr, m_context.GetAddressOf()); + HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, nullptr, 0, + D3D11_SDK_VERSION, m_device.GetAddressOf(), nullptr, m_context.GetAddressOf()); if (FAILED(hr)) { @@ -204,40 +166,6 @@ bool D3D11DisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_ return false; } - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferDesc.Width = m_window_width; - swap_chain_desc.BufferDesc.Height = m_window_height; - swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.BufferCount = 3; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = reinterpret_cast(winId()); - swap_chain_desc.Windowed = TRUE; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - - if (m_allow_tearing_supported) - swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - - hr = dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf()); - if (FAILED(hr)) - { - Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard."); - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swap_chain_desc.Flags = 0; - m_allow_tearing_supported = false; - - hr = dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf()); - if (FAILED(hr)) - { - Log_ErrorPrintf("CreateSwapChain failed: 0x%08X", hr); - return false; - } - } - - hr = dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) - Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed"); - if (debug_device) { ComPtr info; @@ -249,7 +177,46 @@ bool D3D11DisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_ } } - if (!QtDisplayWindow::createDeviceContext(worker_thread, debug_device)) + // we need the specific factory for the device, otherwise MakeWindowAssociation() is flaky. + ComPtr dxgi_device; + ComPtr dxgi_adapter; + if (FAILED(m_device.As(&dxgi_device)) || FAILED(dxgi_device->GetParent(IID_PPV_ARGS(dxgi_adapter.GetAddressOf()))) || + FAILED(dxgi_adapter->GetParent(IID_PPV_ARGS(m_dxgi_factory.GetAddressOf())))) + { + Log_WarningPrint("Failed to get parent adapter/device/factory"); + return false; + } + + DXGI_ADAPTER_DESC adapter_desc; + if (SUCCEEDED(dxgi_adapter->GetDesc(&adapter_desc))) + { + char adapter_name_buffer[128]; + const int name_length = + WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description, static_cast(std::wcslen(adapter_desc.Description)), + adapter_name_buffer, countof(adapter_name_buffer), 0, nullptr); + if (name_length >= 0) + { + adapter_name_buffer[name_length] = 0; + Log_InfoPrintf("D3D Adapter: %s", adapter_name_buffer); + } + } + + m_allow_tearing_supported = false; + ComPtr dxgi_factory5; + hr = m_dxgi_factory.As(&dxgi_factory5); + if (SUCCEEDED(hr)) + { + BOOL allow_tearing_supported = false; + hr = dxgi_factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported, + sizeof(allow_tearing_supported)); + if (SUCCEEDED(hr)) + m_allow_tearing_supported = (allow_tearing_supported == TRUE); + } + + if (!createSwapChain(reinterpret_cast(winId()))) + return false; + + if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device)) { m_swap_chain.Reset(); m_context.Reset(); @@ -259,26 +226,86 @@ bool D3D11DisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_ return true; } -bool D3D11DisplayWindow::initializeDeviceContext(bool debug_device) +bool D3D11DisplayWidget::initializeDeviceContext(bool debug_device) { if (!createSwapChainRTV()) return false; - if (!QtDisplayWindow::initializeDeviceContext(debug_device)) + if (!QtDisplayWidget::initializeDeviceContext(debug_device)) return false; return true; } -void D3D11DisplayWindow::destroyDeviceContext() +void D3D11DisplayWidget::destroyDeviceContext() { - QtDisplayWindow::destroyDeviceContext(); + QtDisplayWidget::destroyDeviceContext(); m_swap_chain.Reset(); m_context.Reset(); m_device.Reset(); } -bool D3D11DisplayWindow::createSwapChainRTV() +bool D3D11DisplayWidget::createSwapChain(HWND hwnd) +{ + HRESULT hr; + + DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; + swap_chain_desc.BufferDesc.Width = m_window_width; + swap_chain_desc.BufferDesc.Height = m_window_height; + swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.BufferCount = 3; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.OutputWindow = hwnd; + swap_chain_desc.Windowed = TRUE; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + + if (m_allow_tearing_supported) + swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + + hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf()); + if (FAILED(hr)) + { + Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard."); + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swap_chain_desc.Flags = 0; + m_allow_tearing_supported = false; + + hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("CreateSwapChain failed: 0x%08X", hr); + return false; + } + } + + hr = m_dxgi_factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(hr)) + Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed"); + + return true; +} + +void D3D11DisplayWidget::windowResized(s32 new_window_width, s32 new_window_height) +{ + QtDisplayWidget::windowResized(new_window_width, new_window_height); + HostDisplay::WindowResized(new_window_width, new_window_height); + + if (!m_swap_chain) + return; + + m_swap_chain_rtv.Reset(); + + HRESULT hr = m_swap_chain->ResizeBuffers(0, new_window_width, new_window_height, DXGI_FORMAT_UNKNOWN, + m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); + if (FAILED(hr)) + Log_ErrorPrintf("ResizeBuffers() failed: 0x%08X", hr); + + if (!createSwapChainRTV()) + Panic("Failed to recreate swap chain RTV after resize"); +} + +bool D3D11DisplayWidget::createSwapChainRTV() { ComPtr backbuffer; HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(backbuffer.GetAddressOf())); @@ -303,7 +330,7 @@ bool D3D11DisplayWindow::createSwapChainRTV() return true; } -bool D3D11DisplayWindow::createDeviceResources() +bool D3D11DisplayWidget::createDeviceResources() { HRESULT hr; @@ -349,9 +376,9 @@ bool D3D11DisplayWindow::createDeviceResources() return true; } -void D3D11DisplayWindow::destroyDeviceResources() +void D3D11DisplayWidget::destroyDeviceResources() { - QtDisplayWindow::destroyDeviceResources(); + QtDisplayWidget::destroyDeviceResources(); m_display_uniform_buffer.Release(); m_swap_chain_rtv.Reset(); @@ -364,9 +391,9 @@ void D3D11DisplayWindow::destroyDeviceResources() m_display_rasterizer_state.Reset(); } -bool D3D11DisplayWindow::createImGuiContext() +bool D3D11DisplayWidget::createImGuiContext() { - if (!QtDisplayWindow::createImGuiContext()) + if (!QtDisplayWidget::createImGuiContext()) return false; if (!ImGui_ImplDX11_Init(m_device.Get(), m_context.Get())) @@ -377,13 +404,13 @@ bool D3D11DisplayWindow::createImGuiContext() return true; } -void D3D11DisplayWindow::destroyImGuiContext() +void D3D11DisplayWidget::destroyImGuiContext() { ImGui_ImplDX11_Shutdown(); - QtDisplayWindow::destroyImGuiContext(); + QtDisplayWidget::destroyImGuiContext(); } -void D3D11DisplayWindow::Render() +void D3D11DisplayWidget::Render() { static constexpr std::array clear_color = {}; m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data()); @@ -403,7 +430,7 @@ void D3D11DisplayWindow::Render() ImGui_ImplDX11_NewFrame(); } -void D3D11DisplayWindow::renderDisplay() +void D3D11DisplayWidget::renderDisplay() { if (!m_display_texture_handle) return; diff --git a/src/duckstation-qt/d3d11displaywindow.h b/src/duckstation-qt/d3d11displaywidget.h similarity index 77% rename from src/duckstation-qt/d3d11displaywindow.h rename to src/duckstation-qt/d3d11displaywidget.h index e960934ea..06b474b82 100644 --- a/src/duckstation-qt/d3d11displaywindow.h +++ b/src/duckstation-qt/d3d11displaywidget.h @@ -1,14 +1,15 @@ #pragma once -#include "common/windows_headers.h" #include "common/d3d11/stream_buffer.h" #include "common/d3d11/texture.h" +#include "common/windows_headers.h" #include "core/host_display.h" -#include "qtdisplaywindow.h" +#include "qtdisplaywidget.h" #include +#include #include #include -class D3D11DisplayWindow final : public QtDisplayWindow, private HostDisplay +class D3D11DisplayWidget final : public QtDisplayWidget, private HostDisplay { Q_OBJECT @@ -16,8 +17,8 @@ public: template using ComPtr = Microsoft::WRL::ComPtr; - D3D11DisplayWindow(QtHostInterface* host_interface, QWindow* parent); - ~D3D11DisplayWindow(); + D3D11DisplayWidget(QtHostInterface* host_interface, QWidget* parent); + ~D3D11DisplayWidget(); HostDisplay* getHostDisplayInterface() override; @@ -32,12 +33,12 @@ public: void* GetRenderWindow() const override; void ChangeRenderWindow(void* new_window) override; - void WindowResized(s32 new_window_width, s32 new_window_height) 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) override; - void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, - u32 data_stride) 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; void SetVSync(bool enabled) override; @@ -51,10 +52,13 @@ private: bool createDeviceResources() override; void destroyDeviceResources() override; + bool createSwapChain(HWND hwnd); bool createSwapChainRTV(); void renderDisplay(); + ComPtr m_dxgi_factory; + ComPtr m_device; ComPtr m_context; ComPtr m_swap_chain; diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 6dc74e363..e2cd6e290 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -37,16 +37,16 @@ - + - + - + @@ -56,17 +56,17 @@ - + - + - + @@ -117,16 +117,16 @@ - + - + - + diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index dbda330ba..9f5f7c2b8 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -6,7 +6,6 @@ - @@ -15,24 +14,25 @@ - - - - - + + + + + + @@ -52,16 +52,16 @@ - - - + + + diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index b64428a3b..48ab401ef 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -5,7 +5,7 @@ #include "core/system.h" #include "gamelistsettingswidget.h" #include "gamelistwidget.h" -#include "qtdisplaywindow.h" +#include "qtdisplaywidget.h" #include "qthostinterface.h" #include "qtsettingsinterface.h" #include "settingsdialog.h" @@ -57,10 +57,7 @@ void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_devi { DebugAssert(!m_display_widget); - QtDisplayWindow* display_window = m_host_interface->createDisplayWindow(); - DebugAssert(display_window); - - m_display_widget = QWidget::createWindowContainer(display_window, m_ui.mainContainer); + m_display_widget = m_host_interface->createDisplayWidget(); DebugAssert(m_display_widget); m_display_widget->setFocusPolicy(Qt::StrongFocus); @@ -70,7 +67,7 @@ void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_devi switchToEmulationView(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - display_window->createDeviceContext(worker_thread, use_debug_device); + m_display_widget->createDeviceContext(worker_thread, use_debug_device); } void MainWindow::destroyDisplayWindow() diff --git a/src/duckstation-qt/mainwindow.h b/src/duckstation-qt/mainwindow.h index 233a9cec9..b1a1cf4a4 100644 --- a/src/duckstation-qt/mainwindow.h +++ b/src/duckstation-qt/mainwindow.h @@ -12,6 +12,7 @@ class QThread; class GameListWidget; class QtHostInterface; +class QtDisplayWidget; struct GameListEntry; @@ -71,7 +72,7 @@ private: QtHostInterface* m_host_interface = nullptr; GameListWidget* m_game_list_widget = nullptr; - QWidget* m_display_widget = nullptr; + QtDisplayWidget* m_display_widget = nullptr; QLabel* m_status_speed_widget = nullptr; QLabel* m_status_fps_widget = nullptr; diff --git a/src/duckstation-qt/opengldisplaywindow.cpp b/src/duckstation-qt/opengldisplaywidget.cpp similarity index 76% rename from src/duckstation-qt/opengldisplaywindow.cpp rename to src/duckstation-qt/opengldisplaywidget.cpp index e83bec793..18b12770f 100644 --- a/src/duckstation-qt/opengldisplaywindow.cpp +++ b/src/duckstation-qt/opengldisplaywidget.cpp @@ -1,13 +1,14 @@ -#include "opengldisplaywindow.h" +#include "opengldisplaywidget.h" #include "common/assert.h" #include "common/log.h" #include "imgui.h" #include "qthostinterface.h" #include +#include #include #include #include -Log_SetChannel(OpenGLDisplayWindow); +Log_SetChannel(OpenGLDisplayWidget); static thread_local QOpenGLContext* s_thread_gl_context; @@ -56,11 +57,11 @@ static void SetSwapInterval(QWindow* window, QOpenGLContext* context, int interv #endif } -class OpenGLHostDisplayTexture : public HostDisplayTexture +class OpenGLDisplayWidgetTexture : public HostDisplayTexture { public: - OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} - ~OpenGLHostDisplayTexture() override { glDeleteTextures(1, &m_id); } + OpenGLDisplayWidgetTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} + ~OpenGLDisplayWidgetTexture() override { glDeleteTextures(1, &m_id); } void* GetHandle() const override { return reinterpret_cast(static_cast(m_id)); } u32 GetWidth() const override { return m_width; } @@ -68,8 +69,8 @@ public: GLuint GetGLID() const { return m_id; } - static std::unique_ptr Create(u32 width, u32 height, const void* initial_data, - u32 initial_data_stride) + static std::unique_ptr Create(u32 width, u32 height, const void* initial_data, + u32 initial_data_stride) { GLuint id; glGenTextures(1, &id); @@ -87,7 +88,7 @@ public: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, id); - return std::make_unique(id, width, height); + return std::make_unique(id, width, height); } private: @@ -96,82 +97,84 @@ private: u32 m_height; }; -OpenGLDisplayWindow::OpenGLDisplayWindow(QtHostInterface* host_interface, QWindow* parent) - : QtDisplayWindow(host_interface, parent) +OpenGLDisplayWidget::OpenGLDisplayWidget(QtHostInterface* host_interface, QWidget* parent) + : QtDisplayWidget(host_interface, parent) { - setSurfaceType(QWindow::OpenGLSurface); + QWindow* native_window = windowHandle(); + Assert(native_window); + native_window->setSurfaceType(QWindow::OpenGLSurface); } -OpenGLDisplayWindow::~OpenGLDisplayWindow() = default; +OpenGLDisplayWidget::~OpenGLDisplayWidget() = default; -HostDisplay* OpenGLDisplayWindow::getHostDisplayInterface() +HostDisplay* OpenGLDisplayWidget::getHostDisplayInterface() { return this; } -HostDisplay::RenderAPI OpenGLDisplayWindow::GetRenderAPI() const +HostDisplay::RenderAPI OpenGLDisplayWidget::GetRenderAPI() const { return m_gl_context->isOpenGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL; } -void* OpenGLDisplayWindow::GetRenderDevice() const +void* OpenGLDisplayWidget::GetRenderDevice() const { return nullptr; } -void* OpenGLDisplayWindow::GetRenderContext() const +void* OpenGLDisplayWidget::GetRenderContext() const { return m_gl_context.get(); } -void* OpenGLDisplayWindow::GetRenderWindow() const +void* OpenGLDisplayWidget::GetRenderWindow() const { - return const_cast(static_cast(this)); + return const_cast(static_cast(this)); } -void OpenGLDisplayWindow::ChangeRenderWindow(void* new_window) +void OpenGLDisplayWidget::ChangeRenderWindow(void* new_window) { Panic("Not implemented"); } -void OpenGLDisplayWindow::WindowResized(s32 new_window_width, s32 new_window_height) +void OpenGLDisplayWidget::windowResized(s32 new_window_width, s32 new_window_height) { - QtDisplayWindow::WindowResized(new_window_width, new_window_height); + QtDisplayWidget::windowResized(new_window_width, new_window_height); HostDisplay::WindowResized(new_window_width, new_window_height); } -std::unique_ptr OpenGLDisplayWindow::CreateTexture(u32 width, u32 height, const void* data, - u32 data_stride, bool dynamic) +std::unique_ptr OpenGLDisplayWidget::CreateTexture(u32 width, u32 height, const void* initial_data, + u32 initial_data_stride, bool dynamic) { - return OpenGLHostDisplayTexture::Create(width, height, data, data_stride); + return OpenGLDisplayWidgetTexture::Create(width, height, initial_data, initial_data_stride); } -void OpenGLDisplayWindow::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, - const void* data, u32 data_stride) +void OpenGLDisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, + const void* texture_data, u32 texture_data_stride) { - OpenGLHostDisplayTexture* tex = static_cast(texture); - Assert(data_stride == (width * sizeof(u32))); + OpenGLDisplayWidgetTexture* tex = static_cast(texture); + Assert(texture_data_stride == (width * sizeof(u32))); GLint old_texture_binding = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding); glBindTexture(GL_TEXTURE_2D, tex->GetGLID()); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, texture_data); glBindTexture(GL_TEXTURE_2D, old_texture_binding); } -void OpenGLDisplayWindow::SetVSync(bool enabled) +void OpenGLDisplayWidget::SetVSync(bool enabled) { // Window framebuffer has to be bound to call SetSwapInterval. GLint current_fbo = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - SetSwapInterval(this, m_gl_context.get(), enabled ? 1 : 0); + SetSwapInterval(windowHandle(), m_gl_context.get(), enabled ? 1 : 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo); } -const char* OpenGLDisplayWindow::GetGLSLVersionString() const +const char* OpenGLDisplayWidget::GetGLSLVersionString() const { if (m_gl_context->isOpenGLES()) { @@ -189,7 +192,7 @@ const char* OpenGLDisplayWindow::GetGLSLVersionString() const } } -std::string OpenGLDisplayWindow::GetGLSLVersionHeader() const +std::string OpenGLDisplayWidget::GetGLSLVersionHeader() const { std::string header = GetGLSLVersionString(); header += "\n\n"; @@ -222,12 +225,12 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen } } -bool OpenGLDisplayWindow::hasDeviceContext() const +bool OpenGLDisplayWidget::hasDeviceContext() const { return static_cast(m_gl_context); } -bool OpenGLDisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_device) +bool OpenGLDisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device) { m_gl_context = std::make_unique(); @@ -236,7 +239,7 @@ bool OpenGLDisplayWindow::createDeviceContext(QThread* worker_thread, bool debug {{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}}; static constexpr std::array, 4> es_versions_to_try = {{{3, 2}, {3, 1}, {3, 0}}}; - QSurfaceFormat surface_format = requestedFormat(); + QSurfaceFormat surface_format; // = requestedFormat(); surface_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); surface_format.setSwapInterval(0); surface_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -280,14 +283,14 @@ bool OpenGLDisplayWindow::createDeviceContext(QThread* worker_thread, bool debug Log_InfoPrintf("Got a %s %d.%d context", (m_gl_context->isOpenGLES() ? "OpenGL ES" : "desktop OpenGL"), surface_format.majorVersion(), surface_format.minorVersion()); - if (!m_gl_context->makeCurrent(this)) + if (!m_gl_context->makeCurrent(windowHandle())) { Log_ErrorPrintf("Failed to make GL context current on UI thread"); m_gl_context.reset(); return false; } - if (!QtDisplayWindow::createDeviceContext(worker_thread, debug_device)) + if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device)) { m_gl_context->doneCurrent(); m_gl_context.reset(); @@ -299,9 +302,9 @@ bool OpenGLDisplayWindow::createDeviceContext(QThread* worker_thread, bool debug return true; } -bool OpenGLDisplayWindow::initializeDeviceContext(bool debug_device) +bool OpenGLDisplayWidget::initializeDeviceContext(bool debug_device) { - if (!m_gl_context->makeCurrent(this)) + if (!m_gl_context->makeCurrent(windowHandle())) return false; s_thread_gl_context = m_gl_context.get(); @@ -324,7 +327,7 @@ bool OpenGLDisplayWindow::initializeDeviceContext(bool debug_device) glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); } - if (!QtDisplayWindow::initializeDeviceContext(debug_device)) + if (!QtDisplayWidget::initializeDeviceContext(debug_device)) { s_thread_gl_context = nullptr; m_gl_context->doneCurrent(); @@ -334,20 +337,20 @@ bool OpenGLDisplayWindow::initializeDeviceContext(bool debug_device) return true; } -void OpenGLDisplayWindow::destroyDeviceContext() +void OpenGLDisplayWidget::destroyDeviceContext() { Assert(m_gl_context && s_thread_gl_context == m_gl_context.get()); - QtDisplayWindow::destroyDeviceContext(); + QtDisplayWidget::destroyDeviceContext(); s_thread_gl_context = nullptr; m_gl_context->doneCurrent(); m_gl_context.reset(); } -bool OpenGLDisplayWindow::createImGuiContext() +bool OpenGLDisplayWidget::createImGuiContext() { - if (!QtDisplayWindow::createImGuiContext()) + if (!QtDisplayWidget::createImGuiContext()) return false; if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString())) @@ -358,14 +361,14 @@ bool OpenGLDisplayWindow::createImGuiContext() return true; } -void OpenGLDisplayWindow::destroyImGuiContext() +void OpenGLDisplayWidget::destroyImGuiContext() { ImGui_ImplOpenGL3_Shutdown(); - QtDisplayWindow::destroyImGuiContext(); + QtDisplayWidget::destroyImGuiContext(); } -bool OpenGLDisplayWindow::createDeviceResources() +bool OpenGLDisplayWidget::createDeviceResources() { static constexpr char fullscreen_quad_vertex_shader[] = R"( uniform vec4 u_src_rect; @@ -425,9 +428,9 @@ void main() return true; } -void OpenGLDisplayWindow::destroyDeviceResources() +void OpenGLDisplayWidget::destroyDeviceResources() { - QtDisplayWindow::destroyDeviceResources(); + QtDisplayWidget::destroyDeviceResources(); if (m_display_vao != 0) glDeleteVertexArrays(1, &m_display_vao); @@ -439,7 +442,7 @@ void OpenGLDisplayWindow::destroyDeviceResources() m_display_program.Destroy(); } -void OpenGLDisplayWindow::Render() +void OpenGLDisplayWidget::Render() { glDisable(GL_SCISSOR_TEST); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); @@ -451,8 +454,9 @@ void OpenGLDisplayWindow::Render() ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - m_gl_context->makeCurrent(this); - m_gl_context->swapBuffers(this); + QWindow* window_handle = windowHandle(); + m_gl_context->makeCurrent(window_handle); + m_gl_context->swapBuffers(window_handle); ImGui::NewFrame(); ImGui_ImplOpenGL3_NewFrame(); @@ -460,7 +464,7 @@ void OpenGLDisplayWindow::Render() GL::Program::ResetLastProgram(); } -void OpenGLDisplayWindow::renderDisplay() +void OpenGLDisplayWidget::renderDisplay() { if (!m_display_texture_handle) return; diff --git a/src/duckstation-qt/opengldisplaywindow.h b/src/duckstation-qt/opengldisplaywidget.h similarity index 77% rename from src/duckstation-qt/opengldisplaywindow.h rename to src/duckstation-qt/opengldisplaywidget.h index 225ca0f33..dbee48124 100644 --- a/src/duckstation-qt/opengldisplaywindow.h +++ b/src/duckstation-qt/opengldisplaywidget.h @@ -11,19 +11,19 @@ #include "common/gl/program.h" #include "common/gl/texture.h" #include "core/host_display.h" -#include "qtdisplaywindow.h" +#include "qtdisplaywidget.h" #include #include class QtHostInterface; -class OpenGLDisplayWindow final : public QtDisplayWindow, public HostDisplay +class OpenGLDisplayWidget final : public QtDisplayWidget, public HostDisplay { Q_OBJECT public: - OpenGLDisplayWindow(QtHostInterface* host_interface, QWindow* parent); - ~OpenGLDisplayWindow(); + OpenGLDisplayWidget(QtHostInterface* host_interface, QWidget* parent); + ~OpenGLDisplayWidget(); HostDisplay* getHostDisplayInterface() override; @@ -38,12 +38,12 @@ public: void* GetRenderWindow() const override; void ChangeRenderWindow(void* new_window) override; - void WindowResized(s32 new_window_width, s32 new_window_height) 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) override; - void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, - u32 data_stride) 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; void SetVSync(bool enabled) override; diff --git a/src/duckstation-qt/qtdisplaywidget.cpp b/src/duckstation-qt/qtdisplaywidget.cpp new file mode 100644 index 000000000..e23434a11 --- /dev/null +++ b/src/duckstation-qt/qtdisplaywidget.cpp @@ -0,0 +1,145 @@ +#include "qtdisplaywidget.h" +#include "imgui.h" +#include "qthostinterface.h" +#include "qtutils.h" +#include +#include +#include +#include +#include + +QtDisplayWidget::QtDisplayWidget(QtHostInterface* host_interface, QWidget* parent) + : QWidget(parent), m_host_interface(host_interface) +{ + // We want a native window for both D3D and OpenGL. + setAttribute(Qt::WA_NativeWindow, true); + setAttribute(Qt::WA_PaintOnScreen, true); +} + +QtDisplayWidget::~QtDisplayWidget() = default; + +HostDisplay* QtDisplayWidget::getHostDisplayInterface() +{ + return nullptr; +} + +bool QtDisplayWidget::hasDeviceContext() const +{ + return true; +} + +bool QtDisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device) +{ + return true; +} + +bool QtDisplayWidget::initializeDeviceContext(bool debug_device) +{ + if (!createImGuiContext() || !createDeviceResources()) + return false; + + return true; +} + +void QtDisplayWidget::destroyDeviceContext() +{ + destroyImGuiContext(); + destroyDeviceResources(); +} + +qreal QtDisplayWidget::getDevicePixelRatioFromScreen() const +{ + QScreen* screen_for_ratio; +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + screen_for_ratio = windowHandle()->screen(); +#else + screen_for_ratio = screen(); +#endif + if (!screen_for_ratio) + screen_for_ratio = QGuiApplication::primaryScreen(); + + return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast(1); +} + +int QtDisplayWidget::getScaledWindowWidth() const +{ + return static_cast(std::ceil(static_cast(width()) * getDevicePixelRatioFromScreen())); +} + +int QtDisplayWidget::getScaledWindowHeight() const +{ + return static_cast(std::ceil(static_cast(height()) * getDevicePixelRatioFromScreen())); +} + +bool QtDisplayWidget::createImGuiContext() +{ + ImGui::CreateContext(); + + auto& io = ImGui::GetIO(); + io.IniFilename = nullptr; + io.DisplaySize.x = static_cast(getScaledWindowWidth()); + io.DisplaySize.y = static_cast(getScaledWindowHeight()); + + const float framebuffer_scale = static_cast(getDevicePixelRatioFromScreen()); + io.DisplayFramebufferScale.x = framebuffer_scale; + io.DisplayFramebufferScale.y = framebuffer_scale; + io.FontGlobalScale = framebuffer_scale; + ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); + + return true; +} + +void QtDisplayWidget::destroyImGuiContext() +{ + ImGui::DestroyContext(); +} + +bool QtDisplayWidget::createDeviceResources() +{ + return true; +} + +void QtDisplayWidget::destroyDeviceResources() {} + +void QtDisplayWidget::windowResized(s32 new_window_width, s32 new_window_height) +{ + // imgui may not have been initialized yet + if (!ImGui::GetCurrentContext()) + return; + + auto& io = ImGui::GetIO(); + io.DisplaySize.x = static_cast(new_window_width); + io.DisplaySize.y = static_cast(new_window_height); +} + +QPaintEngine* QtDisplayWidget::paintEngine() const +{ + return nullptr; +} + +bool QtDisplayWidget::event(QEvent* event) +{ + switch (event->type()) + { + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + QKeyEvent* key_event = static_cast(event); + if (!key_event->isAutoRepeat()) + m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(key_event), event->type() == QEvent::KeyPress); + + return true; + } + + case QEvent::Resize: + { + QWidget::event(event); + + emit windowResizedEvent(getScaledWindowWidth(), getScaledWindowHeight()); + return true; + } + + default: + return QWidget::event(event); + } +} diff --git a/src/duckstation-qt/qtdisplaywindow.h b/src/duckstation-qt/qtdisplaywidget.h similarity index 55% rename from src/duckstation-qt/qtdisplaywindow.h rename to src/duckstation-qt/qtdisplaywidget.h index 9162b3031..f3f9a80f1 100644 --- a/src/duckstation-qt/qtdisplaywindow.h +++ b/src/duckstation-qt/qtdisplaywidget.h @@ -1,6 +1,6 @@ #pragma once -#include #include "common/types.h" +#include class QKeyEvent; class QResizeEvent; @@ -9,13 +9,13 @@ class HostDisplay; class QtHostInterface; -class QtDisplayWindow : public QWindow +class QtDisplayWidget : public QWidget { Q_OBJECT public: - QtDisplayWindow(QtHostInterface* host_interface, QWindow* parent); - virtual ~QtDisplayWindow(); + QtDisplayWidget(QtHostInterface* host_interface, QWidget* parent); + virtual ~QtDisplayWidget(); virtual HostDisplay* getHostDisplayInterface(); @@ -27,23 +27,24 @@ public: virtual void Render() = 0; // this comes back on the emu thread - virtual void WindowResized(s32 new_window_width, s32 new_window_height); + virtual void windowResized(s32 new_window_width, s32 new_window_height); + + virtual QPaintEngine* paintEngine() const override; Q_SIGNALS: void windowResizedEvent(int width, int height); protected: - int getScaledWindowWidth() const { return static_cast(static_cast(width()) * devicePixelRatio()); } - int getScaledWindowHeight() const { return static_cast(static_cast(height()) * devicePixelRatio()); } + qreal getDevicePixelRatioFromScreen() const; + int getScaledWindowWidth() const; + int getScaledWindowHeight() const; virtual bool createImGuiContext(); virtual void destroyImGuiContext(); virtual bool createDeviceResources(); virtual void destroyDeviceResources(); - virtual void keyPressEvent(QKeyEvent* event) override; - virtual void keyReleaseEvent(QKeyEvent* event) override; - virtual void resizeEvent(QResizeEvent* event) override; + virtual bool event(QEvent* event) override; QtHostInterface* m_host_interface; }; diff --git a/src/duckstation-qt/qtdisplaywindow.cpp b/src/duckstation-qt/qtdisplaywindow.cpp deleted file mode 100644 index 42028a6fd..000000000 --- a/src/duckstation-qt/qtdisplaywindow.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "qtdisplaywindow.h" -#include "imgui.h" -#include "qthostinterface.h" -#include "qtutils.h" -#include - -QtDisplayWindow::QtDisplayWindow(QtHostInterface* host_interface, QWindow* parent) - : QWindow(parent), m_host_interface(host_interface) -{ -} - -QtDisplayWindow::~QtDisplayWindow() = default; - -HostDisplay* QtDisplayWindow::getHostDisplayInterface() -{ - return nullptr; -} - -bool QtDisplayWindow::hasDeviceContext() const -{ - return true; -} - -bool QtDisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_device) -{ - return true; -} - -bool QtDisplayWindow::initializeDeviceContext(bool debug_device) -{ - if (!createImGuiContext() || !createDeviceResources()) - return false; - - return true; -} - -void QtDisplayWindow::destroyDeviceContext() -{ - destroyImGuiContext(); - destroyDeviceResources(); -} - -bool QtDisplayWindow::createImGuiContext() -{ - ImGui::CreateContext(); - - auto& io = ImGui::GetIO(); - io.IniFilename = nullptr; - io.DisplaySize.x = static_cast(getScaledWindowWidth()); - io.DisplaySize.y = static_cast(getScaledWindowHeight()); - - const float framebuffer_scale = static_cast(devicePixelRatio()); - io.DisplayFramebufferScale.x = framebuffer_scale; - io.DisplayFramebufferScale.y = framebuffer_scale; - io.FontGlobalScale = framebuffer_scale; - ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); - - return true; -} - -void QtDisplayWindow::destroyImGuiContext() -{ - ImGui::DestroyContext(); -} - -bool QtDisplayWindow::createDeviceResources() -{ - return true; -} - -void QtDisplayWindow::destroyDeviceResources() {} - -void QtDisplayWindow::WindowResized(s32 new_window_width, s32 new_window_height) -{ - // imgui may not have been initialized yet - if (!ImGui::GetCurrentContext()) - return; - - auto& io = ImGui::GetIO(); - io.DisplaySize.x = static_cast(new_window_width); - io.DisplaySize.y = static_cast(new_window_height); -} - -void QtDisplayWindow::keyPressEvent(QKeyEvent* event) -{ - if (event->isAutoRepeat()) - return; - - m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(event), true); -} - -void QtDisplayWindow::keyReleaseEvent(QKeyEvent* event) -{ - if (event->isAutoRepeat()) - return; - - m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(event), false); -} - -void QtDisplayWindow::resizeEvent(QResizeEvent* event) -{ - QWindow::resizeEvent(event); - - const int width = static_cast(static_cast(event->size().width()) * devicePixelRatio()); - const int height = static_cast(static_cast(event->size().height()) * devicePixelRatio()); - emit windowResizedEvent(width, height); -} diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index f13a6627e..3bfb99216 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -10,6 +10,7 @@ #include "core/system.h" #include "frontend-common/sdl_audio_stream.h" #include "frontend-common/sdl_controller_interface.h" +#include "opengldisplaywidget.h" #include "qtsettingsinterface.h" #include "qtutils.h" #include @@ -23,7 +24,7 @@ Log_SetChannel(QtHostInterface); #ifdef WIN32 -#include "d3d11displaywindow.h" +#include "d3d11displaywidget.h" #endif QtHostInterface::QtHostInterface(QObject* parent) @@ -39,7 +40,7 @@ QtHostInterface::QtHostInterface(QObject* parent) QtHostInterface::~QtHostInterface() { - Assert(!m_display_window); + Assert(!m_display_widget); stopThread(); } @@ -135,20 +136,20 @@ void QtHostInterface::refreshGameList(bool invalidate_cache /* = false */, bool emit gameListRefreshed(); } -QtDisplayWindow* QtHostInterface::createDisplayWindow() +QtDisplayWidget* QtHostInterface::createDisplayWidget() { - Assert(!m_display_window); + Assert(!m_display_widget); #ifdef WIN32 if (m_settings.gpu_renderer == GPURenderer::HardwareOpenGL) - m_display_window = new OpenGLDisplayWindow(this, nullptr); + m_display_widget = new OpenGLDisplayWidget(this, nullptr); else - m_display_window = new D3D11DisplayWindow(this, nullptr); + m_display_widget = new D3D11DisplayWidget(this, nullptr); #else - m_display_window = new OpenGLDisplayWindow(this, nullptr); + m_display_widget = new OpenGLDisplayWidget(this, nullptr); #endif - connect(m_display_window, &QtDisplayWindow::windowResizedEvent, this, &QtHostInterface::onDisplayWindowResized); - return m_display_window; + connect(m_display_widget, &QtDisplayWidget::windowResizedEvent, this, &QtHostInterface::onDisplayWidgetResized); + return m_display_widget; } void QtHostInterface::bootSystem(const SystemBootParameters& params) @@ -188,43 +189,43 @@ void QtHostInterface::handleKeyEvent(int key, bool pressed) HandleHostKeyEvent(key, pressed); } -void QtHostInterface::onDisplayWindowResized(int width, int height) +void QtHostInterface::onDisplayWidgetResized(int width, int height) { // this can be null if it was destroyed and the main thread is late catching up - if (m_display_window) - m_display_window->WindowResized(width, height); + if (m_display_widget) + m_display_widget->windowResized(width, height); } bool QtHostInterface::AcquireHostDisplay() { - DebugAssert(!m_display_window); + DebugAssert(!m_display_widget); emit createDisplayWindowRequested(m_worker_thread, m_settings.gpu_use_debug_device); - if (!m_display_window->hasDeviceContext()) + if (!m_display_widget->hasDeviceContext()) { - m_display_window = nullptr; + m_display_widget = nullptr; emit destroyDisplayWindowRequested(); return false; } - if (!m_display_window->initializeDeviceContext(m_settings.gpu_use_debug_device)) + if (!m_display_widget->initializeDeviceContext(m_settings.gpu_use_debug_device)) { - m_display_window->destroyDeviceContext(); - m_display_window = nullptr; + m_display_widget->destroyDeviceContext(); + m_display_widget = nullptr; emit destroyDisplayWindowRequested(); return false; } - m_display = m_display_window->getHostDisplayInterface(); + m_display = m_display_widget->getHostDisplayInterface(); return true; } void QtHostInterface::ReleaseHostDisplay() { - DebugAssert(m_display_window && m_display == m_display_window->getHostDisplayInterface()); + DebugAssert(m_display_widget && m_display == m_display_widget->getHostDisplayInterface()); m_display = nullptr; - m_display_window->destroyDeviceContext(); - m_display_window = nullptr; + m_display_widget->destroyDeviceContext(); + m_display_widget = nullptr; emit destroyDisplayWindowRequested(); } diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index e4803887e..2d9a8f8fd 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -2,7 +2,6 @@ #include "core/host_interface.h" #include "core/system.h" #include "frontend-common/common_host_interface.h" -#include "opengldisplaywindow.h" #include #include #include @@ -24,6 +23,8 @@ class QTimer; class GameList; +class QtDisplayWidget; + Q_DECLARE_METATYPE(SystemBootParameters); class QtHostInterface : public QObject, private CommonHostInterface @@ -51,7 +52,7 @@ public: bool isOnWorkerThread() const { return QThread::currentThread() == m_worker_thread; } - QtDisplayWindow* createDisplayWindow(); + QtDisplayWidget* createDisplayWidget(); void populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu); @@ -101,7 +102,7 @@ public Q_SLOTS: private Q_SLOTS: void doStopThread(); - void onDisplayWindowResized(int width, int height); + void onDisplayWidgetResized(int width, int height); void doBackgroundControllerPoll(); protected: @@ -155,7 +156,7 @@ private: QSettings m_qsettings; std::mutex m_qsettings_mutex; - QtDisplayWindow* m_display_window = nullptr; + QtDisplayWidget* m_display_widget = nullptr; QThread* m_original_thread = nullptr; Thread* m_worker_thread = nullptr; QEventLoop* m_worker_thread_event_loop = nullptr; diff --git a/src/duckstation-sdl/opengl_host_display.cpp b/src/duckstation-sdl/opengl_host_display.cpp index cb39ca9e6..563a55dd8 100644 --- a/src/duckstation-sdl/opengl_host_display.cpp +++ b/src/duckstation-sdl/opengl_host_display.cpp @@ -8,11 +8,11 @@ #include Log_SetChannel(OpenGLHostDisplay); -class OpenGLHostDisplayTexture : public HostDisplayTexture +class OpenGLDisplayWidgetTexture : public HostDisplayTexture { public: - OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} - ~OpenGLHostDisplayTexture() override { glDeleteTextures(1, &m_id); } + OpenGLDisplayWidgetTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {} + ~OpenGLDisplayWidgetTexture() override { glDeleteTextures(1, &m_id); } void* GetHandle() const override { return reinterpret_cast(static_cast(m_id)); } u32 GetWidth() const override { return m_width; } @@ -20,7 +20,7 @@ public: GLuint GetGLID() const { return m_id; } - static std::unique_ptr Create(u32 width, u32 height, const void* initial_data, + static std::unique_ptr Create(u32 width, u32 height, const void* initial_data, u32 initial_data_stride) { GLuint id; @@ -39,7 +39,7 @@ public: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, id); - return std::make_unique(id, width, height); + return std::make_unique(id, width, height); } private: @@ -111,13 +111,13 @@ void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_heigh std::unique_ptr OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic) { - return OpenGLHostDisplayTexture::Create(width, height, data, data_stride); + return OpenGLDisplayWidgetTexture::Create(width, height, data, data_stride); } void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride) { - OpenGLHostDisplayTexture* tex = static_cast(texture); + OpenGLDisplayWidgetTexture* tex = static_cast(texture); Assert(data_stride == (width * sizeof(u32))); GLint old_texture_binding = 0;