HostDisplay: Move most backend logic to FrontendCommon
This commit is contained in:
parent
84a52a3911
commit
2a38090e7a
|
@ -438,19 +438,15 @@ Global
|
|||
{4266505B-DBAF-484B-AB31-B53B9C8235B3}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
|
||||
{4266505B-DBAF-484B-AB31-B53B9C8235B3}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x86.Build.0 = Debug|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x64.ActiveCfg = DebugFast|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x64.Build.0 = DebugFast|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x86.ActiveCfg = DebugFast|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x86.Build.0 = DebugFast|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x64.Build.0 = Release|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x86.Build.0 = Release|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
|
||||
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
|
||||
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
|
|
@ -11,7 +11,8 @@ struct WindowInfo
|
|||
X11,
|
||||
Wayland,
|
||||
MacOS,
|
||||
Android
|
||||
Android,
|
||||
Libretro,
|
||||
};
|
||||
|
||||
enum class SurfaceFormat
|
||||
|
|
|
@ -13,12 +13,6 @@ HostDisplayTexture::~HostDisplayTexture() = default;
|
|||
|
||||
HostDisplay::~HostDisplay() = default;
|
||||
|
||||
void HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
m_window_width = new_window_width;
|
||||
m_window_height = new_window_height;
|
||||
}
|
||||
|
||||
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
|
||||
{
|
||||
m_cursor_texture = std::move(texture);
|
||||
|
@ -68,7 +62,7 @@ void HostDisplay::CalculateDrawRect(s32 window_width, s32 window_height, s32* ou
|
|||
float* out_y_scale) const
|
||||
{
|
||||
const float y_scale =
|
||||
(static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_pixel_aspect_ratio;
|
||||
(static_cast<float>(m_display_width) / static_cast<float>(m_display_height)) / m_display_aspect_ratio;
|
||||
const float display_width = static_cast<float>(m_display_width);
|
||||
const float display_height = static_cast<float>(m_display_height) * y_scale;
|
||||
const float active_left = static_cast<float>(m_display_active_left);
|
||||
|
@ -266,26 +260,28 @@ bool HostDisplay::WriteDisplayTextureToFile(const char* filename, bool full_reso
|
|||
s32 resize_height = 0;
|
||||
if (apply_aspect_ratio && full_resolution)
|
||||
{
|
||||
if (m_display_pixel_aspect_ratio > 1.0f)
|
||||
if (m_display_aspect_ratio > 1.0f)
|
||||
{
|
||||
resize_width = m_display_texture_view_width;
|
||||
resize_height = static_cast<s32>(static_cast<float>(resize_width) / m_display_pixel_aspect_ratio);
|
||||
resize_height = static_cast<s32>(static_cast<float>(resize_width) / m_display_aspect_ratio);
|
||||
}
|
||||
else
|
||||
{
|
||||
resize_height = std::abs(m_display_texture_view_height);
|
||||
resize_width = static_cast<s32>(static_cast<float>(resize_height) * m_display_pixel_aspect_ratio);
|
||||
resize_width = static_cast<s32>(static_cast<float>(resize_height) * m_display_aspect_ratio);
|
||||
}
|
||||
}
|
||||
else if (apply_aspect_ratio)
|
||||
{
|
||||
const auto [left, top, right, bottom] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
const auto [left, top, right, bottom] =
|
||||
CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
resize_width = right - left;
|
||||
resize_height = bottom - top;
|
||||
}
|
||||
else if (!full_resolution)
|
||||
{
|
||||
const auto [left, top, right, bottom] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
const auto [left, top, right, bottom] =
|
||||
CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
const float ratio =
|
||||
static_cast<float>(m_display_texture_view_width) / static_cast<float>(std::abs(m_display_texture_view_height));
|
||||
if (ratio > 1.0f)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
#include "common/rectangle.h"
|
||||
#include "common/window_info.h"
|
||||
#include "types.h"
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
|
@ -31,8 +33,8 @@ public:
|
|||
|
||||
virtual ~HostDisplay();
|
||||
|
||||
ALWAYS_INLINE s32 GetWindowWidth() const { return m_window_width; }
|
||||
ALWAYS_INLINE s32 GetWindowHeight() const { return m_window_height; }
|
||||
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
|
||||
ALWAYS_INLINE s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
|
||||
|
||||
// Position is relative to the top-left corner of the window.
|
||||
ALWAYS_INLINE s32 GetMousePositionX() const { return m_mouse_position_x; }
|
||||
|
@ -47,8 +49,19 @@ public:
|
|||
virtual void* GetRenderDevice() const = 0;
|
||||
virtual void* GetRenderContext() const = 0;
|
||||
|
||||
virtual bool HasRenderDevice() const = 0;
|
||||
virtual bool HasRenderSurface() const = 0;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) = 0;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) = 0;
|
||||
virtual bool MakeRenderContextCurrent() = 0;
|
||||
virtual bool DoneRenderContextCurrent() = 0;
|
||||
virtual void DestroyRenderDevice() = 0;
|
||||
virtual void DestroyRenderSurface() = 0;
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& wi) = 0;
|
||||
|
||||
/// Call when the window size changes externally to recreate any resources.
|
||||
virtual void WindowResized(s32 new_window_width, s32 new_window_height);
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) = 0;
|
||||
|
||||
/// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below.
|
||||
virtual std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
|
||||
|
@ -59,7 +72,8 @@ public:
|
|||
virtual bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) = 0;
|
||||
|
||||
virtual void Render() = 0;
|
||||
/// Returns false if the window was completely occluded.
|
||||
virtual bool Render() = 0;
|
||||
|
||||
virtual void SetVSync(bool enabled) = 0;
|
||||
|
||||
|
@ -91,7 +105,7 @@ public:
|
|||
}
|
||||
|
||||
void SetDisplayParameters(s32 display_width, s32 display_height, s32 active_left, s32 active_top, s32 active_width,
|
||||
s32 active_height, float pixel_aspect_ratio)
|
||||
s32 active_height, float display_aspect_ratio)
|
||||
{
|
||||
m_display_width = display_width;
|
||||
m_display_height = display_height;
|
||||
|
@ -99,7 +113,7 @@ public:
|
|||
m_display_active_top = active_top;
|
||||
m_display_active_width = active_width;
|
||||
m_display_active_height = active_height;
|
||||
m_display_pixel_aspect_ratio = pixel_aspect_ratio;
|
||||
m_display_aspect_ratio = display_aspect_ratio;
|
||||
m_display_changed = true;
|
||||
}
|
||||
|
||||
|
@ -147,8 +161,7 @@ protected:
|
|||
|
||||
std::tuple<s32, s32, s32, s32> CalculateSoftwareCursorDrawRect() const;
|
||||
|
||||
s32 m_window_width = 0;
|
||||
s32 m_window_height = 0;
|
||||
WindowInfo m_window_info;
|
||||
|
||||
s32 m_mouse_position_x = 0;
|
||||
s32 m_mouse_position_y = 0;
|
||||
|
@ -159,7 +172,7 @@ protected:
|
|||
s32 m_display_active_top = 0;
|
||||
s32 m_display_active_width = 0;
|
||||
s32 m_display_active_height = 0;
|
||||
float m_display_pixel_aspect_ratio = 1.0f;
|
||||
float m_display_aspect_ratio = 1.0f;
|
||||
|
||||
void* m_display_texture_handle = nullptr;
|
||||
s32 m_display_texture_width = 0;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
virtual ~HostInterface();
|
||||
|
||||
/// Access to host display.
|
||||
ALWAYS_INLINE HostDisplay* GetDisplay() const { return m_display; }
|
||||
ALWAYS_INLINE HostDisplay* GetDisplay() const { return m_display.get(); }
|
||||
|
||||
/// Access to host audio stream.
|
||||
ALWAYS_INLINE AudioStream* GetAudioStream() const { return m_audio_stream.get(); }
|
||||
|
@ -96,6 +96,12 @@ public:
|
|||
/// Retrieves information about specified game from game list.
|
||||
virtual void GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title);
|
||||
|
||||
/// Returns the default path to a memory card.
|
||||
virtual std::string GetSharedMemoryCardPath(u32 slot) const;
|
||||
|
||||
/// Returns the default path to a memory card for a specific game.
|
||||
virtual std::string GetGameMemoryCardPath(const char* game_code, u32 slot) const;
|
||||
|
||||
/// Enables the software cursor. Can be called multiple times, but must be matched by a call to DisableSoftwareCursor().
|
||||
void EnableSoftwareCursor();
|
||||
|
||||
|
@ -135,12 +141,6 @@ protected:
|
|||
/// Sets the user directory to the program directory, i.e. "portable mode".
|
||||
void SetUserDirectoryToProgramDirectory();
|
||||
|
||||
/// Returns the default path to a memory card.
|
||||
std::string GetSharedMemoryCardPath(u32 slot) const;
|
||||
|
||||
/// Returns the default path to a memory card for a specific game.
|
||||
std::string GetGameMemoryCardPath(const char* game_code, u32 slot) const;
|
||||
|
||||
/// Loads the BIOS image for the specified region.
|
||||
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
|
||||
|
||||
|
@ -153,7 +153,7 @@ protected:
|
|||
bool SaveState(const char* filename);
|
||||
void CreateAudioStream();
|
||||
|
||||
HostDisplay* m_display = nullptr;
|
||||
std::unique_ptr<HostDisplay> m_display;
|
||||
std::unique_ptr<AudioStream> m_audio_stream;
|
||||
std::unique_ptr<System> m_system;
|
||||
Settings m_settings;
|
||||
|
|
|
@ -463,7 +463,7 @@ const char* Settings::GetControllerTypeDisplayName(ControllerType type)
|
|||
static std::array<const char*, 4> s_memory_card_type_names = {{"None", "Shared", "PerGame", "PerGameTitle"}};
|
||||
static std::array<const char*, 4> s_memory_card_type_display_names = {{"No Memory Card", "Shared Between All Games",
|
||||
"Separate Card Per Game (Game Code)",
|
||||
"Seperate Card Per Game (Game Title)"}};
|
||||
"Separate Card Per Game (Game Title)"}};
|
||||
|
||||
std::optional<MemoryCardType> Settings::ParseMemoryCardTypeName(const char* str)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,12 @@ struct SystemBootParameters
|
|||
class System
|
||||
{
|
||||
public:
|
||||
enum : u32
|
||||
{
|
||||
// 5 megabytes is sufficient for now, at the moment they're around 4.2MB.
|
||||
MAX_SAVE_STATE_SIZE = 5 * 1024 * 1024
|
||||
};
|
||||
|
||||
friend TimingEvent;
|
||||
|
||||
~System();
|
||||
|
|
|
@ -41,10 +41,6 @@ add_executable(duckstation-qt
|
|||
mainwindow.ui
|
||||
memorycardsettingswidget.cpp
|
||||
memorycardsettingswidget.h
|
||||
openglhostdisplay.cpp
|
||||
openglhostdisplay.h
|
||||
qthostdisplay.cpp
|
||||
qthostdisplay.h
|
||||
qtdisplaywidget.cpp
|
||||
qtdisplaywidget.h
|
||||
qthostinterface.cpp
|
||||
|
@ -58,19 +54,12 @@ add_executable(duckstation-qt
|
|||
settingsdialog.cpp
|
||||
settingsdialog.h
|
||||
settingsdialog.ui
|
||||
vulkanhostdisplay.cpp
|
||||
vulkanhostdisplay.h
|
||||
)
|
||||
|
||||
target_include_directories(duckstation-qt PRIVATE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}")
|
||||
target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui glad minizip scmversion vulkan-loader Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(duckstation-qt PRIVATE
|
||||
d3d11hostdisplay.cpp
|
||||
d3d11hostdisplay.h
|
||||
)
|
||||
|
||||
# We want a Windows subsystem application not console.
|
||||
set_target_properties(duckstation-qt PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
#include "d3d11hostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
Log_SetChannel(D3D11HostDisplay);
|
||||
|
||||
D3D11HostDisplay::D3D11HostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {}
|
||||
|
||||
D3D11HostDisplay::~D3D11HostDisplay() = default;
|
||||
|
||||
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_interface.GetRenderAPI();
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_interface.GetRenderDevice();
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_interface.GetRenderContext();
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
return m_interface.CreateTexture(width, height, initial_data, initial_data_stride, dynamic);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
m_interface.UpdateTexture(texture, x, y, width, height, texture_data, texture_data_stride);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
return m_interface.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::SetVSync(bool enabled)
|
||||
{
|
||||
m_interface.SetVSync(enabled);
|
||||
}
|
||||
|
||||
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 m_widget->parent() == nullptr;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::hasDeviceContext() const
|
||||
{
|
||||
return m_interface.HasContext();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device)
|
||||
{
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi || !m_interface.CreateContextAndSwapChain(wi.value(), adapter_name.toStdString(),
|
||||
shouldUseFlipModelSwapChain(), debug_device))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_width = static_cast<s32>(m_interface.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_interface.GetSwapChainHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
return QtHostDisplay::initializeDeviceContext(shader_cache_directory, debug_device);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::activateDeviceContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::deactivateDeviceContext() {}
|
||||
|
||||
void D3D11HostDisplay::destroyDeviceContext()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
m_interface.DestroySwapChain();
|
||||
m_interface.DestroyContext();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::recreateSurface()
|
||||
{
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
return false;
|
||||
|
||||
if (!m_interface.RecreateSwapChain(wi.value(), shouldUseFlipModelSwapChain()))
|
||||
return false;
|
||||
|
||||
m_window_width = static_cast<s32>(m_interface.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_interface.GetSwapChainHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::destroySurface()
|
||||
{
|
||||
m_interface.DestroySwapChain();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
QtHostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
|
||||
m_interface.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_width = static_cast<s32>(m_interface.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_interface.GetSwapChainHeight());
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::createDeviceResources()
|
||||
{
|
||||
if (!QtHostDisplay::createDeviceResources())
|
||||
return false;
|
||||
|
||||
return m_interface.CreateResources();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::destroyDeviceResources()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceResources();
|
||||
m_interface.DestroyResources();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::createImGuiContext()
|
||||
{
|
||||
if (!QtHostDisplay::createImGuiContext() || !m_interface.CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::destroyImGuiContext()
|
||||
{
|
||||
m_interface.DestroyImGuiContext();
|
||||
QtHostDisplay::destroyImGuiContext();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::Render()
|
||||
{
|
||||
if (!m_interface.HasSwapChain() || !m_interface.BeginRender())
|
||||
return;
|
||||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
m_interface.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
m_interface.RenderImGui();
|
||||
|
||||
if (HasSoftwareCursor())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
m_interface.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
m_interface.EndRenderAndPresent();
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include "frontend-common/d3d11_host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include <memory>
|
||||
|
||||
class QtHostInterface;
|
||||
|
||||
class D3D11HostDisplay final : public QtHostDisplay
|
||||
{
|
||||
public:
|
||||
D3D11HostDisplay(QtHostInterface* host_interface);
|
||||
~D3D11HostDisplay();
|
||||
|
||||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(const QString& adapter_name, bool debug_device) override;
|
||||
bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
bool activateDeviceContext() override;
|
||||
void deactivateDeviceContext() override;
|
||||
void destroyDeviceContext() override;
|
||||
bool recreateSurface() override;
|
||||
void destroySurface();
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
bool shouldUseFlipModelSwapChain() const;
|
||||
|
||||
bool createImGuiContext() override;
|
||||
void destroyImGuiContext() override;
|
||||
bool createDeviceResources() override;
|
||||
void destroyDeviceResources() override;
|
||||
|
||||
FrontendCommon::D3D11HostDisplay m_interface;
|
||||
};
|
|
@ -39,7 +39,6 @@
|
|||
<ClCompile Include="advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
<ClCompile Include="consolesettingswidget.cpp" />
|
||||
<ClCompile Include="d3d11hostdisplay.cpp" />
|
||||
<ClCompile Include="generalsettingswidget.cpp" />
|
||||
<ClCompile Include="gpusettingswidget.cpp" />
|
||||
<ClCompile Include="hotkeysettingswidget.cpp" />
|
||||
|
@ -50,19 +49,15 @@
|
|||
<ClCompile Include="gamepropertiesdialog.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="mainwindow.cpp" />
|
||||
<ClCompile Include="openglhostdisplay.cpp" />
|
||||
<ClCompile Include="controllersettingswidget.cpp" />
|
||||
<ClCompile Include="memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="qthostdisplay.cpp" />
|
||||
<ClCompile Include="qthostinterface.cpp" />
|
||||
<ClCompile Include="qtprogresscallback.cpp" />
|
||||
<ClCompile Include="qtsettingsinterface.cpp" />
|
||||
<ClCompile Include="qtutils.cpp" />
|
||||
<ClCompile Include="settingsdialog.cpp" />
|
||||
<ClCompile Include="vulkanhostdisplay.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="vulkanhostdisplay.h" />
|
||||
<QtMoc Include="aboutdialog.h" />
|
||||
<QtMoc Include="audiosettingswidget.h" />
|
||||
<QtMoc Include="controllersettingswidget.h" />
|
||||
|
@ -73,9 +68,7 @@
|
|||
<QtMoc Include="hotkeysettingswidget.h" />
|
||||
<QtMoc Include="inputbindingwidgets.h" />
|
||||
<QtMoc Include="advancedsettingswidget.h" />
|
||||
<ClInclude Include="d3d11hostdisplay.h" />
|
||||
<QtMoc Include="qtprogresscallback.h" />
|
||||
<ClInclude Include="qthostdisplay.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="settingwidgetbinder.h" />
|
||||
<QtMoc Include="consolesettingswidget.h" />
|
||||
|
@ -83,25 +76,18 @@
|
|||
<QtMoc Include="gamelistwidget.h" />
|
||||
<QtMoc Include="gamepropertiesdialog.h" />
|
||||
<QtMoc Include="mainwindow.h" />
|
||||
<ClInclude Include="openglhostdisplay.h" />
|
||||
<QtMoc Include="qthostinterface.h" />
|
||||
<ClInclude Include="qtsettingsinterface.h" />
|
||||
<ClInclude Include="qtutils.h" />
|
||||
<QtMoc Include="settingsdialog.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\dep\glad\glad.vcxproj">
|
||||
<Project>{43540154-9e1e-409c-834f-b84be5621388}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
|
||||
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\minizip\minizip.vcxproj">
|
||||
<Project>{8bda439c-6358-45fb-9994-2ff083babe06}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\vulkan-loader\vulkan-loader.vcxproj">
|
||||
<Project>{9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\common.vcxproj">
|
||||
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
<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" />
|
||||
<ClCompile Include="advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="gamepropertiesdialog.cpp" />
|
||||
|
@ -43,18 +40,13 @@
|
|||
<ClCompile Include="$(IntDir)moc_aboutdialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_controllersettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)qrc_icons.cpp" />
|
||||
<ClCompile Include="vulkanhostdisplay.cpp" />
|
||||
<ClCompile Include="$(IntDir)qrc_resources.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="qtsettingsinterface.h" />
|
||||
<ClInclude Include="qtutils.h" />
|
||||
<ClInclude Include="settingwidgetbinder.h" />
|
||||
<ClInclude Include="qthostdisplay.h" />
|
||||
<ClInclude Include="d3d11hostdisplay.h" />
|
||||
<ClInclude Include="openglhostdisplay.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="vulkanhostdisplay.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="resources">
|
||||
|
@ -62,7 +54,7 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\icons.qrc" />
|
||||
<QtResource Include="resources\resources.qrc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="consolesettingswidget.h" />
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
#include "aboutdialog.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/game_list.h"
|
||||
#include "core/host_display.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/system.h"
|
||||
#include "gamelistsettingswidget.h"
|
||||
#include "gamelistwidget.h"
|
||||
#include "gamepropertiesdialog.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include "qthostinterface.h"
|
||||
#include "qtsettingsinterface.h"
|
||||
#include "qtutils.h"
|
||||
|
@ -22,8 +22,8 @@
|
|||
#include <QtGui/QCursor>
|
||||
#include <QtGui/QWindowStateChangeEvent>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
#include <cmath>
|
||||
|
||||
static constexpr char DISC_IMAGE_FILTER[] =
|
||||
|
@ -72,14 +72,13 @@ bool MainWindow::confirmMessage(const QString& message)
|
|||
return (result == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
void MainWindow::createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
|
||||
bool fullscreen, bool render_to_main)
|
||||
QtDisplayWidget* MainWindow::createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
|
||||
bool fullscreen, bool render_to_main)
|
||||
{
|
||||
Assert(!m_host_display && !m_display_widget);
|
||||
Assert(!fullscreen || !render_to_main);
|
||||
|
||||
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 = new QtDisplayWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
m_display_widget->setWindowIcon(windowIcon());
|
||||
|
||||
|
@ -101,32 +100,37 @@ void MainWindow::createDisplay(QThread* worker_thread, const QString& adapter_na
|
|||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
if (!m_host_display->createDeviceContext(adapter_name, use_debug_device))
|
||||
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
{
|
||||
reportError(tr("Failed to create host display device context."));
|
||||
return;
|
||||
reportError(tr("Failed to get window info from widget"));
|
||||
destroyDisplayWidget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_host_display->deactivateDeviceContext();
|
||||
m_host_display = m_host_interface->createHostDisplay();
|
||||
if (!m_host_display || !m_host_display->CreateRenderDevice(wi.value(), adapter_name.toStdString(), use_debug_device))
|
||||
{
|
||||
reportError(tr("Failed to create host display device context."));
|
||||
destroyDisplayWidget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_host_display->DoneRenderContextCurrent();
|
||||
return m_display_widget;
|
||||
}
|
||||
|
||||
void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
|
||||
QtDisplayWidget* MainWindow::updateDisplay(QThread* worker_thread, 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;
|
||||
return m_display_widget;
|
||||
|
||||
m_host_display->destroySurface();
|
||||
m_host_display->DestroyRenderSurface();
|
||||
|
||||
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);
|
||||
destroyDisplayWidget();
|
||||
m_display_widget = new QtDisplayWidget((!fullscreen && render_to_main) ? m_ui.mainContainer : nullptr);
|
||||
m_display_widget->setWindowTitle(windowTitle());
|
||||
m_display_widget->setWindowIcon(windowIcon());
|
||||
|
||||
|
@ -148,30 +152,44 @@ void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool ren
|
|||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
if (!m_host_display->recreateSurface())
|
||||
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
{
|
||||
reportError(tr("Failed to get new window info from widget"));
|
||||
destroyDisplayWidget();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_host_display->ChangeRenderWindow(wi.value()))
|
||||
Panic("Failed to recreate surface on new widget.");
|
||||
|
||||
m_display_widget->setFocus();
|
||||
|
||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
return m_display_widget;
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplay()
|
||||
{
|
||||
DebugAssert(m_host_display && m_display_widget);
|
||||
m_host_display = nullptr;
|
||||
destroyDisplayWidget();
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplayWidget()
|
||||
{
|
||||
if (!m_display_widget)
|
||||
return;
|
||||
|
||||
if (m_display_widget->parent())
|
||||
{
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
switchToGameListView();
|
||||
m_ui.mainContainer->removeWidget(m_display_widget);
|
||||
}
|
||||
|
||||
m_host_display->destroyWidget();
|
||||
delete m_display_widget;
|
||||
m_display_widget = nullptr;
|
||||
|
||||
delete m_host_display;
|
||||
m_host_display = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::focusDisplayWidget()
|
||||
|
|
|
@ -12,9 +12,9 @@ class QThread;
|
|||
|
||||
class GameListWidget;
|
||||
class QtHostInterface;
|
||||
class QtHostDisplay;
|
||||
class QtDisplayWidget;
|
||||
|
||||
class HostDisplay;
|
||||
struct GameListEntry;
|
||||
|
||||
class MainWindow final : public QMainWindow
|
||||
|
@ -29,9 +29,9 @@ private Q_SLOTS:
|
|||
void reportError(const QString& message);
|
||||
void reportMessage(const QString& message);
|
||||
bool confirmMessage(const QString& message);
|
||||
void createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device, bool fullscreen,
|
||||
bool render_to_main);
|
||||
void updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
||||
QtDisplayWidget* createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
|
||||
bool fullscreen, bool render_to_main);
|
||||
QtDisplayWidget* updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
||||
void destroyDisplay();
|
||||
void focusDisplayWidget();
|
||||
|
||||
|
@ -72,6 +72,7 @@ private:
|
|||
void updateEmulationActions(bool starting, bool running);
|
||||
void switchToGameListView();
|
||||
void switchToEmulationView();
|
||||
void destroyDisplayWidget();
|
||||
SettingsDialog* getSettingsDialog();
|
||||
void doSettings(SettingsDialog::Category category = SettingsDialog::Category::Count);
|
||||
void updateDebugMenuCPUExecutionMode();
|
||||
|
@ -83,7 +84,7 @@ private:
|
|||
|
||||
GameListWidget* m_game_list_widget = nullptr;
|
||||
|
||||
QtHostDisplay* m_host_display = nullptr;
|
||||
HostDisplay* m_host_display = nullptr;
|
||||
QtDisplayWidget* m_display_widget = nullptr;
|
||||
|
||||
QLabel* m_status_speed_widget = nullptr;
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// GLAD has to come first so that Qt doesn't pull in the system GL headers, which are incompatible with glad.
|
||||
#include <glad.h>
|
||||
|
||||
// Hack to prevent Apple's glext.h headers from getting included via qopengl.h, since we still want to use glad.
|
||||
#ifdef __APPLE__
|
||||
#define __glext_h_
|
||||
#endif
|
||||
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include <memory>
|
||||
|
||||
class QtHostInterface;
|
||||
|
||||
class OpenGLHostDisplay final : public QtHostDisplay
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplay(QtHostInterface* host_interface);
|
||||
~OpenGLHostDisplay();
|
||||
|
||||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(const QString& adapter_name, bool debug_device) override;
|
||||
bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
bool activateDeviceContext() override;
|
||||
void deactivateDeviceContext() override;
|
||||
void destroyDeviceContext() override;
|
||||
bool recreateSurface() override;
|
||||
void destroySurface();
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
bool createImGuiContext() override;
|
||||
void destroyImGuiContext() override;
|
||||
bool createDeviceResources() override;
|
||||
void destroyDeviceResources() override;
|
||||
|
||||
void renderDisplay();
|
||||
|
||||
std::unique_ptr<GL::Context> m_gl_context = nullptr;
|
||||
|
||||
GL::Program m_display_program;
|
||||
GLuint m_display_vao = 0;
|
||||
GLuint m_display_nearest_sampler = 0;
|
||||
GLuint m_display_linear_sampler = 0;
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
#include "qtdisplaywidget.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include "qthostinterface.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QScreen>
|
||||
|
@ -10,6 +10,10 @@
|
|||
#include <QtGui/QWindowStateChangeEvent>
|
||||
#include <cmath>
|
||||
|
||||
#if !defined(WIN32) && !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
QtDisplayWidget::QtDisplayWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
// We want a native window for both D3D and OpenGL.
|
||||
|
@ -47,6 +51,46 @@ int QtDisplayWidget::scaledWindowHeight() const
|
|||
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen()));
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> QtDisplayWidget::getWindowInfo() const
|
||||
{
|
||||
WindowInfo wi;
|
||||
|
||||
// Windows and Apple are easy here since there's no display connection.
|
||||
#if defined(WIN32)
|
||||
wi.type = WindowInfo::Type::Win32;
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
#elif defined(__APPLE__)
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
const QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("xcb"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::X11;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
}
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::Wayland;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
|
||||
wi.window_handle = pni->nativeResourceForWindow("surface", windowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Unknown PNI platform " << platform_name;
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
wi.surface_width = scaledWindowWidth();
|
||||
wi.surface_height = scaledWindowHeight();
|
||||
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
QPaintEngine* QtDisplayWidget::paintEngine() const
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include "common/window_info.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <optional>
|
||||
|
||||
class QtDisplayWidget final : public QWidget
|
||||
{
|
||||
|
@ -16,6 +18,8 @@ public:
|
|||
int scaledWindowHeight() const;
|
||||
qreal devicePixelRatioFromScreen() const;
|
||||
|
||||
std::optional<WindowInfo> getWindowInfo() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void windowResizedEvent(int width, int height);
|
||||
void windowRestoredEvent();
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
#include "qthostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include "imgui.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostinterface.h"
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <cmath>
|
||||
#if !defined(WIN32) && !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
QtHostDisplay::QtHostDisplay(QtHostInterface* host_interface) : m_host_interface(host_interface) {}
|
||||
|
||||
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(const QString& adapter_name, bool debug_device)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
if (!createImGuiContext() || !createDeviceResources())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::activateDeviceContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtHostDisplay::deactivateDeviceContext() {}
|
||||
|
||||
void QtHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
destroyImGuiContext();
|
||||
destroyDeviceResources();
|
||||
}
|
||||
|
||||
bool QtHostDisplay::recreateSurface()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void QtHostDisplay::destroySurface() {}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> QtHostDisplay::getWindowInfo() const
|
||||
{
|
||||
WindowInfo wi;
|
||||
|
||||
// Windows and Apple are easy here since there's no display connection.
|
||||
#if defined(WIN32)
|
||||
wi.type = WindowInfo::Type::Win32;
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
#elif defined(__APPLE__)
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
const QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("xcb"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::X11;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle());
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
}
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::Wayland;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle());
|
||||
wi.window_handle = pni->nativeResourceForWindow("surface", m_widget->windowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Unknown PNI platform " << platform_name;
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
wi.surface_width = m_widget->width();
|
||||
wi.surface_height = m_widget->height();
|
||||
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
||||
|
||||
return wi;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
class QString;
|
||||
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(const QString& adapter_name, bool debug_device);
|
||||
virtual bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device);
|
||||
virtual bool activateDeviceContext();
|
||||
virtual void deactivateDeviceContext();
|
||||
virtual void destroyDeviceContext();
|
||||
virtual bool recreateSurface();
|
||||
virtual void destroySurface();
|
||||
|
||||
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();
|
||||
|
||||
std::optional<WindowInfo> getWindowInfo() const;
|
||||
|
||||
QtHostInterface* m_host_interface;
|
||||
QtDisplayWidget* m_widget = nullptr;
|
||||
};
|
|
@ -8,14 +8,17 @@
|
|||
#include "core/game_list.h"
|
||||
#include "core/gpu.h"
|
||||
#include "core/system.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include "frontend-common/opengl_host_display.h"
|
||||
#include "frontend-common/sdl_audio_stream.h"
|
||||
#include "frontend-common/sdl_controller_interface.h"
|
||||
#include "frontend-common/vulkan_host_display.h"
|
||||
#include "imgui.h"
|
||||
#include "mainwindow.h"
|
||||
#include "openglhostdisplay.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qtprogresscallback.h"
|
||||
#include "qtsettingsinterface.h"
|
||||
#include "qtutils.h"
|
||||
#include "vulkanhostdisplay.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QDebug>
|
||||
|
@ -27,7 +30,7 @@
|
|||
Log_SetChannel(QtHostInterface);
|
||||
|
||||
#ifdef WIN32
|
||||
#include "d3d11hostdisplay.h"
|
||||
#include "frontend-common/d3d11_host_display.h"
|
||||
#endif
|
||||
|
||||
QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostInterface()
|
||||
|
@ -37,7 +40,7 @@ QtHostInterface::QtHostInterface(QObject* parent) : QObject(parent), CommonHostI
|
|||
|
||||
QtHostInterface::~QtHostInterface()
|
||||
{
|
||||
Assert(!getHostDisplay());
|
||||
Assert(!m_display);
|
||||
}
|
||||
|
||||
const char* QtHostInterface::GetFrontendName() const
|
||||
|
@ -177,7 +180,7 @@ void QtHostInterface::applySettings()
|
|||
if (m_system)
|
||||
{
|
||||
const bool render_to_main = getSettingValue("Main/RenderToMainWindow", true).toBool();
|
||||
if (getHostDisplay() && !m_is_fullscreen && render_to_main != m_is_rendering_to_main)
|
||||
if (m_display && !m_is_fullscreen && render_to_main != m_is_rendering_to_main)
|
||||
{
|
||||
m_is_rendering_to_main = render_to_main;
|
||||
updateDisplayState();
|
||||
|
@ -271,10 +274,10 @@ void QtHostInterface::onDisplayWindowMouseButtonEvent(int button, bool pressed)
|
|||
void QtHostInterface::onHostDisplayWindowResized(int width, int height)
|
||||
{
|
||||
// this can be null if it was destroyed and the main thread is late catching up
|
||||
if (!getHostDisplay())
|
||||
if (!m_display)
|
||||
return;
|
||||
|
||||
getHostDisplay()->WindowResized(width, height);
|
||||
m_display->ResizeRenderWindow(width, height);
|
||||
|
||||
// re-render the display, since otherwise it will be out of date and stretched if paused
|
||||
if (m_system)
|
||||
|
@ -289,7 +292,7 @@ void QtHostInterface::redrawDisplayWindow()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!getHostDisplay() || !m_system)
|
||||
if (!m_display || !m_system)
|
||||
return;
|
||||
|
||||
renderDisplay();
|
||||
|
@ -306,71 +309,69 @@ void QtHostInterface::toggleFullscreen()
|
|||
SetFullscreen(!m_is_fullscreen);
|
||||
}
|
||||
|
||||
QtHostDisplay* QtHostInterface::getHostDisplay()
|
||||
{
|
||||
return static_cast<QtHostDisplay*>(m_display);
|
||||
}
|
||||
|
||||
bool QtHostInterface::AcquireHostDisplay()
|
||||
{
|
||||
Assert(!m_display);
|
||||
|
||||
m_is_rendering_to_main = getSettingValue("Main/RenderToMainWindow", true).toBool();
|
||||
emit createDisplayRequested(m_worker_thread, QString::fromStdString(m_settings.gpu_adapter),
|
||||
m_settings.gpu_use_debug_device, m_is_fullscreen, m_is_rendering_to_main);
|
||||
Assert(m_display);
|
||||
|
||||
if (!getHostDisplay()->hasDeviceContext())
|
||||
QtDisplayWidget* display_widget =
|
||||
createDisplayRequested(m_worker_thread, QString::fromStdString(m_settings.gpu_adapter),
|
||||
m_settings.gpu_use_debug_device, m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!display_widget || !m_display->HasRenderDevice())
|
||||
{
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getHostDisplay()->activateDeviceContext() ||
|
||||
!getHostDisplay()->initializeDeviceContext(GetShaderCacheDirectory(), m_settings.gpu_use_debug_device))
|
||||
createImGuiContext(display_widget->devicePixelRatioFromScreen());
|
||||
|
||||
if (!m_display->MakeRenderContextCurrent() ||
|
||||
!m_display->InitializeRenderDevice(GetShaderCacheDirectory(), m_settings.gpu_use_debug_device))
|
||||
{
|
||||
getHostDisplay()->destroyDeviceContext();
|
||||
destroyImGuiContext();
|
||||
m_display->DestroyRenderDevice();
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
m_display.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
connectDisplaySignals();
|
||||
connectDisplaySignals(display_widget);
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
QtHostDisplay* QtHostInterface::createHostDisplay()
|
||||
HostDisplay* QtHostInterface::createHostDisplay()
|
||||
{
|
||||
Assert(!getHostDisplay());
|
||||
|
||||
switch (m_settings.gpu_renderer)
|
||||
{
|
||||
case GPURenderer::HardwareVulkan:
|
||||
m_display = new VulkanHostDisplay(this);
|
||||
m_display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
|
||||
break;
|
||||
|
||||
case GPURenderer::HardwareOpenGL:
|
||||
#ifndef WIN32
|
||||
default:
|
||||
#endif
|
||||
m_display = new OpenGLHostDisplay(this);
|
||||
m_display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
|
||||
break;
|
||||
|
||||
#ifdef WIN32
|
||||
case GPURenderer::HardwareD3D11:
|
||||
default:
|
||||
m_display = new D3D11HostDisplay(this);
|
||||
m_display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return getHostDisplay();
|
||||
return m_display.get();
|
||||
}
|
||||
|
||||
void QtHostInterface::connectDisplaySignals()
|
||||
void QtHostInterface::connectDisplaySignals(QtDisplayWidget* widget)
|
||||
{
|
||||
QtDisplayWidget* widget = getHostDisplay()->getWidget();
|
||||
widget->disconnect(this);
|
||||
|
||||
connect(widget, &QtDisplayWidget::windowResizedEvent, this, &QtHostInterface::onHostDisplayWindowResized);
|
||||
connect(widget, &QtDisplayWidget::windowRestoredEvent, this, &QtHostInterface::redrawDisplayWindow);
|
||||
connect(widget, &QtDisplayWidget::windowClosedEvent, this, &QtHostInterface::powerOffSystem,
|
||||
|
@ -380,21 +381,16 @@ void QtHostInterface::connectDisplaySignals()
|
|||
connect(widget, &QtDisplayWidget::windowMouseButtonEvent, this, &QtHostInterface::onDisplayWindowMouseButtonEvent);
|
||||
}
|
||||
|
||||
void QtHostInterface::disconnectDisplaySignals()
|
||||
{
|
||||
getHostDisplay()->getWidget()->disconnect(this);
|
||||
}
|
||||
|
||||
void QtHostInterface::updateDisplayState()
|
||||
{
|
||||
// this expects the context to get moved back to us afterwards
|
||||
getHostDisplay()->deactivateDeviceContext();
|
||||
emit updateDisplayRequested(m_worker_thread, m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!getHostDisplay()->activateDeviceContext())
|
||||
m_display->DoneRenderContextCurrent();
|
||||
|
||||
QtDisplayWidget* display_widget = updateDisplayRequested(m_worker_thread, m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!display_widget || !m_display->MakeRenderContextCurrent())
|
||||
Panic("Failed to make device context current after updating");
|
||||
|
||||
getHostDisplay()->updateImGuiDisplaySize();
|
||||
connectDisplaySignals();
|
||||
connectDisplaySignals(display_widget);
|
||||
redrawDisplayWindow();
|
||||
UpdateSpeedLimiterState();
|
||||
}
|
||||
|
@ -403,9 +399,10 @@ void QtHostInterface::ReleaseHostDisplay()
|
|||
{
|
||||
Assert(m_display);
|
||||
|
||||
getHostDisplay()->destroyDeviceContext();
|
||||
m_display->DestroyRenderDevice();
|
||||
destroyImGuiContext();
|
||||
emit destroyDisplayRequested();
|
||||
m_display = nullptr;
|
||||
m_display.reset();
|
||||
m_is_fullscreen = false;
|
||||
}
|
||||
|
||||
|
@ -938,6 +935,7 @@ void QtHostInterface::renderDisplay()
|
|||
DrawImGuiWindows();
|
||||
|
||||
m_display->Render();
|
||||
ImGui::NewFrame();
|
||||
|
||||
m_system->GetGPU()->RestoreGraphicsAPIState();
|
||||
}
|
||||
|
@ -950,6 +948,25 @@ void QtHostInterface::wakeThread()
|
|||
QMetaObject::invokeMethod(m_worker_thread_event_loop, "quit", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void QtHostInterface::createImGuiContext(float framebuffer_scale)
|
||||
{
|
||||
ImGui::CreateContext();
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
io.DisplayFramebufferScale.x = framebuffer_scale;
|
||||
io.DisplayFramebufferScale.y = framebuffer_scale;
|
||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||
|
||||
ImGui::StyleColorsDarker();
|
||||
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale);
|
||||
}
|
||||
|
||||
void QtHostInterface::destroyImGuiContext()
|
||||
{
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
QtHostInterface::Thread::Thread(QtHostInterface* parent) : QThread(parent), m_parent(parent) {}
|
||||
|
||||
QtHostInterface::Thread::~Thread() = default;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "frontend-common/common_host_interface.h"
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QThread>
|
||||
#include <atomic>
|
||||
|
@ -25,8 +26,7 @@ class QTimer;
|
|||
class GameList;
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class QtHostDisplay;
|
||||
class QtDisplayWidget;
|
||||
|
||||
Q_DECLARE_METATYPE(SystemBootParameters);
|
||||
|
||||
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
ALWAYS_INLINE MainWindow* getMainWindow() const { return m_main_window; }
|
||||
void setMainWindow(MainWindow* window);
|
||||
QtHostDisplay* createHostDisplay();
|
||||
HostDisplay* createHostDisplay();
|
||||
|
||||
void populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu);
|
||||
|
||||
|
@ -96,9 +96,9 @@ Q_SIGNALS:
|
|||
void emulationPaused(bool paused);
|
||||
void stateSaved(const QString& game_code, bool global, qint32 slot);
|
||||
void gameListRefreshed();
|
||||
void createDisplayRequested(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
|
||||
bool fullscreen, bool render_to_main);
|
||||
void updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
||||
QtDisplayWidget* createDisplayRequested(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
|
||||
bool fullscreen, bool render_to_main);
|
||||
QtDisplayWidget* 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,
|
||||
|
@ -186,21 +186,21 @@ private:
|
|||
Common::Event m_init_event;
|
||||
};
|
||||
|
||||
QtHostDisplay* getHostDisplay();
|
||||
|
||||
void createBackgroundControllerPollTimer();
|
||||
void destroyBackgroundControllerPollTimer();
|
||||
void startBackgroundControllerPollTimer();
|
||||
void stopBackgroundControllerPollTimer();
|
||||
|
||||
void createImGuiContext(float framebuffer_scale);
|
||||
void destroyImGuiContext();
|
||||
|
||||
void createThread();
|
||||
void stopThread();
|
||||
void threadEntryPoint();
|
||||
bool initializeOnThread();
|
||||
void shutdownOnThread();
|
||||
void renderDisplay();
|
||||
void connectDisplaySignals();
|
||||
void disconnectDisplaySignals();
|
||||
void connectDisplaySignals(QtDisplayWidget* widget);
|
||||
void updateDisplayState();
|
||||
void wakeThread();
|
||||
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
#include "vulkanhostdisplay.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
Log_SetChannel(VulkanHostDisplay);
|
||||
|
||||
VulkanHostDisplay::VulkanHostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {}
|
||||
|
||||
VulkanHostDisplay::~VulkanHostDisplay() = default;
|
||||
|
||||
HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_vulkan_display.GetRenderAPI();
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_vulkan_display.GetRenderDevice();
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_vulkan_display.GetRenderContext();
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> VulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
return m_vulkan_display.CreateTexture(width, height, initial_data, initial_data_stride, dynamic);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
m_vulkan_display.UpdateTexture(texture, x, y, width, height, texture_data, texture_data_stride);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride)
|
||||
{
|
||||
return m_vulkan_display.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::SetVSync(bool enabled)
|
||||
{
|
||||
m_vulkan_display.SetVSync(enabled);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::hasDeviceContext() const
|
||||
{
|
||||
return m_vulkan_display.HasContext();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device)
|
||||
{
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi || !m_vulkan_display.CreateContextAndSwapChain(wi.value(), adapter_name.toStdString(), debug_device))
|
||||
return false;
|
||||
|
||||
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_vulkan_display.GetSwapChainHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
m_vulkan_display.CreateShaderCache(shader_cache_directory, debug_device);
|
||||
|
||||
return QtHostDisplay::initializeDeviceContext(shader_cache_directory, debug_device);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::activateDeviceContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::deactivateDeviceContext() {}
|
||||
|
||||
void VulkanHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
m_vulkan_display.DestroyShaderCache();
|
||||
m_vulkan_display.DestroySwapChain();
|
||||
m_vulkan_display.DestroyContext();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::recreateSurface()
|
||||
{
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
return false;
|
||||
|
||||
if (!m_vulkan_display.RecreateSwapChain(wi.value()))
|
||||
return false;
|
||||
|
||||
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_vulkan_display.GetSwapChainHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::destroySurface()
|
||||
{
|
||||
m_vulkan_display.DestroySwapChain();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
QtHostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
|
||||
m_vulkan_display.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_width = static_cast<s32>(m_vulkan_display.GetSwapChainWidth());
|
||||
m_window_height = static_cast<s32>(m_vulkan_display.GetSwapChainHeight());
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::createDeviceResources()
|
||||
{
|
||||
if (!QtHostDisplay::createDeviceResources())
|
||||
return false;
|
||||
|
||||
return m_vulkan_display.CreateResources();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::destroyDeviceResources()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceResources();
|
||||
m_vulkan_display.DestroyResources();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::createImGuiContext()
|
||||
{
|
||||
if (!QtHostDisplay::createImGuiContext() || !m_vulkan_display.CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::destroyImGuiContext()
|
||||
{
|
||||
m_vulkan_display.DestroyImGuiContext();
|
||||
QtHostDisplay::destroyImGuiContext();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::Render()
|
||||
{
|
||||
if (!m_vulkan_display.HasSwapChain() || !m_vulkan_display.BeginRender())
|
||||
return;
|
||||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
m_vulkan_display.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height,
|
||||
m_display_linear_filtering);
|
||||
}
|
||||
|
||||
m_vulkan_display.RenderImGui();
|
||||
|
||||
if (HasSoftwareCursor())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
m_vulkan_display.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
m_vulkan_display.EndRenderAndPresent();
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include "frontend-common/vulkan_host_display.h"
|
||||
#include <memory>
|
||||
|
||||
class QtHostInterface;
|
||||
|
||||
class VulkanHostDisplay final : public QtHostDisplay
|
||||
{
|
||||
public:
|
||||
VulkanHostDisplay(QtHostInterface* host_interface);
|
||||
~VulkanHostDisplay();
|
||||
|
||||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(const QString& adapter_name, bool debug_device) override;
|
||||
bool initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
bool activateDeviceContext() override;
|
||||
void deactivateDeviceContext() override;
|
||||
void destroyDeviceContext() override;
|
||||
bool recreateSurface() override;
|
||||
void destroySurface();
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
bool createImGuiContext() override;
|
||||
void destroyImGuiContext() override;
|
||||
bool createDeviceResources() override;
|
||||
void destroyDeviceResources() override;
|
||||
|
||||
FrontendCommon::VulkanHostDisplay m_vulkan_display;
|
||||
};
|
|
@ -2,15 +2,11 @@ add_executable(duckstation-sdl
|
|||
imgui_impl_sdl.cpp
|
||||
imgui_impl_sdl.h
|
||||
main.cpp
|
||||
opengl_host_display.cpp
|
||||
opengl_host_display.h
|
||||
sdl_host_interface.cpp
|
||||
sdl_host_interface.h
|
||||
sdl_key_names.h
|
||||
sdl_util.cpp
|
||||
sdl_util.h
|
||||
sdl_vulkan_host_display.cpp
|
||||
sdl_vulkan_host_display.h
|
||||
)
|
||||
|
||||
target_include_directories(duckstation-sdl PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||
|
@ -18,8 +14,6 @@ target_link_libraries(duckstation-sdl PRIVATE core common imgui nativefiledialog
|
|||
|
||||
if(WIN32)
|
||||
target_sources(duckstation-sdl PRIVATE
|
||||
sdl_d3d11_host_display.cpp
|
||||
sdl_d3d11_host_display.h
|
||||
duckstation-sdl.manifest
|
||||
)
|
||||
|
||||
|
|
|
@ -55,23 +55,17 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sdl_d3d11_host_display.cpp" />
|
||||
<ClCompile Include="imgui_impl_sdl.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
<ClCompile Include="sdl_host_interface.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="sdl_util.cpp" />
|
||||
<ClCompile Include="sdl_vulkan_host_display.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="sdl_d3d11_host_display.h" />
|
||||
<ClInclude Include="imgui_impl_sdl.h" />
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="sdl_host_interface.h" />
|
||||
<ClInclude Include="sdl_key_names.h" />
|
||||
<ClInclude Include="sdl_util.h" />
|
||||
<ClInclude Include="sdl_vulkan_host_display.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="duckstation-sdl.manifest" />
|
||||
|
|
|
@ -2,22 +2,16 @@
|
|||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
<ClCompile Include="sdl_host_interface.cpp" />
|
||||
<ClCompile Include="imgui_impl_sdl.cpp" />
|
||||
<ClCompile Include="sdl_util.cpp" />
|
||||
<ClCompile Include="sdl_vulkan_host_display.cpp" />
|
||||
<ClCompile Include="sdl_d3d11_host_display.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
<ClInclude Include="sdl_host_interface.h" />
|
||||
<ClInclude Include="imgui_impl_sdl.h" />
|
||||
<ClInclude Include="sdl_key_names.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="sdl_util.h" />
|
||||
<ClInclude Include="sdl_vulkan_host_display.h" />
|
||||
<ClInclude Include="sdl_d3d11_host_display.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="duckstation-sdl.manifest" />
|
||||
|
|
|
@ -1,369 +0,0 @@
|
|||
#include "opengl_host_display.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "sdl_util.h"
|
||||
#include <SDL_syswm.h>
|
||||
#include <array>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <tuple>
|
||||
Log_SetChannel(OpenGLHostDisplay);
|
||||
|
||||
class OpenGLDisplayWidgetTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
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; }
|
||||
u32 GetHeight() const override { return m_height; }
|
||||
|
||||
GLuint GetGLID() const { return m_id; }
|
||||
|
||||
static std::unique_ptr<OpenGLDisplayWidgetTexture> Create(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride)
|
||||
{
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
GLint old_texture_binding = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
||||
|
||||
// TODO: Set pack width
|
||||
Assert(!initial_data || initial_data_stride == (width * sizeof(u32)));
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, initial_data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
return std::make_unique<OpenGLDisplayWidgetTexture>(id, width, height);
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint m_id;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
};
|
||||
|
||||
OpenGLHostDisplay::OpenGLHostDisplay(SDL_Window* window) : m_window(window)
|
||||
{
|
||||
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
|
||||
}
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
{
|
||||
if (m_gl_context)
|
||||
{
|
||||
if (m_display_vao != 0)
|
||||
glDeleteVertexArrays(1, &m_display_vao);
|
||||
if (m_display_linear_sampler != 0)
|
||||
glDeleteSamplers(1, &m_display_linear_sampler);
|
||||
if (m_display_nearest_sampler != 0)
|
||||
glDeleteSamplers(1, &m_display_nearest_sampler);
|
||||
|
||||
m_display_program.Destroy();
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
if (m_window)
|
||||
SDL_DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->IsGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
HostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
|
||||
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
|
||||
u32 data_stride, bool dynamic)
|
||||
{
|
||||
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)
|
||||
{
|
||||
OpenGLDisplayWidgetTexture* tex = static_cast<OpenGLDisplayWidgetTexture*>(texture);
|
||||
Assert((data_stride % sizeof(u32)) == 0);
|
||||
|
||||
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding);
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
|
||||
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &old_row_length);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex->GetGLID());
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, data_stride / sizeof(u32));
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
|
||||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||
}
|
||||
|
||||
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);
|
||||
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_row_length);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, sizeof(u32));
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, out_data_stride / sizeof(u32));
|
||||
|
||||
const GLuint texture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle));
|
||||
GL::Texture::GetTextureSubImage(texture, 0, x, y, 0, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
height * out_data_stride, out_data);
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, old_alignment);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, old_row_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
m_gl_context->SetSwapInterval(enabled ? 1 : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_0)
|
||||
return "#version 300 es";
|
||||
else
|
||||
return "#version 100";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GLAD_GL_VERSION_3_3)
|
||||
return "#version 330";
|
||||
else
|
||||
return "#version 130";
|
||||
}
|
||||
}
|
||||
|
||||
std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
||||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
header += "precision highp float;\n";
|
||||
header += "precision highp int;\n\n";
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
|
||||
const GLchar* message, const void* userParam)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH_KHR:
|
||||
Log_ErrorPrintf(message);
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM_KHR:
|
||||
Log_WarningPrint(message);
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_LOW_KHR:
|
||||
Log_InfoPrintf(message);
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
||||
// Log_DebugPrint(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
|
||||
{
|
||||
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
|
||||
if (!wi)
|
||||
return false;
|
||||
|
||||
m_gl_context = GL::Context::Create(wi.value());
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create a GL context of any kind.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debug_device && GLAD_GL_KHR_debug)
|
||||
{
|
||||
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
// this can change due to retina scaling on macos?
|
||||
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
|
||||
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
|
||||
|
||||
// start with vsync on
|
||||
m_gl_context->SetSwapInterval(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, nullptr) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
return false;
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateGLResources()
|
||||
{
|
||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||
uniform vec4 u_src_rect;
|
||||
out vec2 v_tex0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
||||
v_tex0 = u_src_rect.xy + pos * u_src_rect.zw;
|
||||
gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
|
||||
}
|
||||
)";
|
||||
|
||||
static constexpr char display_fragment_shader[] = R"(
|
||||
uniform sampler2D samp0;
|
||||
|
||||
in vec2 v_tex0;
|
||||
out vec4 o_col0;
|
||||
|
||||
void main()
|
||||
{
|
||||
o_col0 = texture(samp0, v_tex0);
|
||||
}
|
||||
)";
|
||||
|
||||
if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {},
|
||||
GetGLSLVersionHeader() + display_fragment_shader))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to compile display shaders");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_gl_context->IsGLES())
|
||||
m_display_program.BindFragData(0, "o_col0");
|
||||
|
||||
if (!m_display_program.Link())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to link display program");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_display_program.Bind();
|
||||
m_display_program.RegisterUniform("u_src_rect");
|
||||
m_display_program.RegisterUniform("samp0");
|
||||
m_display_program.Uniform1i(1, 0);
|
||||
|
||||
glGenVertexArrays(1, &m_display_vao);
|
||||
|
||||
// samplers
|
||||
glGenSamplers(1, &m_display_nearest_sampler);
|
||||
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glGenSamplers(1, &m_display_linear_sampler);
|
||||
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplay> OpenGLHostDisplay::Create(SDL_Window* window, bool debug_device)
|
||||
{
|
||||
std::unique_ptr<OpenGLHostDisplay> display = std::make_unique<OpenGLHostDisplay>(window);
|
||||
if (!display->CreateGLContext(debug_device) || !display->CreateImGuiContext() || !display->CreateGLResources())
|
||||
return nullptr;
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::Render()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
RenderDisplay();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
||||
GL::Program::ResetLastProgram();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
glViewport(vp_left, m_window_height - vp_top - vp_height, vp_width, vp_height);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
m_display_program.Bind();
|
||||
m_display_program.Uniform4f(
|
||||
0, static_cast<float>(m_display_texture_view_x) / static_cast<float>(m_display_texture_width),
|
||||
static_cast<float>(m_display_texture_view_y) / static_cast<float>(m_display_texture_height),
|
||||
(static_cast<float>(m_display_texture_view_width) - 0.5f) / static_cast<float>(m_display_texture_width),
|
||||
(static_cast<float>(m_display_texture_view_height) + 0.5f) / static_cast<float>(m_display_texture_height));
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(m_display_texture_handle)));
|
||||
glBindSampler(0, m_display_linear_filtering ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindSampler(0, 0);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "core/host_display.h"
|
||||
#include <SDL.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class OpenGLHostDisplay final : public HostDisplay
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplay(SDL_Window* window);
|
||||
~OpenGLHostDisplay();
|
||||
|
||||
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, bool debug_device);
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* 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;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
bool CreateGLContext(bool debug_device);
|
||||
bool CreateImGuiContext();
|
||||
bool CreateGLResources();
|
||||
|
||||
void RenderDisplay();
|
||||
|
||||
SDL_Window* m_window = nullptr;
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
|
||||
GL::Program m_display_program;
|
||||
GLuint m_display_vao = 0;
|
||||
GLuint m_display_nearest_sampler = 0;
|
||||
GLuint m_display_linear_sampler = 0;
|
||||
};
|
|
@ -1,121 +0,0 @@
|
|||
#include "sdl_d3d11_host_display.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "sdl_util.h"
|
||||
#include <SDL_syswm.h>
|
||||
#include <array>
|
||||
#include <dxgi1_5.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_dx11.h>
|
||||
|
||||
SDLD3D11HostDisplay::SDLD3D11HostDisplay(SDL_Window* window) : m_window(window)
|
||||
{
|
||||
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
|
||||
}
|
||||
|
||||
SDLD3D11HostDisplay::~SDLD3D11HostDisplay()
|
||||
{
|
||||
if (m_window)
|
||||
SDL_DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplay> SDLD3D11HostDisplay::Create(SDL_Window* window, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
std::unique_ptr<SDLD3D11HostDisplay> display = std::make_unique<SDLD3D11HostDisplay>(window);
|
||||
if (!display->Initialize(adapter_name, debug_device))
|
||||
return {};
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI SDLD3D11HostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_interface.GetRenderAPI();
|
||||
}
|
||||
|
||||
void* SDLD3D11HostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_interface.GetRenderDevice();
|
||||
}
|
||||
|
||||
void* SDLD3D11HostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_interface.GetRenderContext();
|
||||
}
|
||||
|
||||
void SDLD3D11HostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
m_interface.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
HostDisplay::WindowResized(static_cast<s32>(m_interface.GetSwapChainWidth()),
|
||||
static_cast<s32>(m_interface.GetSwapChainHeight()));
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_interface.GetSwapChainWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_interface.GetSwapChainHeight());
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> SDLD3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* data,
|
||||
u32 data_stride, bool dynamic)
|
||||
{
|
||||
return m_interface.CreateTexture(width, height, data, data_stride, dynamic);
|
||||
}
|
||||
|
||||
void SDLD3D11HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* data, u32 data_stride)
|
||||
{
|
||||
m_interface.UpdateTexture(texture, x, y, width, height, data, data_stride);
|
||||
}
|
||||
|
||||
bool SDLD3D11HostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||
void* out_data, u32 out_data_stride)
|
||||
{
|
||||
return m_interface.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
|
||||
}
|
||||
|
||||
void SDLD3D11HostDisplay::SetVSync(bool enabled)
|
||||
{
|
||||
m_interface.SetVSync(enabled);
|
||||
}
|
||||
|
||||
bool SDLD3D11HostDisplay::Initialize(std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
|
||||
if (!wi.has_value())
|
||||
return false;
|
||||
|
||||
if (!m_interface.CreateContextAndSwapChain(wi.value(), adapter_name, true, debug_device))
|
||||
return false;
|
||||
|
||||
if (!m_interface.CreateResources())
|
||||
return false;
|
||||
|
||||
if (!m_interface.CreateImGuiContext() || !ImGui_ImplSDL2_InitForVulkan(m_window))
|
||||
return false;
|
||||
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLD3D11HostDisplay::Render()
|
||||
{
|
||||
if (!m_interface.BeginRender())
|
||||
return;
|
||||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
m_interface.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
m_interface.RenderImGui();
|
||||
|
||||
if (HasSoftwareCursor())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
m_interface.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
m_interface.EndRenderAndPresent();
|
||||
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#pragma once
|
||||
#include "core/host_display.h"
|
||||
#include "frontend-common/d3d11_host_display.h"
|
||||
#include <SDL.h>
|
||||
|
||||
class SDLD3D11HostDisplay final : public HostDisplay
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||
|
||||
SDLD3D11HostDisplay(SDL_Window* window);
|
||||
~SDLD3D11HostDisplay();
|
||||
|
||||
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, std::string_view adapter_name, bool debug_device);
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* 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;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
SDL_Window* m_window = nullptr;
|
||||
|
||||
FrontendCommon::D3D11HostDisplay m_interface;
|
||||
|
||||
bool Initialize(std::string_view adapter_name, bool debug_device);
|
||||
};
|
|
@ -11,13 +11,14 @@
|
|||
#include "frontend-common/icon.h"
|
||||
#include "frontend-common/imgui_styles.h"
|
||||
#include "frontend-common/ini_settings_interface.h"
|
||||
#include "frontend-common/opengl_host_display.h"
|
||||
#include "frontend-common/sdl_audio_stream.h"
|
||||
#include "frontend-common/sdl_controller_interface.h"
|
||||
#include "frontend-common/vulkan_host_display.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "opengl_host_display.h"
|
||||
#include "scmversion/scmversion.h"
|
||||
#include "sdl_key_names.h"
|
||||
#include "sdl_vulkan_host_display.h"
|
||||
#include "sdl_util.h"
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <imgui.h>
|
||||
|
@ -26,7 +27,7 @@
|
|||
Log_SetChannel(SDLHostInterface);
|
||||
|
||||
#ifdef WIN32
|
||||
#include "sdl_d3d11_host_display.h"
|
||||
#include "frontend-common/d3d11_host_display.h"
|
||||
#endif
|
||||
|
||||
SDLHostInterface::SDLHostInterface()
|
||||
|
@ -129,49 +130,86 @@ void SDLHostInterface::DestroySDLWindow()
|
|||
|
||||
bool SDLHostInterface::CreateDisplay()
|
||||
{
|
||||
const std::string shader_cache_directory(GetShaderCacheDirectory());
|
||||
std::unique_ptr<HostDisplay> display;
|
||||
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
|
||||
if (!wi.has_value())
|
||||
{
|
||||
ReportError("Failed to get window info from SDL window");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplay> display;
|
||||
switch (m_settings.gpu_renderer)
|
||||
{
|
||||
case GPURenderer::HardwareVulkan:
|
||||
display = SDLVulkanHostDisplay::Create(m_window, m_settings.gpu_adapter, shader_cache_directory,
|
||||
m_settings.gpu_use_debug_device);
|
||||
display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
|
||||
break;
|
||||
|
||||
case GPURenderer::HardwareOpenGL:
|
||||
#ifndef WIN32
|
||||
default:
|
||||
#endif
|
||||
display = OpenGLHostDisplay::Create(m_window, m_settings.gpu_use_debug_device);
|
||||
display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
|
||||
break;
|
||||
|
||||
#ifdef WIN32
|
||||
case GPURenderer::HardwareD3D11:
|
||||
default:
|
||||
display = SDLD3D11HostDisplay::Create(m_window, m_settings.gpu_adapter, m_settings.gpu_use_debug_device);
|
||||
display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!display)
|
||||
Assert(display);
|
||||
if (!display->CreateRenderDevice(wi.value(), m_settings.gpu_adapter, m_settings.gpu_use_debug_device) ||
|
||||
!display->InitializeRenderDevice(GetShaderCacheDirectory(), m_settings.gpu_use_debug_device))
|
||||
{
|
||||
ReportError("Failed to create/initialize display render device");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool imgui_result;
|
||||
switch (display->GetRenderAPI())
|
||||
{
|
||||
#ifdef WIN32
|
||||
case HostDisplay::RenderAPI::D3D11:
|
||||
imgui_result = ImGui_ImplSDL2_InitForD3D(m_window);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case HostDisplay::RenderAPI::Vulkan:
|
||||
imgui_result = ImGui_ImplSDL2_InitForVulkan(m_window);
|
||||
break;
|
||||
|
||||
case HostDisplay::RenderAPI::OpenGL:
|
||||
case HostDisplay::RenderAPI::OpenGLES:
|
||||
imgui_result = ImGui_ImplSDL2_InitForOpenGL(m_window, nullptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
imgui_result = true;
|
||||
break;
|
||||
}
|
||||
if (!imgui_result)
|
||||
{
|
||||
ReportError("Failed to initialize ImGui SDL2 wrapper");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_app_icon_texture =
|
||||
display->CreateTexture(APP_ICON_WIDTH, APP_ICON_HEIGHT, APP_ICON_DATA, APP_ICON_WIDTH * sizeof(u32));
|
||||
if (!display)
|
||||
if (!m_app_icon_texture)
|
||||
return false;
|
||||
|
||||
display->SetDisplayTopMargin(m_fullscreen ? 0 : static_cast<int>(20.0f * ImGui::GetIO().DisplayFramebufferScale.x));
|
||||
m_display = display.release();
|
||||
m_display = std::move(display);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLHostInterface::DestroyDisplay()
|
||||
{
|
||||
m_app_icon_texture.reset();
|
||||
delete m_display;
|
||||
m_display = nullptr;
|
||||
m_display->DestroyRenderDevice();
|
||||
m_display.reset();
|
||||
}
|
||||
|
||||
void SDLHostInterface::CreateImGuiContext()
|
||||
|
@ -227,13 +265,16 @@ bool SDLHostInterface::AcquireHostDisplay()
|
|||
{
|
||||
ImGui::EndFrame();
|
||||
DestroyDisplay();
|
||||
DestroySDLWindow();
|
||||
|
||||
// We need to recreate the window, otherwise bad things happen...
|
||||
DestroySDLWindow();
|
||||
if (!CreateSDLWindow())
|
||||
Panic("Failed to recreate SDL window on GPU renderer switch");
|
||||
|
||||
if (!CreateDisplay())
|
||||
Panic("Failed to recreate display on GPU renderer switch");
|
||||
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -357,7 +398,7 @@ bool SDLHostInterface::SetFullscreen(bool enabled)
|
|||
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||
m_display->WindowResized(window_width, window_height);
|
||||
m_display->ResizeRenderWindow(window_width, window_height);
|
||||
m_fullscreen = enabled;
|
||||
return true;
|
||||
}
|
||||
|
@ -389,6 +430,8 @@ bool SDLHostInterface::Initialize()
|
|||
return false;
|
||||
}
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
RegisterHotkeys();
|
||||
|
||||
// process events to pick up controllers before updating input map
|
||||
|
@ -488,7 +531,7 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
|||
{
|
||||
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
||||
{
|
||||
m_display->WindowResized(event->window.data1, event->window.data2);
|
||||
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
|
||||
UpdateFramebufferScale();
|
||||
}
|
||||
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
|
||||
|
@ -1492,6 +1535,8 @@ void SDLHostInterface::Run()
|
|||
m_system->GetGPU()->ResetGraphicsAPIState();
|
||||
|
||||
m_display->Render();
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
ImGui::NewFrame();
|
||||
|
||||
if (m_system)
|
||||
{
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
#include "sdl_vulkan_host_display.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_vulkan.h"
|
||||
#include "sdl_util.h"
|
||||
#include <SDL_syswm.h>
|
||||
#include <array>
|
||||
Log_SetChannel(VulkanHostDisplay);
|
||||
|
||||
SDLVulkanHostDisplay::SDLVulkanHostDisplay(SDL_Window* window) : m_window(window)
|
||||
{
|
||||
SDL_GetWindowSize(window, &m_window_width, &m_window_height);
|
||||
}
|
||||
|
||||
SDLVulkanHostDisplay::~SDLVulkanHostDisplay()
|
||||
{
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
m_display.DestroyImGuiContext();
|
||||
m_display.DestroyResources();
|
||||
m_display.DestroyShaderCache();
|
||||
m_display.DestroySwapChain();
|
||||
m_display.DestroyContext();
|
||||
|
||||
if (m_window)
|
||||
SDL_DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplay> SDLVulkanHostDisplay::Create(SDL_Window* window, std::string_view adapter_name,
|
||||
std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
std::unique_ptr<SDLVulkanHostDisplay> display = std::make_unique<SDLVulkanHostDisplay>(window);
|
||||
if (!display->Initialize(adapter_name, shader_cache_directory, debug_device))
|
||||
return nullptr;
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI SDLVulkanHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_display.GetRenderAPI();
|
||||
}
|
||||
|
||||
void* SDLVulkanHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_display.GetRenderDevice();
|
||||
}
|
||||
|
||||
void* SDLVulkanHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_display.GetRenderContext();
|
||||
}
|
||||
|
||||
void SDLVulkanHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
m_display.ResizeSwapChain(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
HostDisplay::WindowResized(static_cast<s32>(m_display.GetSwapChainWidth()),
|
||||
static_cast<s32>(m_display.GetSwapChainHeight()));
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_display.GetSwapChainWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_display.GetSwapChainHeight());
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> SDLVulkanHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
|
||||
u32 data_stride, bool dynamic /*= false*/)
|
||||
{
|
||||
return m_display.CreateTexture(width, height, data, data_stride, dynamic);
|
||||
}
|
||||
|
||||
void SDLVulkanHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* data, u32 data_stride)
|
||||
{
|
||||
m_display.UpdateTexture(texture, x, y, width, height, data, data_stride);
|
||||
}
|
||||
|
||||
bool SDLVulkanHostDisplay::DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height,
|
||||
void* out_data, u32 out_data_stride)
|
||||
{
|
||||
return m_display.DownloadTexture(texture_handle, x, y, width, height, out_data, out_data_stride);
|
||||
}
|
||||
|
||||
void SDLVulkanHostDisplay::SetVSync(bool enabled)
|
||||
{
|
||||
m_display.SetVSync(enabled);
|
||||
}
|
||||
|
||||
bool SDLVulkanHostDisplay::Initialize(std::string_view adapter_name, std::string_view shader_cache_directory,
|
||||
bool debug_device)
|
||||
{
|
||||
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
|
||||
if (!wi.has_value())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to get window info for SDL window");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_display.CreateContextAndSwapChain(wi.value(), adapter_name, debug_device))
|
||||
return false;
|
||||
|
||||
m_display.CreateShaderCache(shader_cache_directory, debug_device);
|
||||
|
||||
if (!m_display.CreateResources())
|
||||
return false;
|
||||
|
||||
if (!m_display.CreateImGuiContext() || !ImGui_ImplSDL2_InitForVulkan(m_window))
|
||||
return false;
|
||||
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLVulkanHostDisplay::Render()
|
||||
{
|
||||
if (!m_display.BeginRender())
|
||||
return;
|
||||
|
||||
if (HasDisplayTexture())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
m_display.RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
m_display.RenderImGui();
|
||||
|
||||
if (HasSoftwareCursor())
|
||||
{
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
m_display.RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
m_display.EndRenderAndPresent();
|
||||
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#pragma once
|
||||
#include "core/host_display.h"
|
||||
#include "frontend-common/vulkan_host_display.h"
|
||||
#include <SDL.h>
|
||||
#include <string_view>
|
||||
|
||||
class SDLVulkanHostDisplay final : public HostDisplay
|
||||
{
|
||||
public:
|
||||
SDLVulkanHostDisplay(SDL_Window* window);
|
||||
~SDLVulkanHostDisplay();
|
||||
|
||||
static std::unique_ptr<HostDisplay> Create(SDL_Window* window, std::string_view adapter_name,
|
||||
std::string_view shader_cache_directory, bool debug_device);
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
|
||||
bool dynamic = false) override;
|
||||
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 data_stride) override;
|
||||
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
bool Initialize(std::string_view adapter_name, std::string_view shader_cache_directory, bool debug_device);
|
||||
|
||||
SDL_Window* m_window = nullptr;
|
||||
FrontendCommon::VulkanHostDisplay m_display;
|
||||
};
|
|
@ -9,13 +9,15 @@ add_library(frontend-common
|
|||
imgui_styles.h
|
||||
ini_settings_interface.cpp
|
||||
ini_settings_interface.h
|
||||
opengl_host_display.cpp
|
||||
opengl_host_display.h
|
||||
save_state_selector_ui.cpp
|
||||
save_state_selector_ui.h
|
||||
vulkan_host_display.cpp
|
||||
vulkan_host_display.h
|
||||
)
|
||||
|
||||
target_link_libraries(frontend-common PUBLIC core common imgui simpleini scmversion vulkan-loader)
|
||||
target_link_libraries(frontend-common PUBLIC core common imgui simpleini scmversion glad vulkan-loader)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(frontend-common PRIVATE
|
||||
|
@ -25,7 +27,7 @@ if(WIN32)
|
|||
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
|
||||
endif()
|
||||
|
||||
if(SDL2_FOUND)
|
||||
if(SDL2_FOUND AND NOT BUILD_LIBRETRO_CORE)
|
||||
target_sources(frontend-common PRIVATE
|
||||
sdl_audio_stream.cpp
|
||||
sdl_audio_stream.h
|
||||
|
@ -45,7 +47,7 @@ if(SDL2_FOUND)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_DISCORD_PRESENCE)
|
||||
if(ENABLE_DISCORD_PRESENCE AND NOT BUILD_LIBRETRO_CORE)
|
||||
target_compile_definitions(frontend-common PUBLIC -DWITH_DISCORD_PRESENCE=1)
|
||||
target_link_libraries(frontend-common PRIVATE discord-rpc)
|
||||
endif()
|
||||
|
|
|
@ -1814,8 +1814,8 @@ void CommonHostInterface::DisplayLoadingScreen(const char* message, int progress
|
|||
const bool has_progress = (progress_min < progress_max);
|
||||
|
||||
// eat the last imgui frame, it might've been partially rendered by the caller.
|
||||
ImGui::EndFrame();
|
||||
ImGui::NewFrame();
|
||||
//ImGui::EndFrame();
|
||||
//ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(width, (has_progress ? 50.0f : 30.0f) * scale), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always,
|
||||
|
@ -1843,6 +1843,7 @@ void CommonHostInterface::DisplayLoadingScreen(const char* message, int progress
|
|||
ImGui::End();
|
||||
|
||||
m_display->Render();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void CommonHostInterface::GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title)
|
||||
|
|
|
@ -67,7 +67,36 @@ private:
|
|||
|
||||
D3D11HostDisplay::D3D11HostDisplay() = default;
|
||||
|
||||
D3D11HostDisplay::~D3D11HostDisplay() = default;
|
||||
D3D11HostDisplay::~D3D11HostDisplay()
|
||||
{
|
||||
AssertMsg(!m_context, "Context should have been destroyed by now");
|
||||
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return HostDisplay::RenderAPI::D3D11;
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return m_device.Get();
|
||||
}
|
||||
|
||||
void* D3D11HostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_context.Get();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_device);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D11HostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
|
@ -135,13 +164,7 @@ void D3D11HostDisplay::SetVSync(bool enabled)
|
|||
m_vsync = enabled;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::HasContext() const
|
||||
{
|
||||
return static_cast<bool>(m_device);
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name,
|
||||
bool use_flip_model, bool debug_device)
|
||||
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
UINT create_flags = 0;
|
||||
if (debug_device)
|
||||
|
@ -242,24 +265,53 @@ bool D3D11HostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::stri
|
|||
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
|
||||
}
|
||||
|
||||
return CreateSwapChain(wi, use_flip_model);
|
||||
m_window_info = wi;
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyContext()
|
||||
bool D3D11HostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
Assert(!m_swap_chain);
|
||||
if (!CreateSwapChain())
|
||||
return false;
|
||||
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
DestroyRenderSurface();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateSwapChain(const WindowInfo& new_wi, bool use_flip_model)
|
||||
bool D3D11HostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
if (new_wi.type != WindowInfo::Type::Win32)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateSwapChain()
|
||||
{
|
||||
if (m_window_info.type != WindowInfo::Type::Win32)
|
||||
return false;
|
||||
|
||||
m_using_flip_model_swap_chain = use_flip_model;
|
||||
m_using_flip_model_swap_chain = UseFlipModelSwapChain();
|
||||
|
||||
const HWND window_hwnd = reinterpret_cast<HWND>(new_wi.window_handle);
|
||||
const HWND window_hwnd = reinterpret_cast<HWND>(m_window_info.window_handle);
|
||||
RECT client_rc{};
|
||||
GetClientRect(window_hwnd, &client_rc);
|
||||
const u32 width = static_cast<u32>(client_rc.right - client_rc.left);
|
||||
|
@ -330,23 +382,33 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
|
|||
return false;
|
||||
}
|
||||
|
||||
m_swap_chain_width = backbuffer_desc.Width;
|
||||
m_swap_chain_height = backbuffer_desc.Height;
|
||||
m_window_info.surface_width = backbuffer_desc.Width;
|
||||
m_window_info.surface_height = backbuffer_desc.Height;
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(backbuffer_desc.Width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(backbuffer_desc.Height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::RecreateSwapChain(const WindowInfo& new_wi, bool use_flip_model)
|
||||
bool D3D11HostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
return CreateSwapChain(new_wi, use_flip_model);
|
||||
DestroyRenderSurface();
|
||||
|
||||
m_window_info = new_wi;
|
||||
return CreateSwapChain();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroySwapChain()
|
||||
void D3D11HostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
m_swap_chain_rtv.Reset();
|
||||
m_swap_chain.Reset();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::ResizeSwapChain(u32 new_width, u32 new_height)
|
||||
void D3D11HostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
if (!m_swap_chain)
|
||||
return;
|
||||
|
@ -423,8 +485,8 @@ void D3D11HostDisplay::DestroyResources()
|
|||
|
||||
bool D3D11HostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain_height);
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
if (!ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()))
|
||||
return false;
|
||||
|
@ -438,12 +500,27 @@ void D3D11HostDisplay::DestroyImGuiContext()
|
|||
ImGui_ImplDX11_Shutdown();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::BeginRender()
|
||||
bool D3D11HostDisplay::Render()
|
||||
{
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data());
|
||||
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
||||
|
||||
RenderDisplay();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
if (!m_vsync && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -453,20 +530,20 @@ void D3D11HostDisplay::RenderImGui()
|
|||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::EndRenderAndPresent()
|
||||
void D3D11HostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!m_vsync && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter)
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
m_context->VSSetShader(m_display_vertex_shader.Get(), nullptr, 0);
|
||||
|
@ -493,6 +570,15 @@ void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, v
|
|||
m_context->Draw(3, 0);
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
{
|
||||
|
@ -574,4 +660,9 @@ std::vector<std::string> D3D11HostDisplay::EnumerateAdapterNames(IDXGIFactory* d
|
|||
return adapter_names;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::UseFlipModelSwapChain() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class D3D11HostDisplay final
|
||||
class D3D11HostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
|
@ -24,56 +24,62 @@ public:
|
|||
D3D11HostDisplay();
|
||||
~D3D11HostDisplay();
|
||||
|
||||
ALWAYS_INLINE HostDisplay::RenderAPI GetRenderAPI() const { return HostDisplay::RenderAPI::D3D11; }
|
||||
ALWAYS_INLINE void* GetRenderDevice() const { return m_device.Get(); }
|
||||
ALWAYS_INLINE void* GetRenderContext() const { return m_context.Get(); }
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view adapter_name, bool use_flip_model,
|
||||
bool debug_device);
|
||||
bool HasContext() const;
|
||||
void DestroyContext();
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
bool CreateResources();
|
||||
void DestroyResources();
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
bool CreateImGuiContext();
|
||||
void DestroyImGuiContext();
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
ALWAYS_INLINE u32 GetSwapChainWidth() const { return m_swap_chain_width; }
|
||||
ALWAYS_INLINE u32 GetSwapChainHeight() const { return m_swap_chain_height; }
|
||||
ALWAYS_INLINE bool HasSwapChain() const { return static_cast<bool>(m_swap_chain); }
|
||||
|
||||
bool RecreateSwapChain(const WindowInfo& new_wi, bool use_flip_model);
|
||||
void ResizeSwapChain(u32 new_width, u32 new_height);
|
||||
void DestroySwapChain();
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic);
|
||||
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);
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride);
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled);
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginRender();
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter);
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void EndRenderAndPresent();
|
||||
virtual bool Render() override;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames();
|
||||
|
||||
private:
|
||||
protected:
|
||||
static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 16;
|
||||
|
||||
virtual bool UseFlipModelSwapChain() const;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames(IDXGIFactory* dxgi_factory);
|
||||
|
||||
bool CreateSwapChain(const WindowInfo& new_wi, bool use_flip_model);
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
bool CreateSwapChain();
|
||||
bool CreateSwapChainRTV();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
ComPtr<IDXGIFactory> m_dxgi_factory;
|
||||
|
||||
ComPtr<ID3D11Device> m_device;
|
||||
|
@ -94,9 +100,6 @@ private:
|
|||
D3D11::StreamBuffer m_display_uniform_buffer;
|
||||
D3D11::AutoStagingTexture m_readback_staging_texture;
|
||||
|
||||
u32 m_swap_chain_width = 0;
|
||||
u32 m_swap_chain_height = 0;
|
||||
|
||||
bool m_allow_tearing_supported = false;
|
||||
bool m_using_flip_model_swap_chain = true;
|
||||
bool m_using_allow_tearing = false;
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
<ProjectReference Include="..\..\dep\glad\glad.vcxproj">
|
||||
<Project>{43540154-9e1e-409c-834f-b84be5621388}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
|
||||
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\dep\libcue\libcue.vcxproj">
|
||||
<Project>{6a4208ed-e3dc-41e1-81cd-f61025fc285a}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -67,6 +70,7 @@
|
|||
<ClCompile Include="icon.cpp" />
|
||||
<ClCompile Include="imgui_styles.cpp" />
|
||||
<ClCompile Include="ini_settings_interface.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
<ClCompile Include="save_state_selector_ui.cpp" />
|
||||
<ClCompile Include="sdl_audio_stream.cpp" />
|
||||
<ClCompile Include="sdl_controller_interface.cpp" />
|
||||
|
@ -80,6 +84,7 @@
|
|||
<ClInclude Include="icon.h" />
|
||||
<ClInclude Include="imgui_styles.h" />
|
||||
<ClInclude Include="ini_settings_interface.h" />
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
<ClInclude Include="save_state_selector_ui.h" />
|
||||
<ClInclude Include="sdl_audio_stream.h" />
|
||||
<ClInclude Include="sdl_controller_interface.h" />
|
||||
|
@ -234,7 +239,7 @@
|
|||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
|
@ -261,7 +266,7 @@
|
|||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -291,7 +296,7 @@
|
|||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
|
@ -318,7 +323,7 @@
|
|||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -349,7 +354,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
|
@ -378,7 +383,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
@ -409,7 +414,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
|
@ -438,7 +443,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<ClCompile Include="save_state_selector_ui.cpp" />
|
||||
<ClCompile Include="vulkan_host_display.cpp" />
|
||||
<ClCompile Include="d3d11_host_display.cpp" />
|
||||
<ClCompile Include="opengl_host_display.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="icon.h" />
|
||||
|
@ -25,6 +26,7 @@
|
|||
<ClInclude Include="save_state_selector_ui.h" />
|
||||
<ClInclude Include="vulkan_host_display.h" />
|
||||
<ClInclude Include="d3d11_host_display.h" />
|
||||
<ClInclude Include="opengl_host_display.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="font_roboto_regular.inl" />
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
#include "openglhostdisplay.h"
|
||||
#include "opengl_host_display.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(OpenGLHostDisplay);
|
||||
Log_SetChannel(LibretroOpenGLHostDisplay);
|
||||
|
||||
class OpenGLDisplayWidgetTexture : public HostDisplayTexture
|
||||
namespace FrontendCommon {
|
||||
|
||||
class OpenGLHostDisplayTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
OpenGLDisplayWidgetTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
|
||||
~OpenGLDisplayWidgetTexture() override { glDeleteTextures(1, &m_id); }
|
||||
OpenGLHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
|
||||
~OpenGLHostDisplayTexture() 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; }
|
||||
|
@ -23,8 +21,8 @@ public:
|
|||
|
||||
GLuint GetGLID() const { return m_id; }
|
||||
|
||||
static std::unique_ptr<OpenGLDisplayWidgetTexture> Create(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride)
|
||||
static std::unique_ptr<OpenGLHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride)
|
||||
{
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
@ -42,7 +40,7 @@ public:
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
return std::make_unique<OpenGLDisplayWidgetTexture>(id, width, height);
|
||||
return std::make_unique<OpenGLHostDisplayTexture>(id, width, height);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -51,13 +49,16 @@ private:
|
|||
u32 m_height;
|
||||
};
|
||||
|
||||
OpenGLHostDisplay::OpenGLHostDisplay(QtHostInterface* host_interface) : QtHostDisplay(host_interface) {}
|
||||
OpenGLHostDisplay::OpenGLHostDisplay() = default;
|
||||
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay() = default;
|
||||
OpenGLHostDisplay::~OpenGLHostDisplay()
|
||||
{
|
||||
AssertMsg(!m_gl_context, "Context should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->IsGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
|
@ -70,22 +71,16 @@ void* OpenGLHostDisplay::GetRenderContext() const
|
|||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
QtHostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
}
|
||||
|
||||
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);
|
||||
return OpenGLHostDisplayTexture::Create(width, height, initial_data, initial_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);
|
||||
OpenGLHostDisplayTexture* tex = static_cast<OpenGLHostDisplayTexture*>(texture);
|
||||
Assert((texture_data_stride % sizeof(u32)) == 0);
|
||||
|
||||
GLint old_texture_binding = 0, old_alignment = 0, old_row_length = 0;
|
||||
|
@ -134,7 +129,7 @@ void OpenGLHostDisplay::SetVSync(bool enabled)
|
|||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (m_gl_context->IsGLES())
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_0)
|
||||
return "#version 300 es";
|
||||
|
@ -154,7 +149,7 @@ std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
|||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
if (m_gl_context->IsGLES())
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
{
|
||||
header += "precision highp float;\n";
|
||||
header += "precision highp int;\n\n";
|
||||
|
@ -183,49 +178,54 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen
|
|||
}
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::hasDeviceContext() const
|
||||
bool OpenGLHostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::createDeviceContext(const QString& adapter_name, bool debug_device)
|
||||
bool OpenGLHostDisplay::HasRenderSurface() const
|
||||
{
|
||||
m_window_width = m_widget->scaledWindowWidth();
|
||||
m_window_height = m_widget->scaledWindowHeight();
|
||||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
return false;
|
||||
|
||||
m_gl_context = GL::Context::Create(wi.value());
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create any GL context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi;
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::initializeDeviceContext(std::string_view shader_cache_directory, bool debug_device)
|
||||
bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
if (debug_device && GLAD_GL_KHR_debug)
|
||||
{
|
||||
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||
if (GetRenderAPI() == RenderAPI::OpenGLES)
|
||||
glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||
else
|
||||
glDebugMessageCallback(GLDebugCallback, nullptr);
|
||||
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
if (!QtHostDisplay::initializeDeviceContext(shader_cache_directory, debug_device))
|
||||
{
|
||||
m_gl_context->DoneCurrent();
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::activateDeviceContext()
|
||||
bool OpenGLHostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
if (!m_gl_context->MakeCurrent())
|
||||
{
|
||||
|
@ -236,56 +236,92 @@ bool OpenGLHostDisplay::activateDeviceContext()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::deactivateDeviceContext()
|
||||
bool OpenGLHostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
m_gl_context->DoneCurrent();
|
||||
return m_gl_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroyDeviceContext()
|
||||
void OpenGLHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
|
||||
m_gl_context->DoneCurrent();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::recreateSurface()
|
||||
bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
m_window_width = m_widget->scaledWindowWidth();
|
||||
m_window_height = m_widget->scaledWindowHeight();
|
||||
Assert(m_gl_context);
|
||||
|
||||
if (m_gl_context)
|
||||
if (!m_gl_context->ChangeSurface(new_wi))
|
||||
{
|
||||
std::optional<WindowInfo> wi = getWindowInfo();
|
||||
if (!wi.has_value() || !m_gl_context->ChangeSurface(wi.value()))
|
||||
return false;
|
||||
Log_ErrorPrintf("Failed to change surface");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = new_wi;
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroySurface() {}
|
||||
|
||||
bool OpenGLHostDisplay::createImGuiContext()
|
||||
void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
if (!QtHostDisplay::createImGuiContext())
|
||||
return false;
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
if (!m_gl_context)
|
||||
return;
|
||||
|
||||
m_window_info = {};
|
||||
if (!m_gl_context->ChangeSurface(m_window_info))
|
||||
Log_ErrorPrintf("Failed to switch to surfaceless");
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
return false;
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroyImGuiContext()
|
||||
void OpenGLHostDisplay::DestroyImGuiContext()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
|
||||
QtHostDisplay::destroyImGuiContext();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::createDeviceResources()
|
||||
bool OpenGLHostDisplay::CreateResources()
|
||||
{
|
||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||
uniform vec4 u_src_rect;
|
||||
|
@ -318,7 +354,7 @@ void main()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!m_gl_context->IsGLES())
|
||||
if (GetRenderAPI() != RenderAPI::OpenGLES)
|
||||
m_display_program.BindFragData(0, "o_col0");
|
||||
|
||||
if (!m_display_program.Link())
|
||||
|
@ -345,10 +381,8 @@ void main()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroyDeviceResources()
|
||||
void OpenGLHostDisplay::DestroyResources()
|
||||
{
|
||||
QtHostDisplay::destroyDeviceResources();
|
||||
|
||||
if (m_display_vao != 0)
|
||||
glDeleteVertexArrays(1, &m_display_vao);
|
||||
if (m_display_linear_sampler != 0)
|
||||
|
@ -359,49 +393,95 @@ void OpenGLHostDisplay::destroyDeviceResources()
|
|||
m_display_program.Destroy();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::Render()
|
||||
bool OpenGLHostDisplay::Render()
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
renderDisplay();
|
||||
RenderDisplay();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderImGui()
|
||||
{
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
GL::Program::ResetLastProgram();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::renderDisplay()
|
||||
void OpenGLHostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!m_display_texture_handle)
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
const auto [vp_left, vp_top, vp_width, vp_height] =
|
||||
CalculateDrawRect(m_window_width, m_window_height, m_display_top_margin);
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
RenderDisplay(left, GetWindowHeight() - top - height, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
glViewport(vp_left, m_window_height - (m_display_top_margin + vp_top) - vp_height, vp_width, vp_height);
|
||||
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle,
|
||||
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
glViewport(left, bottom, width, height);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
m_display_program.Bind();
|
||||
m_display_program.Uniform4f(
|
||||
0, static_cast<float>(m_display_texture_view_x) / static_cast<float>(m_display_texture_width),
|
||||
static_cast<float>(m_display_texture_view_y) / static_cast<float>(m_display_texture_height),
|
||||
(static_cast<float>(m_display_texture_view_width) - 0.5f) / static_cast<float>(m_display_texture_width),
|
||||
(static_cast<float>(m_display_texture_view_height) + 0.5f) / static_cast<float>(m_display_texture_height));
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(m_display_texture_handle)));
|
||||
glBindSampler(0, m_display_linear_filtering ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||
m_display_program.Uniform4f(0, static_cast<float>(texture_view_x) / static_cast<float>(texture_width),
|
||||
static_cast<float>(texture_view_y) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - 0.5f) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_height) + 0.5f) / static_cast<float>(texture_height));
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle)));
|
||||
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height,
|
||||
HostDisplayTexture* texture_handle)
|
||||
{
|
||||
glViewport(left, GetWindowHeight() - top - height, width, height);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
m_display_program.Bind();
|
||||
m_display_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID());
|
||||
glBindSampler(0, m_display_linear_sampler);
|
||||
glBindVertexArray(m_display_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
// GLAD has to come first so that Qt doesn't pull in the system GL headers, which are incompatible with glad.
|
||||
#include <glad.h>
|
||||
|
||||
// Hack to prevent Apple's glext.h headers from getting included via qopengl.h, since we still want to use glad.
|
||||
#ifdef __APPLE__
|
||||
#define __glext_h_
|
||||
#endif
|
||||
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include <memory>
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class OpenGLHostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
OpenGLHostDisplay();
|
||||
virtual ~OpenGLHostDisplay();
|
||||
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride) override;
|
||||
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
virtual bool Render() override;
|
||||
|
||||
protected:
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
|
||||
GL::Program m_display_program;
|
||||
GLuint m_display_vao = 0;
|
||||
GLuint m_display_nearest_sampler = 0;
|
||||
GLuint m_display_linear_sampler = 0;
|
||||
};
|
||||
|
||||
} // namespace FrontendCommon
|
|
@ -96,7 +96,22 @@ VulkanHostDisplay::~VulkanHostDisplay()
|
|||
AssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::RecreateSwapChain(const WindowInfo& new_wi)
|
||||
HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return HostDisplay::RenderAPI::Vulkan;
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderDevice() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* VulkanHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
Assert(!m_swap_chain);
|
||||
|
||||
|
@ -115,22 +130,39 @@ bool VulkanHostDisplay::RecreateSwapChain(const WindowInfo& new_wi)
|
|||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi_copy;
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::ResizeSwapChain(u32 new_width, u32 new_height)
|
||||
void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (!m_swap_chain->ResizeSwapChain(new_width, new_height))
|
||||
if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height))
|
||||
Panic("Failed to resize swap chain");
|
||||
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain->GetWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain->GetHeight());
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroySwapChain()
|
||||
void VulkanHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
m_window_info = {};
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
|
@ -193,27 +225,47 @@ void VulkanHostDisplay::SetVSync(bool enabled)
|
|||
m_swap_chain->SetVSync(enabled);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device)
|
||||
bool VulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
{
|
||||
if (!Vulkan::Context::Create(gpu_name, &wi, &m_swap_chain, debug_device, false))
|
||||
if (!Vulkan::Context::Create(adapter_name, &wi, &m_swap_chain, debug_device, false))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create Vulkan context");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = wi;
|
||||
if (m_swap_chain)
|
||||
{
|
||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::CreateShaderCache(std::string_view shader_cache_directory, bool debug_shaders)
|
||||
bool VulkanHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
Vulkan::ShaderCache::Create(shader_cache_directory, debug_shaders);
|
||||
Vulkan::ShaderCache::Create(shader_cache_directory, debug_device);
|
||||
|
||||
if (!CreateResources())
|
||||
return false;
|
||||
|
||||
if (ImGui::GetCurrentContext() && !CreateImGuiContext())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::HasContext() const
|
||||
bool VulkanHostDisplay::HasRenderDevice() const
|
||||
{
|
||||
return static_cast<bool>(g_vulkan_context);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::HasRenderSurface() const
|
||||
{
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateResources()
|
||||
{
|
||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||
|
@ -329,24 +381,37 @@ void VulkanHostDisplay::DestroyImGuiContext()
|
|||
ImGui_ImplVulkan_Shutdown();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyContext()
|
||||
void VulkanHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (!g_vulkan_context)
|
||||
return;
|
||||
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
DestroyImGuiContext();
|
||||
|
||||
DestroyResources();
|
||||
|
||||
Vulkan::ShaderCache::Destroy();
|
||||
DestroyRenderSurface();
|
||||
Vulkan::Context::Destroy();
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyShaderCache()
|
||||
bool VulkanHostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
Vulkan::ShaderCache::Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::DoneRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_swap_chain->GetWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_swap_chain->GetHeight());
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||
|
||||
ImGui_ImplVulkan_InitInfo vii = {};
|
||||
vii.Instance = g_vulkan_context->GetVulkanInstance();
|
||||
|
@ -370,14 +435,14 @@ bool VulkanHostDisplay::CreateImGuiContext()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::BeginRender()
|
||||
bool VulkanHostDisplay::Render()
|
||||
{
|
||||
VkResult res = m_swap_chain->AcquireNextImage();
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
ResizeSwapChain(0, 0);
|
||||
ResizeRenderWindow(0, 0);
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
}
|
||||
|
||||
|
@ -409,13 +474,13 @@ bool VulkanHostDisplay::BeginRender()
|
|||
1u,
|
||||
&clear_value};
|
||||
vkCmdBeginRenderPass(cmdbuffer, &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::EndRenderAndPresent()
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
Vulkan::Texture& swap_chain_texture = m_swap_chain->GetCurrentTexture();
|
||||
RenderDisplay();
|
||||
|
||||
if (ImGui::GetCurrentContext())
|
||||
RenderImGui();
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
|
||||
|
@ -426,13 +491,26 @@ void VulkanHostDisplay::EndRenderAndPresent()
|
|||
m_swap_chain->GetCurrentImageIndex());
|
||||
g_vulkan_context->MoveToNextCommandBuffer();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplVulkan_NewFrame();
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui_ImplVulkan_NewFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay()
|
||||
{
|
||||
if (!HasDisplayTexture())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight(), m_display_top_margin);
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, m_display_linear_filtering);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y,
|
||||
u32 texture_view_width, u32 texture_view_height, bool linear_filter)
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y,
|
||||
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
||||
|
@ -469,6 +547,15 @@ void VulkanHostDisplay::RenderImGui()
|
|||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), g_vulkan_context->GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderSoftwareCursor()
|
||||
{
|
||||
if (!HasSoftwareCursor())
|
||||
return;
|
||||
|
||||
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect();
|
||||
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture)
|
||||
{
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
|
|
@ -14,57 +14,44 @@ class SwapChain;
|
|||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class VulkanHostDisplay
|
||||
class VulkanHostDisplay : public HostDisplay
|
||||
{
|
||||
public:
|
||||
VulkanHostDisplay();
|
||||
~VulkanHostDisplay();
|
||||
virtual ~VulkanHostDisplay();
|
||||
|
||||
ALWAYS_INLINE HostDisplay::RenderAPI GetRenderAPI() const { return HostDisplay::RenderAPI::Vulkan; }
|
||||
ALWAYS_INLINE void* GetRenderDevice() const { return nullptr; }
|
||||
ALWAYS_INLINE void* GetRenderContext() const { return nullptr; }
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
|
||||
bool dynamic);
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
|
||||
u32 data_stride);
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
bool DownloadTexture(const void* texture_handle, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||
u32 out_data_stride);
|
||||
u32 out_data_stride) override;
|
||||
|
||||
void SetVSync(bool enabled);
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginRender();
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
u32 texture_height, u32 texture_view_x, u32 texture_view_y, u32 texture_view_width,
|
||||
u32 texture_view_height, bool linear_filter);
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
void EndRenderAndPresent();
|
||||
|
||||
bool CreateContextAndSwapChain(const WindowInfo& wi, std::string_view gpu_name, bool debug_device);
|
||||
bool HasContext() const;
|
||||
void DestroyContext();
|
||||
|
||||
void CreateShaderCache(std::string_view shader_cache_directory, bool debug_shaders);
|
||||
void DestroyShaderCache();
|
||||
|
||||
bool CreateResources();
|
||||
void DestroyResources();
|
||||
|
||||
bool CreateImGuiContext();
|
||||
void DestroyImGuiContext();
|
||||
|
||||
ALWAYS_INLINE u32 GetSwapChainWidth() const { return m_swap_chain->GetWidth(); }
|
||||
ALWAYS_INLINE u32 GetSwapChainHeight() const { return m_swap_chain->GetHeight(); }
|
||||
ALWAYS_INLINE bool HasSwapChain() const { return static_cast<bool>(m_swap_chain); }
|
||||
|
||||
bool RecreateSwapChain(const WindowInfo& new_wi);
|
||||
void ResizeSwapChain(u32 new_width, u32 new_height);
|
||||
void DestroySwapChain();
|
||||
virtual bool Render() override;
|
||||
|
||||
static std::vector<std::string> EnumerateAdapterNames();
|
||||
|
||||
private:
|
||||
protected:
|
||||
struct PushConstants
|
||||
{
|
||||
float src_rect_left;
|
||||
|
@ -73,6 +60,21 @@ private:
|
|||
float src_rect_height;
|
||||
};
|
||||
|
||||
virtual bool CreateResources();
|
||||
virtual void DestroyResources();
|
||||
|
||||
virtual bool CreateImGuiContext();
|
||||
virtual void DestroyImGuiContext();
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderImGui();
|
||||
void RenderSoftwareCursor();
|
||||
|
||||
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
s32 texture_height, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
|
||||
s32 texture_view_height, bool linear_filter);
|
||||
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, HostDisplayTexture* texture_handle);
|
||||
|
||||
std::unique_ptr<Vulkan::SwapChain> m_swap_chain;
|
||||
|
||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
|
|
Loading…
Reference in New Issue