Qt: Refactor render widget state transitions
Recreate widget each time. Fixes fullscreen mode switches on D3D11 and hopefully Wayland.
This commit is contained in:
parent
d7aa514f14
commit
ea3c0b65cf
|
@ -29,10 +29,12 @@ add_executable(duckstation-qt
|
|||
mainwindow.cpp
|
||||
mainwindow.h
|
||||
mainwindow.ui
|
||||
opengldisplaywidget.cpp
|
||||
opengldisplaywidget.h
|
||||
openglhostdisplay.cpp
|
||||
openglhostdisplay.h
|
||||
portsettingswidget.cpp
|
||||
portsettingswidget.h
|
||||
qthostdisplay.cpp
|
||||
qthostdisplay.h
|
||||
qtdisplaywidget.cpp
|
||||
qtdisplaywidget.h
|
||||
qthostinterface.cpp
|
||||
|
@ -52,8 +54,8 @@ target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui g
|
|||
|
||||
if(WIN32)
|
||||
target_sources(duckstation-qt PRIVATE
|
||||
d3d11displaywidget.cpp
|
||||
d3d11displaywidget.h
|
||||
d3d11hostdisplay.cpp
|
||||
d3d11hostdisplay.h
|
||||
)
|
||||
target_link_libraries(duckstation PRIVATE d3d11.lib dxgi.lib)
|
||||
endif()
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
#include "d3d11displaywidget.h"
|
||||
#include "d3d11hostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/d3d11/shader_compiler.h"
|
||||
#include "common/log.h"
|
||||
#include "frontend-common/display_ps.hlsl.h"
|
||||
#include "frontend-common/display_vs.hlsl.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include <array>
|
||||
#include <dxgi1_5.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_dx11.h>
|
||||
Log_SetChannel(D3D11DisplayWidget);
|
||||
Log_SetChannel(D3D11HostDisplay);
|
||||
|
||||
class D3D11DisplayWidgetTexture : public HostDisplayTexture
|
||||
{
|
||||
|
@ -61,51 +62,33 @@ private:
|
|||
bool m_dynamic;
|
||||
};
|
||||
|
||||
D3D11DisplayWidget::D3D11DisplayWidget(QtHostInterface* host_interface, QWidget* parent)
|
||||
: QtDisplayWidget(host_interface, parent)
|
||||
{
|
||||
}
|
||||
D3D11HostDisplay::D3D11HostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {}
|
||||
|
||||
D3D11DisplayWidget::~D3D11DisplayWidget() = default;
|
||||
D3D11HostDisplay::~D3D11HostDisplay() = default;
|
||||
|
||||
HostDisplay* D3D11DisplayWidget::getHostDisplayInterface()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI D3D11DisplayWidget::GetRenderAPI() const
|
||||
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return HostDisplay::RenderAPI::D3D11;
|
||||
}
|
||||
|
||||
void* D3D11DisplayWidget::GetRenderDevice() const
|
||||
void* D3D11HostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_device.Get();
|
||||
}
|
||||
|
||||
void* D3D11DisplayWidget::GetRenderContext() const
|
||||
void* D3D11HostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_context.Get();
|
||||
}
|
||||
|
||||
void* D3D11DisplayWidget::GetRenderWindow() const
|
||||
{
|
||||
return const_cast<QWidget*>(static_cast<const QWidget*>(this));
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::ChangeRenderWindow(void* new_window)
|
||||
{
|
||||
Panic("Not supported");
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D11DisplayWidget::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
return D3D11DisplayWidgetTexture::Create(m_device.Get(), width, height, initial_data, initial_data_stride, dynamic);
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
D3D11DisplayWidgetTexture* d3d11_texture = static_cast<D3D11DisplayWidgetTexture*>(texture);
|
||||
if (!d3d11_texture->IsDynamic())
|
||||
|
@ -141,8 +124,8 @@ void D3D11DisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y
|
|||
}
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||
void* out_data, u32 out_data_stride)
|
||||
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
ID3D11ShaderResourceView* srv =
|
||||
const_cast<ID3D11ShaderResourceView*>(static_cast<const ID3D11ShaderResourceView*>(texture_handle));
|
||||
|
@ -159,17 +142,17 @@ bool D3D11DisplayWidget::DownloadTexture(const void* texture_handle, u32 x, u32
|
|||
static_cast<u32*>(out_data));
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::SetVSync(bool enabled)
|
||||
void D3D11HostDisplay::SetVSync(bool enabled)
|
||||
{
|
||||
m_vsync = enabled;
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::hasDeviceContext() const
|
||||
bool D3D11HostDisplay::hasDeviceContext() const
|
||||
{
|
||||
return static_cast<bool>(m_device);
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device)
|
||||
bool D3D11HostDisplay::createDeviceContext(bool debug_device)
|
||||
{
|
||||
UINT create_flags = 0;
|
||||
if (debug_device)
|
||||
|
@ -231,49 +214,34 @@ bool D3D11DisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_
|
|||
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
|
||||
}
|
||||
|
||||
if (!createSwapChain())
|
||||
return false;
|
||||
|
||||
if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device))
|
||||
{
|
||||
m_swap_chain.Reset();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::initializeDeviceContext(bool debug_device)
|
||||
void D3D11HostDisplay::destroyDeviceContext()
|
||||
{
|
||||
if (!createSwapChainRTV())
|
||||
return false;
|
||||
|
||||
if (!QtDisplayWidget::initializeDeviceContext(debug_device))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::destroyDeviceContext()
|
||||
{
|
||||
QtDisplayWidget::destroyDeviceContext();
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
m_swap_chain.Reset();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::shouldUseFlipModelSwapChain() const
|
||||
bool D3D11HostDisplay::shouldUseFlipModelSwapChain() const
|
||||
{
|
||||
// For some reason DXGI gets stuck waiting for some kernel object when the Qt window has a parent (render-to-main) on
|
||||
// some computers, unless the window is completely occluded. The legacy swap chain mode does not have this problem.
|
||||
return parent() == nullptr;
|
||||
return m_widget->parent() == nullptr;
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::createSwapChain()
|
||||
bool D3D11HostDisplay::createSurface()
|
||||
{
|
||||
m_using_flip_model_swap_chain = shouldUseFlipModelSwapChain();
|
||||
|
||||
const HWND window_hwnd = reinterpret_cast<HWND>(m_widget->winId());
|
||||
RECT client_rc{};
|
||||
GetClientRect(window_hwnd, &client_rc);
|
||||
m_window_width = client_rc.right - client_rc.left;
|
||||
m_window_height = client_rc.bottom - client_rc.top;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
|
||||
swap_chain_desc.BufferDesc.Width = m_window_width;
|
||||
swap_chain_desc.BufferDesc.Height = m_window_height;
|
||||
|
@ -281,7 +249,7 @@ bool D3D11DisplayWidget::createSwapChain()
|
|||
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<HWND>(winId());
|
||||
swap_chain_desc.OutputWindow = window_hwnd;
|
||||
swap_chain_desc.Windowed = TRUE;
|
||||
swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
|
@ -289,6 +257,10 @@ bool D3D11DisplayWidget::createSwapChain()
|
|||
if (m_using_allow_tearing)
|
||||
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
|
||||
Log_InfoPrintf("Creating a %dx%d %s %s swap chain", m_window_width, m_window_height,
|
||||
m_using_flip_model_swap_chain ? "flip-discard" : "discard",
|
||||
swap_chain_desc.Windowed ? "windowed" : "full-screen");
|
||||
|
||||
HRESULT hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
|
||||
if (FAILED(hr) && m_using_flip_model_swap_chain)
|
||||
{
|
||||
|
@ -310,44 +282,14 @@ bool D3D11DisplayWidget::createSwapChain()
|
|||
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;
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::recreateSwapChain()
|
||||
{
|
||||
m_swap_chain_rtv.Reset();
|
||||
m_swap_chain.Reset();
|
||||
|
||||
if (!createSwapChain() || !createSwapChainRTV())
|
||||
Panic("Failed to recreate swap chain");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (m_using_flip_model_swap_chain != shouldUseFlipModelSwapChain())
|
||||
{
|
||||
recreateSwapChain();
|
||||
return;
|
||||
}
|
||||
|
||||
m_swap_chain_rtv.Reset();
|
||||
|
||||
HRESULT hr = m_swap_chain->ResizeBuffers(0, new_window_width, new_window_height, DXGI_FORMAT_UNKNOWN,
|
||||
m_using_allow_tearing ? 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()
|
||||
bool D3D11HostDisplay::createSwapChainRTV()
|
||||
{
|
||||
ComPtr<ID3D11Texture2D> backbuffer;
|
||||
HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(backbuffer.GetAddressOf()));
|
||||
|
@ -372,7 +314,32 @@ bool D3D11DisplayWidget::createSwapChainRTV()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::createDeviceResources()
|
||||
void D3D11HostDisplay::destroySurface()
|
||||
{
|
||||
m_swap_chain_rtv.Reset();
|
||||
m_swap_chain.Reset();
|
||||
QtHostDisplay::destroySurface();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
QtHostDisplay::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_using_allow_tearing ? 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 D3D11HostDisplay::createDeviceResources()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -418,9 +385,9 @@ bool D3D11DisplayWidget::createDeviceResources()
|
|||
return true;
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::destroyDeviceResources()
|
||||
void D3D11HostDisplay::destroyDeviceResources()
|
||||
{
|
||||
QtDisplayWidget::destroyDeviceResources();
|
||||
QtHostDisplay::destroyDeviceResources();
|
||||
|
||||
m_display_uniform_buffer.Release();
|
||||
m_swap_chain_rtv.Reset();
|
||||
|
@ -433,9 +400,9 @@ void D3D11DisplayWidget::destroyDeviceResources()
|
|||
m_display_rasterizer_state.Reset();
|
||||
}
|
||||
|
||||
bool D3D11DisplayWidget::createImGuiContext()
|
||||
bool D3D11HostDisplay::createImGuiContext()
|
||||
{
|
||||
if (!QtDisplayWidget::createImGuiContext())
|
||||
if (!QtHostDisplay::createImGuiContext())
|
||||
return false;
|
||||
|
||||
if (!ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()))
|
||||
|
@ -446,13 +413,13 @@ bool D3D11DisplayWidget::createImGuiContext()
|
|||
return true;
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::destroyImGuiContext()
|
||||
void D3D11HostDisplay::destroyImGuiContext()
|
||||
{
|
||||
ImGui_ImplDX11_Shutdown();
|
||||
QtDisplayWidget::destroyImGuiContext();
|
||||
QtHostDisplay::destroyImGuiContext();
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::Render()
|
||||
void D3D11HostDisplay::Render()
|
||||
{
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data());
|
||||
|
@ -472,12 +439,13 @@ void D3D11DisplayWidget::Render()
|
|||
ImGui_ImplDX11_NewFrame();
|
||||
}
|
||||
|
||||
void D3D11DisplayWidget::renderDisplay()
|
||||
void D3D11HostDisplay::renderDisplay()
|
||||
{
|
||||
if (!m_display_texture_handle)
|
||||
return;
|
||||
|
||||
auto [vp_left, vp_top, vp_width, vp_height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
auto [vp_left, vp_top, vp_width, vp_height] =
|
||||
CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
|
@ -4,37 +4,31 @@
|
|||
#include "common/d3d11/texture.h"
|
||||
#include "common/windows_headers.h"
|
||||
#include "core/host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include <d3d11.h>
|
||||
#include <dxgi.h>
|
||||
#include <memory>
|
||||
#include <wrl/client.h>
|
||||
|
||||
class D3D11DisplayWidget final : public QtDisplayWidget, private HostDisplay
|
||||
class D3D11HostDisplay final : public QtHostDisplay
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||
|
||||
D3D11DisplayWidget(QtHostInterface* host_interface, QWidget* parent);
|
||||
~D3D11DisplayWidget();
|
||||
|
||||
HostDisplay* getHostDisplayInterface() override;
|
||||
D3D11HostDisplay(QtHostInterface* host_interface);
|
||||
~D3D11HostDisplay();
|
||||
|
||||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(QThread* worker_thread, bool debug_device) override;
|
||||
bool initializeDeviceContext(bool debug_device) override;
|
||||
bool createDeviceContext(bool debug_device) override;
|
||||
void destroyDeviceContext() override;
|
||||
bool createSurface() override;
|
||||
void destroySurface() override;
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
|
@ -56,9 +50,7 @@ private:
|
|||
void destroyDeviceResources() override;
|
||||
|
||||
bool shouldUseFlipModelSwapChain() const;
|
||||
bool createSwapChain();
|
||||
bool createSwapChainRTV();
|
||||
void recreateSwapChain();
|
||||
|
||||
void renderDisplay();
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
<ClCompile Include="consolesettingswidget.cpp" />
|
||||
<ClCompile Include="d3d11displaywidget.cpp" />
|
||||
<ClCompile Include="d3d11hostdisplay.cpp" />
|
||||
<ClCompile Include="generalsettingswidget.cpp" />
|
||||
<ClCompile Include="gpusettingswidget.cpp" />
|
||||
<ClCompile Include="hotkeysettingswidget.cpp" />
|
||||
|
@ -47,8 +47,9 @@
|
|||
<ClCompile Include="gamelistwidget.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="mainwindow.cpp" />
|
||||
<ClCompile Include="opengldisplaywidget.cpp" />
|
||||
<ClCompile Include="openglhostdisplay.cpp" />
|
||||
<ClCompile Include="portsettingswidget.cpp" />
|
||||
<ClCompile Include="qthostdisplay.cpp" />
|
||||
<ClCompile Include="qthostinterface.cpp" />
|
||||
<ClCompile Include="qtprogresscallback.cpp" />
|
||||
<ClCompile Include="qtsettingsinterface.cpp" />
|
||||
|
@ -63,14 +64,15 @@
|
|||
<QtMoc Include="gpusettingswidget.h" />
|
||||
<QtMoc Include="hotkeysettingswidget.h" />
|
||||
<QtMoc Include="inputbindingwidgets.h" />
|
||||
<QtMoc Include="d3d11displaywidget.h" />
|
||||
<ClInclude Include="d3d11hostdisplay.h" />
|
||||
<QtMoc Include="qtprogresscallback.h" />
|
||||
<ClInclude Include="qthostdisplay.h" />
|
||||
<ClInclude Include="settingwidgetbinder.h" />
|
||||
<QtMoc Include="consolesettingswidget.h" />
|
||||
<QtMoc Include="gamelistsettingswidget.h" />
|
||||
<QtMoc Include="gamelistwidget.h" />
|
||||
<QtMoc Include="mainwindow.h" />
|
||||
<QtMoc Include="opengldisplaywidget.h" />
|
||||
<ClInclude Include="openglhostdisplay.h" />
|
||||
<QtMoc Include="qthostinterface.h" />
|
||||
<ClInclude Include="qtsettingsinterface.h" />
|
||||
<ClInclude Include="qtutils.h" />
|
||||
|
@ -127,7 +129,6 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="$(IntDir)moc_audiosettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_consolesettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_d3d11displaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_generalsettingswidget.cpp" />
|
||||
|
@ -135,7 +136,6 @@
|
|||
<ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_opengldisplaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
|
||||
|
@ -477,4 +477,4 @@
|
|||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\dep\msvc\vsprops\QtCompile.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_audiosettingswidget.cpp" />
|
||||
<ClCompile Include="opengldisplaywidget.cpp" />
|
||||
<ClCompile Include="d3d11displaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_d3d11displaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_opengldisplaywidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
|
||||
|
@ -37,11 +35,15 @@
|
|||
<ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" />
|
||||
<ClCompile Include="generalsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_generalsettingswidget.cpp" />
|
||||
<ClCompile Include="qthostdisplay.cpp" />
|
||||
<ClCompile Include="openglhostdisplay.cpp" />
|
||||
<ClCompile Include="d3d11hostdisplay.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="qtsettingsinterface.h" />
|
||||
<ClInclude Include="qtutils.h" />
|
||||
<ClInclude Include="settingwidgetbinder.h" />
|
||||
<ClInclude Include="qthostdisplay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="resources">
|
||||
|
@ -63,11 +65,11 @@
|
|||
<QtMoc Include="hotkeysettingswidget.h" />
|
||||
<QtMoc Include="inputbindingwidgets.h" />
|
||||
<QtMoc Include="audiosettingswidget.h" />
|
||||
<QtMoc Include="opengldisplaywidget.h" />
|
||||
<QtMoc Include="d3d11displaywidget.h" />
|
||||
<QtMoc Include="qtdisplaywidget.h" />
|
||||
<QtMoc Include="generalsettingswidget.h" />
|
||||
<QtMoc Include="qtprogresscallback.h" />
|
||||
<QtMoc Include="openglhostdisplay.h" />
|
||||
<QtMoc Include="d3d11hostdisplay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUi Include="consolesettingswidget.ui" />
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
static void InitLogging()
|
||||
{
|
||||
// set log flags
|
||||
#ifdef _DEBUG
|
||||
#ifdef _DEBUGA
|
||||
Log::SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
|
||||
Log::SetFilterLevel(LOGLEVEL_DEBUG);
|
||||
#else
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "gamelistsettingswidget.h"
|
||||
#include "gamelistwidget.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include "qthostinterface.h"
|
||||
#include "qtsettingsinterface.h"
|
||||
#include "scmversion/scmversion.h"
|
||||
|
@ -66,17 +67,15 @@ bool MainWindow::confirmMessage(const QString& message)
|
|||
return (result == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_device, bool fullscreen,
|
||||
bool render_to_main)
|
||||
void MainWindow::createDisplay(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main)
|
||||
{
|
||||
DebugAssert(!m_display_widget);
|
||||
Assert(!m_host_display && !m_display_widget);
|
||||
Assert(!fullscreen || !render_to_main);
|
||||
|
||||
m_display_widget = m_host_interface->createDisplayWidget();
|
||||
m_host_display = m_host_interface->createHostDisplay();
|
||||
m_display_widget = m_host_display->createWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
m_display_widget->setWindowIcon(windowIcon());
|
||||
DebugAssert(m_display_widget);
|
||||
|
||||
m_display_widget->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
|
@ -96,15 +95,77 @@ void MainWindow::createDisplayWindow(QThread* worker_thread, bool use_debug_devi
|
|||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
m_display_widget->createDeviceContext(worker_thread, use_debug_device);
|
||||
if (!m_host_display->createDeviceContext(use_debug_device))
|
||||
{
|
||||
reportError(tr("Failed to create host display device context."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_host_display->createSurface() || !m_host_display->makeDeviceContextCurrent())
|
||||
{
|
||||
reportError(tr("Failed to create host display surface."));
|
||||
m_host_display->destroyDeviceContext();
|
||||
return;
|
||||
}
|
||||
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplayWindow()
|
||||
void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
|
||||
{
|
||||
DebugAssert(m_display_widget);
|
||||
const bool is_fullscreen = m_display_widget->isFullScreen();
|
||||
const bool is_rendering_to_main = (!is_fullscreen && m_display_widget->parent());
|
||||
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main)
|
||||
{
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_display_widget->isFullScreen())
|
||||
m_host_display->destroySurface();
|
||||
|
||||
if (is_rendering_to_main)
|
||||
{
|
||||
switchToGameListView();
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
}
|
||||
|
||||
m_host_display->destroyWidget();
|
||||
m_display_widget = m_host_display->createWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
m_display_widget->setWindowIcon(windowIcon());
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
m_display_widget->showFullScreen();
|
||||
m_display_widget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
else if (!render_to_main)
|
||||
{
|
||||
m_display_widget->showNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
switchToEmulationView();
|
||||
}
|
||||
|
||||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
if (!m_host_display->createSurface())
|
||||
Panic("Failed to recreate surface on new widget.");
|
||||
|
||||
m_display_widget->setFocus();
|
||||
|
||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplay()
|
||||
{
|
||||
DebugAssert(m_host_display && m_display_widget);
|
||||
|
||||
if (m_display_widget->parent())
|
||||
{
|
||||
|
@ -112,58 +173,11 @@ void MainWindow::destroyDisplayWindow()
|
|||
switchToGameListView();
|
||||
}
|
||||
|
||||
// recreate the display widget using the potentially-new renderer
|
||||
delete m_display_widget;
|
||||
m_host_display->destroyWidget();
|
||||
m_display_widget = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::updateDisplayWindow(bool fullscreen, bool render_to_main)
|
||||
{
|
||||
const bool is_fullscreen = m_display_widget->isFullScreen();
|
||||
const bool is_rendering_to_main = (!is_fullscreen && m_display_widget->parent());
|
||||
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main)
|
||||
return;
|
||||
|
||||
if (fullscreen || !render_to_main)
|
||||
{
|
||||
if (m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->setCurrentIndex(0);
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
m_display_widget->setParent(nullptr);
|
||||
switchToGameListView();
|
||||
}
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
m_display_widget->showFullScreen();
|
||||
m_display_widget->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we don't position it, it ends up in the top-left corner with the title bar obscured
|
||||
m_display_widget->setCursor(QCursor());
|
||||
m_display_widget->showNormal();
|
||||
m_display_widget->move(pos());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// render-to-main
|
||||
if (!m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->insertWidget(1, m_display_widget);
|
||||
m_ui.mainContainer->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
m_display_widget->setCursor(QCursor());
|
||||
}
|
||||
|
||||
m_display_widget->windowResizedEvent(m_display_widget->scaledWindowWidth(), m_display_widget->scaledWindowHeight());
|
||||
m_display_widget->setFocus();
|
||||
|
||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
delete m_host_display;
|
||||
m_host_display = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::focusDisplayWidget()
|
||||
|
@ -523,10 +537,10 @@ void MainWindow::connectSignals()
|
|||
connect(m_host_interface, &QtHostInterface::messageReported, this, &MainWindow::reportMessage);
|
||||
connect(m_host_interface, &QtHostInterface::messageConfirmed, this, &MainWindow::confirmMessage,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(m_host_interface, &QtHostInterface::createDisplayWindowRequested, this, &MainWindow::createDisplayWindow,
|
||||
connect(m_host_interface, &QtHostInterface::createDisplayRequested, this, &MainWindow::createDisplay,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(m_host_interface, &QtHostInterface::destroyDisplayWindowRequested, this, &MainWindow::destroyDisplayWindow);
|
||||
connect(m_host_interface, &QtHostInterface::updateDisplayWindowRequested, this, &MainWindow::updateDisplayWindow,
|
||||
connect(m_host_interface, &QtHostInterface::destroyDisplayRequested, this, &MainWindow::destroyDisplay);
|
||||
connect(m_host_interface, &QtHostInterface::updateDisplayRequested, this, &MainWindow::updateDisplay,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(m_host_interface, &QtHostInterface::focusDisplayWidgetRequested, this, &MainWindow::focusDisplayWidget);
|
||||
connect(m_host_interface, &QtHostInterface::emulationStarted, this, &MainWindow::onEmulationStarted);
|
||||
|
|
|
@ -12,6 +12,7 @@ class QThread;
|
|||
|
||||
class GameListWidget;
|
||||
class QtHostInterface;
|
||||
class QtHostDisplay;
|
||||
class QtDisplayWidget;
|
||||
|
||||
struct GameListEntry;
|
||||
|
@ -28,9 +29,9 @@ private Q_SLOTS:
|
|||
void reportError(const QString& message);
|
||||
void reportMessage(const QString& message);
|
||||
bool confirmMessage(const QString& message);
|
||||
void createDisplayWindow(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main);
|
||||
void destroyDisplayWindow();
|
||||
void updateDisplayWindow(bool fullscreen, bool render_to_main);
|
||||
void createDisplay(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main);
|
||||
void updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
||||
void destroyDisplay();
|
||||
void focusDisplayWidget();
|
||||
void onEmulationStarted();
|
||||
void onEmulationStopped();
|
||||
|
@ -73,6 +74,8 @@ private:
|
|||
QtHostInterface* m_host_interface = nullptr;
|
||||
|
||||
GameListWidget* m_game_list_widget = nullptr;
|
||||
|
||||
QtHostDisplay* m_host_display = nullptr;
|
||||
QtDisplayWidget* m_display_widget = nullptr;
|
||||
|
||||
QLabel* m_status_speed_widget = nullptr;
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
#include "opengldisplaywidget.h"
|
||||
#include "openglhostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostinterface.h"
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QWindow>
|
||||
#include <array>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <tuple>
|
||||
Log_SetChannel(OpenGLDisplayWidget);
|
||||
Log_SetChannel(OpenGLHostDisplay);
|
||||
|
||||
static thread_local QOpenGLContext* s_thread_gl_context;
|
||||
|
||||
|
@ -27,7 +28,7 @@ static void* GetProcAddressCallback(const char* name)
|
|||
|
||||
/// Changes the swap interval on a window. Since Qt doesn't expose this functionality, we need to change it manually
|
||||
/// ourselves it by calling system-specific functions. Assumes the context is current.
|
||||
static void SetSwapInterval(QWindow* window, QOpenGLContext* context, int interval)
|
||||
static void SetSwapInterval(QOpenGLContext* context, int interval)
|
||||
{
|
||||
static QOpenGLContext* last_context = nullptr;
|
||||
|
||||
|
@ -97,60 +98,44 @@ private:
|
|||
u32 m_height;
|
||||
};
|
||||
|
||||
OpenGLDisplayWidget::OpenGLDisplayWidget(QtHostInterface* host_interface, QWidget* parent)
|
||||
: QtDisplayWidget(host_interface, parent)
|
||||
OpenGLHostDisplay::OpenGLHostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {}
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay() = default;
|
||||
|
||||
QtDisplayWidget* OpenGLHostDisplay::createWidget(QWidget* parent)
|
||||
{
|
||||
QWindow* native_window = windowHandle();
|
||||
QtDisplayWidget* widget = QtHostDisplay::createWidget(parent);
|
||||
|
||||
QWindow* native_window = widget->windowHandle();
|
||||
Assert(native_window);
|
||||
native_window->setSurfaceType(QWindow::OpenGLSurface);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
OpenGLDisplayWidget::~OpenGLDisplayWidget() = default;
|
||||
|
||||
HostDisplay* OpenGLDisplayWidget::getHostDisplayInterface()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLDisplayWidget::GetRenderAPI() const
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->isOpenGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLDisplayWidget::GetRenderDevice() const
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenGLDisplayWidget::GetRenderContext() const
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void* OpenGLDisplayWidget::GetRenderWindow() const
|
||||
{
|
||||
return const_cast<QWidget*>(static_cast<const QWidget*>(this));
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::ChangeRenderWindow(void* new_window)
|
||||
{
|
||||
Panic("Not implemented");
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::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);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLDisplayWidget::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
return OpenGLDisplayWidgetTexture::Create(width, height, initial_data, initial_data_stride);
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
void OpenGLHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
OpenGLDisplayWidgetTexture* tex = static_cast<OpenGLDisplayWidgetTexture*>(texture);
|
||||
Assert((texture_data_stride % sizeof(u32)) == 0);
|
||||
|
@ -171,8 +156,8 @@ void OpenGLDisplayWidget::UpdateTexture(HostDisplayTexture* texture, u32 x, u32
|
|||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||
void* out_data, u32 out_data_stride)
|
||||
bool OpenGLHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
GLint old_alignment = 0, old_row_length = 0;
|
||||
glGetIntegerv(GL_PACK_ALIGNMENT, &old_alignment);
|
||||
|
@ -189,17 +174,17 @@ bool OpenGLDisplayWidget::DownloadTexture(const void* texture_handle, u32 x, u32
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::SetVSync(bool enabled)
|
||||
void OpenGLHostDisplay::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(windowHandle(), m_gl_context.get(), enabled ? 1 : 0);
|
||||
SetSwapInterval(m_gl_context.get(), enabled ? 1 : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
const char* OpenGLDisplayWidget::GetGLSLVersionString() const
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (m_gl_context->isOpenGLES())
|
||||
{
|
||||
|
@ -217,7 +202,7 @@ const char* OpenGLDisplayWidget::GetGLSLVersionString() const
|
|||
}
|
||||
}
|
||||
|
||||
std::string OpenGLDisplayWidget::GetGLSLVersionHeader() const
|
||||
std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
||||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
|
@ -250,12 +235,12 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen
|
|||
}
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::hasDeviceContext() const
|
||||
bool OpenGLHostDisplay::hasDeviceContext() const
|
||||
{
|
||||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device)
|
||||
bool OpenGLHostDisplay::createDeviceContext(bool debug_device)
|
||||
{
|
||||
m_gl_context = std::make_unique<QOpenGLContext>();
|
||||
|
||||
|
@ -308,28 +293,12 @@ bool OpenGLDisplayWidget::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(windowHandle()))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make GL context current on UI thread");
|
||||
m_gl_context.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device))
|
||||
{
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context->moveToThread(worker_thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::initializeDeviceContext(bool debug_device)
|
||||
bool OpenGLHostDisplay::initializeDeviceContext(bool debug_device)
|
||||
{
|
||||
if (!m_gl_context->makeCurrent(windowHandle()))
|
||||
if (!m_gl_context->makeCurrent(m_widget->windowHandle()))
|
||||
return false;
|
||||
|
||||
s_thread_gl_context = m_gl_context.get();
|
||||
|
@ -352,7 +321,7 @@ bool OpenGLDisplayWidget::initializeDeviceContext(bool debug_device)
|
|||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
if (!QtDisplayWidget::initializeDeviceContext(debug_device))
|
||||
if (!QtHostDisplay::initializeDeviceContext(debug_device))
|
||||
{
|
||||
s_thread_gl_context = nullptr;
|
||||
m_gl_context->doneCurrent();
|
||||
|
@ -362,20 +331,47 @@ bool OpenGLDisplayWidget::initializeDeviceContext(bool debug_device)
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::destroyDeviceContext()
|
||||
bool OpenGLHostDisplay::makeDeviceContextCurrent()
|
||||
{
|
||||
if (!m_gl_context->makeCurrent(m_widget->windowHandle()))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make GL context current");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::moveContextToThread(QThread* new_thread)
|
||||
{
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context->moveToThread(new_thread);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
Assert(m_gl_context && s_thread_gl_context == m_gl_context.get());
|
||||
|
||||
QtDisplayWidget::destroyDeviceContext();
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
|
||||
s_thread_gl_context = nullptr;
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::createImGuiContext()
|
||||
bool OpenGLHostDisplay::createSurface()
|
||||
{
|
||||
if (!QtDisplayWidget::createImGuiContext())
|
||||
m_window_width = m_widget->scaledWindowWidth();
|
||||
m_window_height = m_widget->scaledWindowHeight();
|
||||
emit m_widget->windowResizedEvent(m_window_width, m_window_height);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroySurface() {}
|
||||
|
||||
bool OpenGLHostDisplay::createImGuiContext()
|
||||
{
|
||||
if (!QtHostDisplay::createImGuiContext())
|
||||
return false;
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
|
@ -386,14 +382,14 @@ bool OpenGLDisplayWidget::createImGuiContext()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::destroyImGuiContext()
|
||||
void OpenGLHostDisplay::destroyImGuiContext()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
|
||||
QtDisplayWidget::destroyImGuiContext();
|
||||
QtHostDisplay::destroyImGuiContext();
|
||||
}
|
||||
|
||||
bool OpenGLDisplayWidget::createDeviceResources()
|
||||
bool OpenGLHostDisplay::createDeviceResources()
|
||||
{
|
||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||
uniform vec4 u_src_rect;
|
||||
|
@ -453,9 +449,9 @@ void main()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::destroyDeviceResources()
|
||||
void OpenGLHostDisplay::destroyDeviceResources()
|
||||
{
|
||||
QtDisplayWidget::destroyDeviceResources();
|
||||
QtHostDisplay::destroyDeviceResources();
|
||||
|
||||
if (m_display_vao != 0)
|
||||
glDeleteVertexArrays(1, &m_display_vao);
|
||||
|
@ -467,7 +463,7 @@ void OpenGLDisplayWidget::destroyDeviceResources()
|
|||
m_display_program.Destroy();
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::Render()
|
||||
void OpenGLHostDisplay::Render()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
@ -479,7 +475,7 @@ void OpenGLDisplayWidget::Render()
|
|||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
QWindow* window_handle = windowHandle();
|
||||
QWindow* window_handle = m_widget->windowHandle();
|
||||
m_gl_context->makeCurrent(window_handle);
|
||||
m_gl_context->swapBuffers(window_handle);
|
||||
|
||||
|
@ -489,12 +485,13 @@ void OpenGLDisplayWidget::Render()
|
|||
GL::Program::ResetLastProgram();
|
||||
}
|
||||
|
||||
void OpenGLDisplayWidget::renderDisplay()
|
||||
void OpenGLHostDisplay::renderDisplay()
|
||||
{
|
||||
if (!m_display_texture_handle)
|
||||
return;
|
||||
|
||||
const auto [vp_left, vp_top, vp_width, vp_height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
const auto [vp_left, vp_top, vp_width, vp_height] =
|
||||
CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
|
||||
glViewport(vp_left, m_window_height - (m_display_top_margin + vp_top) - vp_height, vp_width, vp_height);
|
||||
glDisable(GL_BLEND);
|
|
@ -12,33 +12,32 @@
|
|||
#include "common/gl/texture.h"
|
||||
#include "core/host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <memory>
|
||||
|
||||
class QtHostInterface;
|
||||
|
||||
class OpenGLDisplayWidget final : public QtDisplayWidget, public HostDisplay
|
||||
class OpenGLHostDisplay final : public QtHostDisplay
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OpenGLDisplayWidget(QtHostInterface* host_interface, QWidget* parent);
|
||||
~OpenGLDisplayWidget();
|
||||
OpenGLHostDisplay(QtHostInterface* host_interface);
|
||||
~OpenGLHostDisplay();
|
||||
|
||||
HostDisplay* getHostDisplayInterface() override;
|
||||
QtDisplayWidget* createWidget(QWidget* parent) override;
|
||||
|
||||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(QThread* worker_thread, bool debug_device) override;
|
||||
bool createDeviceContext(bool debug_device) override;
|
||||
bool initializeDeviceContext(bool debug_device) override;
|
||||
bool makeDeviceContextCurrent() override;
|
||||
void moveContextToThread(QThread* new_thread) override;
|
||||
void destroyDeviceContext() override;
|
||||
bool createSurface() override;
|
||||
void destroySurface();
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void* GetRenderWindow() const override;
|
||||
|
||||
void ChangeRenderWindow(void* new_window) 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;
|
|
@ -1,6 +1,5 @@
|
|||
#include "qtdisplaywidget.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include "imgui.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include "qthostinterface.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
@ -10,47 +9,18 @@
|
|||
#include <QtGui/QWindowStateChangeEvent>
|
||||
#include <cmath>
|
||||
|
||||
QtDisplayWidget::QtDisplayWidget(QtHostInterface* host_interface, QWidget* parent)
|
||||
: QWidget(parent), m_host_interface(host_interface)
|
||||
QtDisplayWidget::QtDisplayWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
// We want a native window for both D3D and OpenGL.
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_NativeWindow, true);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
|
||||
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::devicePixelRatioFromScreen() const
|
||||
{
|
||||
QScreen* screen_for_ratio;
|
||||
|
@ -75,49 +45,6 @@ int QtDisplayWidget::scaledWindowHeight() const
|
|||
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen()));
|
||||
}
|
||||
|
||||
bool QtDisplayWidget::createImGuiContext()
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
io.DisplaySize.x = static_cast<float>(scaledWindowWidth());
|
||||
io.DisplaySize.y = static_cast<float>(scaledWindowHeight());
|
||||
|
||||
const float framebuffer_scale = static_cast<float>(devicePixelRatioFromScreen());
|
||||
io.DisplayFramebufferScale.x = framebuffer_scale;
|
||||
io.DisplayFramebufferScale.y = framebuffer_scale;
|
||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||
|
||||
ImGui::StyleColorsDarker();
|
||||
ImGui::AddRobotoRegularFont(15.0f * 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<float>(new_window_width);
|
||||
io.DisplaySize.y = static_cast<float>(new_window_height);
|
||||
}
|
||||
|
||||
QPaintEngine* QtDisplayWidget::paintEngine() const
|
||||
{
|
||||
return nullptr;
|
||||
|
@ -132,7 +59,7 @@ bool QtDisplayWidget::event(QEvent* event)
|
|||
{
|
||||
QKeyEvent* key_event = static_cast<QKeyEvent*>(event);
|
||||
if (!key_event->isAutoRepeat())
|
||||
m_host_interface->handleKeyEvent(QtUtils::KeyEventToInt(key_event), event->type() == QEvent::KeyPress);
|
||||
emit windowKeyEvent(QtUtils::KeyEventToInt(key_event), event->type() == QEvent::KeyPress);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -147,7 +74,7 @@ bool QtDisplayWidget::event(QEvent* event)
|
|||
|
||||
case QEvent::Close:
|
||||
{
|
||||
m_host_interface->synchronousPowerOffSystem();
|
||||
emit windowClosedEvent();
|
||||
QWidget::event(event);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,49 +2,26 @@
|
|||
#include "common/types.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
class QKeyEvent;
|
||||
class QResizeEvent;
|
||||
|
||||
class HostDisplay;
|
||||
|
||||
class QtHostInterface;
|
||||
|
||||
class QtDisplayWidget : public QWidget
|
||||
class QtDisplayWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtDisplayWidget(QtHostInterface* host_interface, QWidget* parent);
|
||||
virtual ~QtDisplayWidget();
|
||||
QtDisplayWidget(QWidget* parent);
|
||||
~QtDisplayWidget();
|
||||
|
||||
virtual HostDisplay* getHostDisplayInterface();
|
||||
|
||||
virtual bool hasDeviceContext() const;
|
||||
virtual bool createDeviceContext(QThread* worker_thread, bool debug_device);
|
||||
virtual bool initializeDeviceContext(bool debug_device);
|
||||
virtual void destroyDeviceContext();
|
||||
|
||||
// this comes back on the emu thread
|
||||
virtual void windowResized(s32 new_window_width, s32 new_window_height);
|
||||
|
||||
virtual QPaintEngine* paintEngine() const override;
|
||||
QPaintEngine* paintEngine() const override;
|
||||
|
||||
int scaledWindowWidth() const;
|
||||
int scaledWindowHeight() const;
|
||||
qreal devicePixelRatioFromScreen() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void windowResizedEvent(int width, int height);
|
||||
void windowRestoredEvent();
|
||||
void windowClosedEvent();
|
||||
void windowKeyEvent(int key_code, bool pressed);
|
||||
|
||||
protected:
|
||||
qreal devicePixelRatioFromScreen() const;
|
||||
|
||||
virtual bool createImGuiContext();
|
||||
virtual void destroyImGuiContext();
|
||||
virtual bool createDeviceResources();
|
||||
virtual void destroyDeviceResources();
|
||||
|
||||
virtual bool event(QEvent* event) override;
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
bool event(QEvent* event) override;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
#include "qthostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include "imgui.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostinterface.h"
|
||||
#include <cmath>
|
||||
|
||||
QtHostDisplay::QtHostDisplay(QtHostInterface* host_interface) : m_host_interface(host_interface) {}
|
||||
|
||||
QtHostDisplay::~QtHostDisplay() = default;
|
||||
|
||||
QtDisplayWidget* QtHostDisplay::createWidget(QWidget* parent)
|
||||
{
|
||||
Assert(!m_widget);
|
||||
m_widget = new QtDisplayWidget(parent);
|
||||
|
||||
// We want a native window for both D3D and OpenGL.
|
||||
m_widget->setAutoFillBackground(false);
|
||||
m_widget->setAttribute(Qt::WA_NativeWindow, true);
|
||||
m_widget->setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
m_widget->setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
|
||||
return m_widget;
|
||||
}
|
||||
|
||||
void QtHostDisplay::destroyWidget()
|
||||
{
|
||||
Assert(m_widget);
|
||||
|
||||
delete m_widget;
|
||||
m_widget = nullptr;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::hasDeviceContext() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::createDeviceContext(bool debug_device)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::initializeDeviceContext(bool debug_device)
|
||||
{
|
||||
if (!createImGuiContext() || !createDeviceResources())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::makeDeviceContextCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtHostDisplay::moveContextToThread(QThread* new_thread) {}
|
||||
|
||||
void QtHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
destroyImGuiContext();
|
||||
destroyDeviceResources();
|
||||
}
|
||||
|
||||
bool QtHostDisplay::createSurface()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void QtHostDisplay::destroySurface() {}
|
||||
|
||||
void* QtHostDisplay::GetRenderWindow() const
|
||||
{
|
||||
return m_widget;
|
||||
}
|
||||
|
||||
void QtHostDisplay::ChangeRenderWindow(void* new_window)
|
||||
{
|
||||
Panic("Not implemented");
|
||||
}
|
||||
|
||||
bool QtHostDisplay::createImGuiContext()
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
io.DisplaySize.x = static_cast<float>(m_window_width);
|
||||
io.DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
const float framebuffer_scale = static_cast<float>(m_widget->devicePixelRatioFromScreen());
|
||||
io.DisplayFramebufferScale.x = framebuffer_scale;
|
||||
io.DisplayFramebufferScale.y = framebuffer_scale;
|
||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||
|
||||
ImGui::StyleColorsDarker();
|
||||
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtHostDisplay::destroyImGuiContext()
|
||||
{
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
bool QtHostDisplay::createDeviceResources()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtHostDisplay::destroyDeviceResources() {}
|
||||
|
||||
void QtHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
HostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
updateImGuiDisplaySize();
|
||||
}
|
||||
|
||||
void QtHostDisplay::updateImGuiDisplaySize()
|
||||
{
|
||||
// imgui may not have been initialized yet
|
||||
if (!ImGui::GetCurrentContext())
|
||||
return;
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.DisplaySize.x = static_cast<float>(m_window_width);
|
||||
io.DisplaySize.y = static_cast<float>(m_window_height);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include "core/host_display.h"
|
||||
|
||||
class QThread;
|
||||
class QWidget;
|
||||
|
||||
class QtHostInterface;
|
||||
class QtDisplayWidget;
|
||||
|
||||
class QtHostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
QtHostDisplay(QtHostInterface* host_interface);
|
||||
virtual ~QtHostDisplay();
|
||||
|
||||
ALWAYS_INLINE bool hasWidget() const { return (m_widget != nullptr); }
|
||||
ALWAYS_INLINE QtDisplayWidget* getWidget() const { return m_widget; }
|
||||
|
||||
virtual QtDisplayWidget* createWidget(QWidget* parent);
|
||||
virtual void destroyWidget();
|
||||
|
||||
virtual bool hasDeviceContext() const;
|
||||
virtual bool createDeviceContext(bool debug_device);
|
||||
virtual bool initializeDeviceContext(bool debug_device);
|
||||
virtual bool makeDeviceContextCurrent();
|
||||
virtual void moveContextToThread(QThread* new_thread);
|
||||
virtual void destroyDeviceContext();
|
||||
virtual bool createSurface();
|
||||
virtual void destroySurface();
|
||||
|
||||
virtual void* GetRenderWindow() const override;
|
||||
virtual void ChangeRenderWindow(void* new_window) override;
|
||||
virtual void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
void updateImGuiDisplaySize();
|
||||
|
||||
protected:
|
||||
virtual bool createImGuiContext();
|
||||
virtual void destroyImGuiContext();
|
||||
virtual bool createDeviceResources();
|
||||
virtual void destroyDeviceResources();
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
QtDisplayWidget* m_widget = nullptr;
|
||||
};
|
|
@ -11,7 +11,7 @@
|
|||
#include "frontend-common/sdl_audio_stream.h"
|
||||
#include "frontend-common/sdl_controller_interface.h"
|
||||
#include "mainwindow.h"
|
||||
#include "opengldisplaywidget.h"
|
||||
#include "openglhostdisplay.h"
|
||||
#include "qtprogresscallback.h"
|
||||
#include "qtsettingsinterface.h"
|
||||
#include "qtutils.h"
|
||||
|
@ -26,7 +26,7 @@
|
|||
Log_SetChannel(QtHostInterface);
|
||||
|
||||
#ifdef WIN32
|
||||
#include "d3d11displaywidget.h"
|
||||
#include "d3d11hostdisplay.h"
|
||||
#endif
|
||||
|
||||
QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostInterface()
|
||||
|
@ -36,7 +36,7 @@ QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostI
|
|||
|
||||
QtHostInterface::~QtHostInterface()
|
||||
{
|
||||
Assert(!m_display_widget);
|
||||
Assert(!getHostDisplay());
|
||||
}
|
||||
|
||||
const char* QtHostInterface::GetFrontendName() const
|
||||
|
@ -162,10 +162,10 @@ void QtHostInterface::applySettings()
|
|||
|
||||
// detect when render-to-main flag changes
|
||||
const bool render_to_main = m_qsettings->value("Main/RenderToMainWindow", true).toBool();
|
||||
if (m_system && m_display_widget && !m_is_fullscreen && render_to_main != m_is_rendering_to_main)
|
||||
if (m_system && getHostDisplay() && !m_is_fullscreen && render_to_main != m_is_rendering_to_main)
|
||||
{
|
||||
m_is_rendering_to_main = render_to_main;
|
||||
emit updateDisplayWindowRequested(false, render_to_main);
|
||||
updateDisplayState();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,23 +188,6 @@ void QtHostInterface::setMainWindow(MainWindow* window)
|
|||
m_main_window = window;
|
||||
}
|
||||
|
||||
QtDisplayWidget* QtHostInterface::createDisplayWidget()
|
||||
{
|
||||
Assert(!m_display_widget);
|
||||
|
||||
#ifdef WIN32
|
||||
if (m_settings.gpu_renderer == GPURenderer::HardwareOpenGL)
|
||||
m_display_widget = new OpenGLDisplayWidget(this, nullptr);
|
||||
else
|
||||
m_display_widget = new D3D11DisplayWidget(this, nullptr);
|
||||
#else
|
||||
m_display_widget = new OpenGLDisplayWidget(this, nullptr);
|
||||
#endif
|
||||
connect(m_display_widget, &QtDisplayWidget::windowResizedEvent, this, &QtHostInterface::onDisplayWidgetResized);
|
||||
connect(m_display_widget, &QtDisplayWidget::windowRestoredEvent, this, &QtHostInterface::redrawDisplayWindow);
|
||||
return m_display_widget;
|
||||
}
|
||||
|
||||
void QtHostInterface::bootSystem(const SystemBootParameters& params)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
|
@ -231,24 +214,19 @@ void QtHostInterface::resumeSystemFromState(const QString& filename, bool boot_o
|
|||
HostInterface::ResumeSystemFromState(filename.toStdString().c_str(), boot_on_failure);
|
||||
}
|
||||
|
||||
void QtHostInterface::handleKeyEvent(int key, bool pressed)
|
||||
void QtHostInterface::onDisplayWindowKeyEvent(int key, bool pressed)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "handleKeyEvent", Qt::QueuedConnection, Q_ARG(int, key), Q_ARG(bool, pressed));
|
||||
return;
|
||||
}
|
||||
|
||||
DebugAssert(isOnWorkerThread());
|
||||
HandleHostKeyEvent(key, pressed);
|
||||
}
|
||||
|
||||
void QtHostInterface::onDisplayWidgetResized(int width, int height)
|
||||
void QtHostInterface::onHostDisplayWindowResized(int width, int height)
|
||||
{
|
||||
// this can be null if it was destroyed and the main thread is late catching up
|
||||
if (!m_display_widget)
|
||||
if (!getHostDisplay())
|
||||
return;
|
||||
|
||||
m_display_widget->windowResized(width, height);
|
||||
getHostDisplay()->WindowResized(width, height);
|
||||
|
||||
// re-render the display, since otherwise it will be out of date and stretched if paused
|
||||
if (m_system)
|
||||
|
@ -263,7 +241,7 @@ void QtHostInterface::redrawDisplayWindow()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!m_display_widget || !m_system)
|
||||
if (!getHostDisplay() || !m_system)
|
||||
return;
|
||||
|
||||
renderDisplay();
|
||||
|
@ -280,39 +258,91 @@ void QtHostInterface::toggleFullscreen()
|
|||
SetFullscreen(!m_is_fullscreen);
|
||||
}
|
||||
|
||||
QtHostDisplay* QtHostInterface::getHostDisplay()
|
||||
{
|
||||
return static_cast<QtHostDisplay*>(m_display);
|
||||
}
|
||||
|
||||
bool QtHostInterface::AcquireHostDisplay()
|
||||
{
|
||||
DebugAssert(!m_display_widget);
|
||||
Assert(!m_display);
|
||||
|
||||
m_is_rendering_to_main = getSettingValue("Main/RenderToMainWindow", true).toBool();
|
||||
emit createDisplayWindowRequested(m_worker_thread, m_settings.gpu_use_debug_device, m_is_fullscreen,
|
||||
m_is_rendering_to_main);
|
||||
if (!m_display_widget->hasDeviceContext())
|
||||
emit createDisplayRequested(m_worker_thread, m_settings.gpu_use_debug_device, m_is_fullscreen,
|
||||
m_is_rendering_to_main);
|
||||
Assert(m_display);
|
||||
|
||||
if (!getHostDisplay()->hasDeviceContext())
|
||||
{
|
||||
m_display_widget = nullptr;
|
||||
emit destroyDisplayWindowRequested();
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_display_widget->initializeDeviceContext(m_settings.gpu_use_debug_device))
|
||||
if (!getHostDisplay()->makeDeviceContextCurrent() ||
|
||||
!getHostDisplay()->initializeDeviceContext(m_settings.gpu_use_debug_device))
|
||||
{
|
||||
m_display_widget->destroyDeviceContext();
|
||||
m_display_widget = nullptr;
|
||||
emit destroyDisplayWindowRequested();
|
||||
getHostDisplay()->destroyDeviceContext();
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_display = m_display_widget->getHostDisplayInterface();
|
||||
connectDisplaySignals();
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
||||
return getHostDisplay();
|
||||
}
|
||||
|
||||
void QtHostInterface::connectDisplaySignals()
|
||||
{
|
||||
QtDisplayWidget* widget = getHostDisplay()->getWidget();
|
||||
connect(widget, &QtDisplayWidget::windowResizedEvent, this, &QtHostInterface::onHostDisplayWindowResized);
|
||||
connect(widget, &QtDisplayWidget::windowRestoredEvent, this, &QtHostInterface::redrawDisplayWindow);
|
||||
connect(widget, &QtDisplayWidget::windowClosedEvent, this, &QtHostInterface::powerOffSystem,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(widget, &QtDisplayWidget::windowKeyEvent, this, &QtHostInterface::onDisplayWindowKeyEvent);
|
||||
}
|
||||
|
||||
void QtHostInterface::disconnectDisplaySignals()
|
||||
{
|
||||
getHostDisplay()->getWidget()->disconnect(this);
|
||||
}
|
||||
|
||||
void QtHostInterface::updateDisplayState()
|
||||
{
|
||||
// this expects the context to get moved back to us afterwards
|
||||
getHostDisplay()->moveContextToThread(m_original_thread);
|
||||
emit updateDisplayRequested(m_worker_thread, m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!getHostDisplay()->makeDeviceContextCurrent())
|
||||
Panic("Failed to make device context current after updating");
|
||||
|
||||
getHostDisplay()->updateImGuiDisplaySize();
|
||||
connectDisplaySignals();
|
||||
UpdateSpeedLimiterState();
|
||||
}
|
||||
|
||||
void QtHostInterface::ReleaseHostDisplay()
|
||||
{
|
||||
DebugAssert(m_display_widget && m_display == m_display_widget->getHostDisplayInterface());
|
||||
Assert(m_display);
|
||||
|
||||
getHostDisplay()->destroyDeviceContext();
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
m_display_widget->destroyDeviceContext();
|
||||
m_display_widget = nullptr;
|
||||
emit destroyDisplayWindowRequested();
|
||||
}
|
||||
|
||||
bool QtHostInterface::IsFullscreen() const
|
||||
|
@ -326,7 +356,7 @@ bool QtHostInterface::SetFullscreen(bool enabled)
|
|||
return true;
|
||||
|
||||
m_is_fullscreen = enabled;
|
||||
emit updateDisplayWindowRequested(m_is_fullscreen, m_is_rendering_to_main);
|
||||
updateDisplayState();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ class QTimer;
|
|||
class GameList;
|
||||
|
||||
class MainWindow;
|
||||
class QtDisplayWidget;
|
||||
|
||||
class QtHostDisplay;
|
||||
|
||||
Q_DECLARE_METATYPE(SystemBootParameters);
|
||||
|
||||
|
@ -65,7 +66,7 @@ public:
|
|||
|
||||
ALWAYS_INLINE MainWindow* getMainWindow() const { return m_main_window; }
|
||||
void setMainWindow(MainWindow* window);
|
||||
QtDisplayWidget* createDisplayWidget();
|
||||
QtHostDisplay* createHostDisplay();
|
||||
|
||||
void populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu);
|
||||
|
||||
|
@ -87,11 +88,10 @@ Q_SIGNALS:
|
|||
void emulationPaused(bool paused);
|
||||
void stateSaved(const QString& game_code, bool global, qint32 slot);
|
||||
void gameListRefreshed();
|
||||
void createDisplayWindowRequested(QThread* worker_thread, bool use_debug_device, bool fullscreen,
|
||||
bool render_to_main);
|
||||
void destroyDisplayWindowRequested();
|
||||
void updateDisplayWindowRequested(bool fullscreen, bool render_to_main);
|
||||
void createDisplayRequested(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main);
|
||||
void updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
||||
void focusDisplayWidgetRequested();
|
||||
void destroyDisplayRequested();
|
||||
void systemPerformanceCountersUpdated(float speed, float fps, float vps, float avg_frame_time,
|
||||
float worst_frame_time);
|
||||
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
|
||||
|
@ -103,7 +103,7 @@ public Q_SLOTS:
|
|||
void applySettings();
|
||||
void updateInputMap();
|
||||
void applyInputProfile(const QString& profile_path);
|
||||
void handleKeyEvent(int key, bool pressed);
|
||||
void onDisplayWindowKeyEvent(int key, bool pressed);
|
||||
void bootSystem(const SystemBootParameters& params);
|
||||
void resumeSystemFromState(const QString& filename, bool boot_on_failure);
|
||||
void powerOffSystem();
|
||||
|
@ -129,7 +129,7 @@ public Q_SLOTS:
|
|||
|
||||
private Q_SLOTS:
|
||||
void doStopThread();
|
||||
void onDisplayWidgetResized(int width, int height);
|
||||
void onHostDisplayWindowResized(int width, int height);
|
||||
void doBackgroundControllerPoll();
|
||||
|
||||
protected:
|
||||
|
@ -180,6 +180,8 @@ private:
|
|||
Common::Event m_init_event;
|
||||
};
|
||||
|
||||
QtHostDisplay* getHostDisplay();
|
||||
|
||||
void createBackgroundControllerPollTimer();
|
||||
void destroyBackgroundControllerPollTimer();
|
||||
|
||||
|
@ -189,13 +191,15 @@ private:
|
|||
bool initializeOnThread();
|
||||
void shutdownOnThread();
|
||||
void renderDisplay();
|
||||
void connectDisplaySignals();
|
||||
void disconnectDisplaySignals();
|
||||
void updateDisplayState();
|
||||
void wakeThread();
|
||||
|
||||
std::unique_ptr<QSettings> m_qsettings;
|
||||
std::recursive_mutex m_qsettings_mutex;
|
||||
|
||||
MainWindow* m_main_window = nullptr;
|
||||
QtDisplayWidget* m_display_widget = nullptr;
|
||||
QThread* m_original_thread = nullptr;
|
||||
Thread* m_worker_thread = nullptr;
|
||||
QEventLoop* m_worker_thread_event_loop = nullptr;
|
||||
|
|
Loading…
Reference in New Issue