Qt: Replace QWindow for display with QWidget base

Not as elegant, but it solves the input focus issue.
This commit is contained in:
Connor McLaughlin 2020-03-12 13:53:51 +10:00
parent db1070a683
commit 2480624cbe
15 changed files with 449 additions and 375 deletions

View file

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

View file

@ -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 <dxgi1_5.h>
#include <imgui.h>
#include <imgui_impl_dx11.h>
Log_SetChannel(D3D11DisplayWindow);
Log_SetChannel(D3D11DisplayWidget);
class D3D11DisplayWindowTexture : public HostDisplayTexture
class D3D11DisplayWidgetTexture : public HostDisplayTexture
{
public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
D3D11DisplayWindowTexture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> srv, u32 width,
D3D11DisplayWidgetTexture(ComPtr<ID3D11Texture2D> texture, ComPtr<ID3D11ShaderResourceView> 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<D3D11DisplayWindowTexture> Create(ID3D11Device* device, u32 width, u32 height,
static std::unique_ptr<D3D11DisplayWidgetTexture> 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<D3D11DisplayWindowTexture>(std::move(texture), std::move(srv), width, height, dynamic);
return std::make_unique<D3D11DisplayWidgetTexture>(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<QWindow*>(static_cast<const QWindow*>(this));
return const_cast<QWidget*>(static_cast<const QWidget*>(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<HostDisplayTexture> 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<HostDisplayTexture> 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<D3D11DisplayWindowTexture*>(texture);
D3D11DisplayWidgetTexture* d3d11_texture = static_cast<D3D11DisplayWidgetTexture*>(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<char*>(sr.pData) + (y * sr.RowPitch) + (x * sizeof(u32));
const char* src_ptr = static_cast<const char*>(data);
if (sr.RowPitch == data_stride)
const char* src_ptr = static_cast<const char*>(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<bool>(m_device);
}
bool D3D11DisplayWindow::createDeviceContext(QThread* worker_thread, bool debug_device)
bool D3D11DisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_device)
{
ComPtr<IDXGIFactory> 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<IDXGIFactory5> 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<HWND>(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<ID3D11InfoQueue> 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<IDXGIDevice> dxgi_device;
ComPtr<IDXGIAdapter> 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<int>(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<IDXGIFactory5> 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<HWND>(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<ID3D11Texture2D> 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<float, 4> 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;

View file

@ -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 <d3d11.h>
#include <dxgi.h>
#include <memory>
#include <wrl/client.h>
class D3D11DisplayWindow final : public QtDisplayWindow, private HostDisplay
class D3D11DisplayWidget final : public QtDisplayWidget, private HostDisplay
{
Q_OBJECT
@ -16,8 +17,8 @@ public:
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
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<HostDisplayTexture> 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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride, bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
u32 texture_data_stride) override;
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<IDXGIFactory> m_dxgi_factory;
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_context;
ComPtr<IDXGISwapChain> m_swap_chain;

View file

@ -37,16 +37,16 @@
<ItemGroup>
<ClCompile Include="audiosettingswidget.cpp" />
<ClCompile Include="consolesettingswidget.cpp" />
<ClCompile Include="d3d11displaywindow.cpp" />
<ClCompile Include="d3d11displaywidget.cpp" />
<ClCompile Include="gpusettingswidget.cpp" />
<ClCompile Include="hotkeysettingswidget.cpp" />
<ClCompile Include="inputbindingwidgets.cpp" />
<ClCompile Include="qtdisplaywindow.cpp" />
<ClCompile Include="qtdisplaywidget.cpp" />
<ClCompile Include="gamelistsettingswidget.cpp" />
<ClCompile Include="gamelistwidget.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="mainwindow.cpp" />
<ClCompile Include="opengldisplaywindow.cpp" />
<ClCompile Include="opengldisplaywidget.cpp" />
<ClCompile Include="portsettingswidget.cpp" />
<ClCompile Include="qthostinterface.cpp" />
<ClCompile Include="qtsettingsinterface.cpp" />
@ -56,17 +56,17 @@
<ItemGroup>
<QtMoc Include="audiosettingswidget.h" />
<QtMoc Include="portsettingswidget.h" />
<QtMoc Include="qtdisplaywindow.h" />
<QtMoc Include="qtdisplaywidget.h" />
<QtMoc Include="gpusettingswidget.h" />
<QtMoc Include="hotkeysettingswidget.h" />
<QtMoc Include="inputbindingwidgets.h" />
<QtMoc Include="d3d11displaywindow.h" />
<QtMoc Include="d3d11displaywidget.h" />
<ClInclude Include="settingwidgetbinder.h" />
<QtMoc Include="consolesettingswidget.h" />
<QtMoc Include="gamelistsettingswidget.h" />
<QtMoc Include="gamelistwidget.h" />
<QtMoc Include="mainwindow.h" />
<QtMoc Include="opengldisplaywindow.h" />
<QtMoc Include="opengldisplaywidget.h" />
<QtMoc Include="qthostinterface.h" />
<ClInclude Include="qtsettingsinterface.h" />
<ClInclude Include="qtutils.h" />
@ -117,16 +117,16 @@
<ItemGroup>
<ClCompile Include="$(IntDir)moc_audiosettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_consolesettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_d3d11displaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_d3d11displaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
<ClCompile Include="$(IntDir)moc_gpusettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_opengldisplaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_opengldisplaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_qtdisplaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_settingsdialog.cpp" />
<ClCompile Include="$(IntDir)qrc_icons.cpp" />

View file

@ -6,7 +6,6 @@
<ClCompile Include="gamelistwidget.cpp" />
<ClCompile Include="settingsdialog.cpp" />
<ClCompile Include="consolesettingswidget.cpp" />
<ClCompile Include="opengldisplaywindow.cpp" />
<ClCompile Include="qthostinterface.cpp" />
<ClCompile Include="gamelistsettingswidget.cpp" />
<ClCompile Include="qtsettingsinterface.cpp" />
@ -15,24 +14,25 @@
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_opengldisplaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_settingsdialog.cpp" />
<ClCompile Include="$(IntDir)qrc_icons.cpp" />
<ClCompile Include="portsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
<ClCompile Include="qtdisplaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_qtdisplaywindow.cpp" />
<ClCompile Include="gpusettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gpusettingswidget.cpp" />
<ClCompile Include="inputbindingwidgets.cpp" />
<ClCompile Include="hotkeysettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
<ClCompile Include="d3d11displaywindow.cpp" />
<ClCompile Include="$(IntDir)moc_d3d11displaywindow.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" />
<ClCompile Include="qtdisplaywidget.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="qtsettingsinterface.h" />
@ -52,16 +52,16 @@
<QtMoc Include="gamelistsettingswidget.h" />
<QtMoc Include="gamelistwidget.h" />
<QtMoc Include="mainwindow.h" />
<QtMoc Include="opengldisplaywindow.h" />
<QtMoc Include="qthostinterface.h" />
<QtMoc Include="settingsdialog.h" />
<QtMoc Include="portsettingswidget.h" />
<QtMoc Include="qtdisplaywindow.h" />
<QtMoc Include="gpusettingswidget.h" />
<QtMoc Include="hotkeysettingswidget.h" />
<QtMoc Include="inputbindingwidgets.h" />
<QtMoc Include="d3d11displaywindow.h" />
<QtMoc Include="audiosettingswidget.h" />
<QtMoc Include="opengldisplaywidget.h" />
<QtMoc Include="d3d11displaywidget.h" />
<QtMoc Include="qtdisplaywidget.h" />
</ItemGroup>
<ItemGroup>
<QtUi Include="consolesettingswidget.ui" />

View file

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

View file

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

View file

@ -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 <QtGui/QKeyEvent>
#include <QtGui/QWindow>
#include <array>
#include <imgui_impl_opengl3.h>
#include <tuple>
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<void*>(static_cast<uintptr_t>(m_id)); }
u32 GetWidth() const override { return m_width; }
@ -68,7 +69,7 @@ public:
GLuint GetGLID() const { return m_id; }
static std::unique_ptr<OpenGLHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
static std::unique_ptr<OpenGLDisplayWidgetTexture> Create(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride)
{
GLuint 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<OpenGLHostDisplayTexture>(id, width, height);
return std::make_unique<OpenGLDisplayWidgetTexture>(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<QWindow*>(static_cast<const QWindow*>(this));
return const_cast<QWidget*>(static_cast<const QWidget*>(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<HostDisplayTexture> OpenGLDisplayWindow::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
std::unique_ptr<HostDisplayTexture> 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<OpenGLHostDisplayTexture*>(texture);
Assert(data_stride == (width * sizeof(u32)));
OpenGLDisplayWidgetTexture* tex = static_cast<OpenGLDisplayWidgetTexture*>(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, &current_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<bool>(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<QOpenGLContext>();
@ -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<std::tuple<int, int>, 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;

View file

@ -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 <QtGui/QOpenGLContext>
#include <memory>
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<HostDisplayTexture> 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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
u32 initial_data_stride, bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
u32 texture_data_stride) override;
void SetVSync(bool enabled) override;

View file

@ -0,0 +1,145 @@
#include "qtdisplaywidget.h"
#include "imgui.h"
#include "qthostinterface.h"
#include "qtutils.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
#include <cmath>
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<qreal>(1);
}
int QtDisplayWidget::getScaledWindowWidth() const
{
return static_cast<int>(std::ceil(static_cast<qreal>(width()) * getDevicePixelRatioFromScreen()));
}
int QtDisplayWidget::getScaledWindowHeight() const
{
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * getDevicePixelRatioFromScreen()));
}
bool QtDisplayWidget::createImGuiContext()
{
ImGui::CreateContext();
auto& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.DisplaySize.x = static_cast<float>(getScaledWindowWidth());
io.DisplaySize.y = static_cast<float>(getScaledWindowHeight());
const float framebuffer_scale = static_cast<float>(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<float>(new_window_width);
io.DisplaySize.y = static_cast<float>(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<QKeyEvent*>(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);
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include <QtGui/QWindow>
#include "common/types.h"
#include <QtWidgets/QWidget>
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<int>(static_cast<qreal>(width()) * devicePixelRatio()); }
int getScaledWindowHeight() const { return static_cast<int>(static_cast<qreal>(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;
};

View file

@ -1,107 +0,0 @@
#include "qtdisplaywindow.h"
#include "imgui.h"
#include "qthostinterface.h"
#include "qtutils.h"
#include <QtGui/QKeyEvent>
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<float>(getScaledWindowWidth());
io.DisplaySize.y = static_cast<float>(getScaledWindowHeight());
const float framebuffer_scale = static_cast<float>(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<float>(new_window_width);
io.DisplaySize.y = static_cast<float>(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<int>(static_cast<qreal>(event->size().width()) * devicePixelRatio());
const int height = static_cast<int>(static_cast<qreal>(event->size().height()) * devicePixelRatio());
emit windowResizedEvent(width, height);
}

View file

@ -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 <QtCore/QCoreApplication>
@ -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();
}

View file

@ -2,7 +2,6 @@
#include "core/host_interface.h"
#include "core/system.h"
#include "frontend-common/common_host_interface.h"
#include "opengldisplaywindow.h"
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QSettings>
@ -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;

View file

@ -8,11 +8,11 @@
#include <tuple>
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<void*>(static_cast<uintptr_t>(m_id)); }
u32 GetWidth() const override { return m_width; }
@ -20,7 +20,7 @@ public:
GLuint GetGLID() const { return m_id; }
static std::unique_ptr<OpenGLHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
static std::unique_ptr<OpenGLDisplayWidgetTexture> 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<OpenGLHostDisplayTexture>(id, width, height);
return std::make_unique<OpenGLDisplayWidgetTexture>(id, width, height);
}
private:
@ -111,13 +111,13 @@ void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_heigh
std::unique_ptr<HostDisplayTexture> 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<OpenGLHostDisplayTexture*>(texture);
OpenGLDisplayWidgetTexture* tex = static_cast<OpenGLDisplayWidgetTexture*>(texture);
Assert(data_stride == (width * sizeof(u32)));
GLint old_texture_binding = 0;