NoGUI: Merge in old branch and use base NoGUI class for SDL
This commit is contained in:
parent
b09da307b5
commit
98bad30af8
|
@ -1,16 +1,35 @@
|
||||||
add_executable(duckstation-nogui
|
add_executable(duckstation-nogui
|
||||||
imgui_impl_sdl.cpp
|
|
||||||
imgui_impl_sdl.h
|
|
||||||
main.cpp
|
main.cpp
|
||||||
sdl_host_interface.cpp
|
nogui_host_interface.cpp
|
||||||
sdl_host_interface.h
|
nogui_host_interface.h
|
||||||
sdl_key_names.h
|
|
||||||
sdl_util.cpp
|
|
||||||
sdl_util.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(duckstation-nogui PRIVATE ${SDL2_INCLUDE_DIRS})
|
target_link_libraries(duckstation-nogui PRIVATE core common imgui glad frontend-common scmversion vulkan-loader)
|
||||||
target_link_libraries(duckstation-nogui PRIVATE core common imgui glad frontend-common scmversion vulkan-loader ${SDL2_LIBRARIES})
|
|
||||||
|
if(USE_SDL2)
|
||||||
|
target_sources(duckstation-nogui PRIVATE
|
||||||
|
imgui_impl_sdl.cpp
|
||||||
|
imgui_impl_sdl.h
|
||||||
|
sdl_host_interface.cpp
|
||||||
|
sdl_host_interface.h
|
||||||
|
sdl_key_names.h
|
||||||
|
)
|
||||||
|
target_include_directories(duckstation-nogui PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(duckstation-nogui PRIVATE ${SDL2_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(USE_DRMKMS)
|
||||||
|
find_package(LIBEVDEV REQUIRED)
|
||||||
|
|
||||||
|
target_sources(duckstation-nogui PRIVATE
|
||||||
|
drm_host_interface.cpp
|
||||||
|
drm_host_interface.h
|
||||||
|
)
|
||||||
|
target_compile_definitions(duckstation-nogui PRIVATE "-DUSE_DRMKMS=1")
|
||||||
|
target_compile_definitions(duckstation-nogui PRIVATE "-DUSE_LIBEVDEV=1")
|
||||||
|
target_include_directories(duckstation-nogui PRIVATE ${LIBEVDEV_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(duckstation-nogui PRIVATE ${LIBEVDEV_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(duckstation-nogui PRIVATE
|
target_sources(duckstation-nogui PRIVATE
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
#include "drm_host_interface.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "evdev_key_names.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
Log_SetChannel(DRMHostInterface);
|
||||||
|
|
||||||
|
DRMHostInterface::DRMHostInterface() = default;
|
||||||
|
|
||||||
|
DRMHostInterface::~DRMHostInterface()
|
||||||
|
{
|
||||||
|
CloseEVDevFDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<NoGUIHostInterface> DRMHostInterface::Create()
|
||||||
|
{
|
||||||
|
return std::make_unique<DRMHostInterface>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRMHostInterface::Initialize()
|
||||||
|
{
|
||||||
|
if (!NoGUIHostInterface::Initialize())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
OpenEVDevFDs();
|
||||||
|
|
||||||
|
signal(SIGTERM, SIGTERMHandler);
|
||||||
|
signal(SIGINT, SIGTERMHandler);
|
||||||
|
signal(SIGQUIT, SIGTERMHandler);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::Shutdown()
|
||||||
|
{
|
||||||
|
CloseEVDevFDs();
|
||||||
|
NoGUIHostInterface::Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRMHostInterface::IsFullscreen() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRMHostInterface::SetFullscreen(bool enabled)
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::FixIncompatibleSettings(bool display_osd_messages)
|
||||||
|
{
|
||||||
|
NoGUIHostInterface::FixIncompatibleSettings(display_osd_messages);
|
||||||
|
|
||||||
|
// Some things we definitely don't want.
|
||||||
|
g_settings.confim_power_off = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DRMHostInterface::CreatePlatformWindow()
|
||||||
|
{
|
||||||
|
Assert(!m_drm_display);
|
||||||
|
m_drm_display = std::make_unique<DRMDisplay>();
|
||||||
|
if (!m_drm_display->Initialize())
|
||||||
|
{
|
||||||
|
m_drm_display.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetImGuiKeyMap();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::DestroyPlatformWindow()
|
||||||
|
{
|
||||||
|
m_drm_display.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<WindowInfo> DRMHostInterface::GetPlatformWindowInfo()
|
||||||
|
{
|
||||||
|
WindowInfo wi;
|
||||||
|
wi.type = WindowInfo::Type::DRM;
|
||||||
|
wi.display_connection = m_drm_display.get();
|
||||||
|
wi.surface_width = m_drm_display->GetWidth();
|
||||||
|
wi.surface_height = m_drm_display->GetHeight();
|
||||||
|
wi.surface_format = WindowInfo::SurfaceFormat::Auto;
|
||||||
|
return wi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::PollAndUpdate()
|
||||||
|
{
|
||||||
|
PollEvDevKeyboards();
|
||||||
|
|
||||||
|
NoGUIHostInterface::PollAndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::OpenEVDevFDs()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
TinyString path;
|
||||||
|
path.Format("/dev/input/event%d", i);
|
||||||
|
|
||||||
|
int fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||||
|
if (fd < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct libevdev* obj;
|
||||||
|
if (libevdev_new_from_fd(fd, &obj) != 0)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("libevdev_new_from_fd(%s) failed", path.GetCharArray());
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_DevPrintf("Input path: %s", path.GetCharArray());
|
||||||
|
Log_DevPrintf("Input device name: \"%s\"", libevdev_get_name(obj));
|
||||||
|
Log_DevPrintf("Input device ID: bus %#x vendor %#x product %#x", libevdev_get_id_bustype(obj),
|
||||||
|
libevdev_get_id_vendor(obj), libevdev_get_id_product(obj));
|
||||||
|
if (!libevdev_has_event_code(obj, EV_KEY, KEY_SPACE))
|
||||||
|
{
|
||||||
|
Log_DevPrintf("This device does not look like a keyboard");
|
||||||
|
libevdev_free(obj);
|
||||||
|
close(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int grab_res = libevdev_grab(obj, LIBEVDEV_GRAB);
|
||||||
|
if (grab_res != 0)
|
||||||
|
Log_WarningPrintf("Failed to grab '%s' (%s): %d", libevdev_get_name(obj), path.GetCharArray(), grab_res);
|
||||||
|
|
||||||
|
m_evdev_keyboards.push_back({obj, fd});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::CloseEVDevFDs()
|
||||||
|
{
|
||||||
|
for (const EvDevKeyboard& kb : m_evdev_keyboards)
|
||||||
|
{
|
||||||
|
libevdev_grab(kb.obj, LIBEVDEV_UNGRAB);
|
||||||
|
libevdev_free(kb.obj);
|
||||||
|
close(kb.fd);
|
||||||
|
}
|
||||||
|
m_evdev_keyboards.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::PollEvDevKeyboards()
|
||||||
|
{
|
||||||
|
for (const EvDevKeyboard& kb : m_evdev_keyboards)
|
||||||
|
{
|
||||||
|
struct input_event ev;
|
||||||
|
while (libevdev_next_event(kb.obj, LIBEVDEV_READ_FLAG_NORMAL, &ev) == 0)
|
||||||
|
{
|
||||||
|
// auto-repeat
|
||||||
|
if (ev.value == 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool pressed = (ev.value == 1);
|
||||||
|
const HostKeyCode code = static_cast<HostKeyCode>(ev.code);
|
||||||
|
if (code >= 0 && code < countof(ImGuiIO::KeysDown))
|
||||||
|
ImGui::GetIO().KeysDown[code] = pressed;
|
||||||
|
|
||||||
|
HandleHostKeyEvent(code, pressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::SetImGuiKeyMap()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = KEY_TAB;
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = KEY_PAGEUP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = KEY_PAGEDOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Insert] = KEY_INSERT;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = KEY_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = KEY_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Space] = KEY_SPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = KEY_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = KEY_ESC;
|
||||||
|
io.KeyMap[ImGuiKey_KeyPadEnter] = KEY_KPENTER;
|
||||||
|
io.KeyMap[ImGuiKey_A] = KEY_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = KEY_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = KEY_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = KEY_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = KEY_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = KEY_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<DRMHostInterface::HostKeyCode> DRMHostInterface::GetHostKeyCode(const std::string_view key_code) const
|
||||||
|
{
|
||||||
|
std::optional<int> kc = EvDevKeyNames::GetKeyCodeForName(key_code);
|
||||||
|
if (!kc.has_value())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return static_cast<HostKeyCode>(kc.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DRMHostInterface::SIGTERMHandler(int sig)
|
||||||
|
{
|
||||||
|
Log_InfoPrintf("Recieved SIGTERM");
|
||||||
|
static_cast<DRMHostInterface*>(g_host_interface)->m_quit_request = true;
|
||||||
|
signal(sig, SIG_DFL);
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/drm_display.h"
|
||||||
|
#include "nogui_host_interface.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <libevdev/libevdev.h>
|
||||||
|
|
||||||
|
class DRMHostInterface final : public NoGUIHostInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DRMHostInterface();
|
||||||
|
~DRMHostInterface();
|
||||||
|
|
||||||
|
bool Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool IsFullscreen() const override;
|
||||||
|
bool SetFullscreen(bool enabled) override;
|
||||||
|
|
||||||
|
static std::unique_ptr<NoGUIHostInterface> Create();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void FixIncompatibleSettings(bool display_osd_messages) override;
|
||||||
|
|
||||||
|
bool CreatePlatformWindow() override;
|
||||||
|
void DestroyPlatformWindow() override;
|
||||||
|
std::optional<WindowInfo> GetPlatformWindowInfo() override;
|
||||||
|
|
||||||
|
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
|
||||||
|
|
||||||
|
void PollAndUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void SIGTERMHandler(int sig);
|
||||||
|
|
||||||
|
void OpenEVDevFDs();
|
||||||
|
void CloseEVDevFDs();
|
||||||
|
void PollEvDevKeyboards();
|
||||||
|
void SetImGuiKeyMap();
|
||||||
|
|
||||||
|
std::unique_ptr<DRMDisplay> m_drm_display;
|
||||||
|
|
||||||
|
struct EvDevKeyboard
|
||||||
|
{
|
||||||
|
struct libevdev* obj;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<EvDevKeyboard> m_evdev_keyboards;
|
||||||
|
};
|
|
@ -68,17 +68,61 @@
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="drm_host_interface.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="imgui_impl_sdl.cpp" />
|
<ClCompile Include="imgui_impl_sdl.cpp" />
|
||||||
|
<ClCompile Include="nogui_host_interface.cpp" />
|
||||||
<ClCompile Include="sdl_host_interface.cpp" />
|
<ClCompile Include="sdl_host_interface.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="sdl_util.cpp" />
|
<ClCompile Include="win32_host_interface.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="drm_host_interface.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="evdev_key_names.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="imgui_impl_sdl.h" />
|
<ClInclude Include="imgui_impl_sdl.h" />
|
||||||
|
<ClInclude Include="nogui_host_interface.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="sdl_host_interface.h" />
|
<ClInclude Include="sdl_host_interface.h" />
|
||||||
<ClInclude Include="sdl_key_names.h" />
|
<ClInclude Include="sdl_key_names.h" />
|
||||||
<ClInclude Include="sdl_util.h" />
|
<ClInclude Include="win32_host_interface.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Manifest Include="duckstation-nogui.manifest" />
|
<Manifest Include="duckstation-nogui.manifest" />
|
||||||
|
@ -103,44 +147,44 @@
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">
|
||||||
|
@ -148,7 +192,7 @@
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
@ -156,7 +200,7 @@
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||||
|
@ -164,7 +208,7 @@
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">
|
||||||
|
@ -172,7 +216,7 @@
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="Configuration">
|
||||||
|
@ -180,7 +224,7 @@
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v142</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>NotSet</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<SpectreMitigation>false</SpectreMitigation>
|
<SpectreMitigation>false</SpectreMitigation>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
@ -311,7 +355,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
@ -333,7 +377,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
@ -355,7 +399,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||||
|
@ -380,7 +424,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||||
|
@ -405,7 +449,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
|
||||||
|
@ -430,7 +474,7 @@
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
@ -453,7 +497,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -478,7 +522,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -502,7 +546,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -526,7 +570,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -551,7 +595,7 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
@ -576,11 +620,11 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>SDL2.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -4,22 +4,27 @@
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="sdl_host_interface.cpp" />
|
<ClCompile Include="sdl_host_interface.cpp" />
|
||||||
<ClCompile Include="imgui_impl_sdl.cpp" />
|
<ClCompile Include="imgui_impl_sdl.cpp" />
|
||||||
<ClCompile Include="sdl_util.cpp" />
|
<ClCompile Include="nogui_host_interface.cpp" />
|
||||||
|
<ClCompile Include="win32_host_interface.cpp" />
|
||||||
|
<ClCompile Include="drm_host_interface.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="sdl_host_interface.h" />
|
<ClInclude Include="sdl_host_interface.h" />
|
||||||
<ClInclude Include="imgui_impl_sdl.h" />
|
<ClInclude Include="imgui_impl_sdl.h" />
|
||||||
<ClInclude Include="sdl_key_names.h" />
|
<ClInclude Include="sdl_key_names.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="sdl_util.h" />
|
<ClInclude Include="nogui_host_interface.h" />
|
||||||
|
<ClInclude Include="win32_host_interface.h" />
|
||||||
|
<ClInclude Include="drm_host_interface.h" />
|
||||||
|
<ClInclude Include="evdev_key_names.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Manifest Include="duckstation-sdl.manifest" />
|
<Manifest Include="duckstation-nogui.manifest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="duckstation-sdl.ico" />
|
<Image Include="duckstation-nogui.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="duckstation-sdl.rc" />
|
<ResourceCompile Include="duckstation-nogui.rc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,278 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/string.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace EvDevKeyNames {
|
||||||
|
|
||||||
|
static const std::map<int, const char*> s_evdev_key_names = {{KEY_ESC, "Escape"},
|
||||||
|
{KEY_1, "1"},
|
||||||
|
{KEY_2, "2"},
|
||||||
|
{KEY_3, "3"},
|
||||||
|
{KEY_4, "4"},
|
||||||
|
{KEY_5, "5"},
|
||||||
|
{KEY_6, "6"},
|
||||||
|
{KEY_7, "7"},
|
||||||
|
{KEY_8, "8"},
|
||||||
|
{KEY_9, "9"},
|
||||||
|
{KEY_0, "0"},
|
||||||
|
{KEY_MINUS, "Minus"},
|
||||||
|
{KEY_EQUAL, "Equal"},
|
||||||
|
{KEY_BACKSPACE, "Backspace"},
|
||||||
|
{KEY_TAB, "Tab"},
|
||||||
|
{KEY_Q, "Q"},
|
||||||
|
{KEY_W, "W"},
|
||||||
|
{KEY_E, "E"},
|
||||||
|
{KEY_R, "R"},
|
||||||
|
{KEY_T, "T"},
|
||||||
|
{KEY_Y, "Y"},
|
||||||
|
{KEY_U, "U"},
|
||||||
|
{KEY_I, "I"},
|
||||||
|
{KEY_O, "O"},
|
||||||
|
{KEY_P, "P"},
|
||||||
|
{KEY_LEFTBRACE, "Leftbrace"},
|
||||||
|
{KEY_RIGHTBRACE, "Rightbrace"},
|
||||||
|
{KEY_ENTER, "Return"},
|
||||||
|
{KEY_LEFTCTRL, "Leftctrl"},
|
||||||
|
{KEY_A, "A"},
|
||||||
|
{KEY_S, "S"},
|
||||||
|
{KEY_D, "D"},
|
||||||
|
{KEY_F, "F"},
|
||||||
|
{KEY_G, "G"},
|
||||||
|
{KEY_H, "H"},
|
||||||
|
{KEY_J, "J"},
|
||||||
|
{KEY_K, "K"},
|
||||||
|
{KEY_L, "L"},
|
||||||
|
{KEY_SEMICOLON, "Semicolon"},
|
||||||
|
{KEY_APOSTROPHE, "Apostrophe"},
|
||||||
|
{KEY_GRAVE, "Grave"},
|
||||||
|
{KEY_LEFTSHIFT, "Leftshift"},
|
||||||
|
{KEY_BACKSLASH, "Backslash"},
|
||||||
|
{KEY_Z, "Z"},
|
||||||
|
{KEY_X, "X"},
|
||||||
|
{KEY_C, "C"},
|
||||||
|
{KEY_V, "V"},
|
||||||
|
{KEY_B, "B"},
|
||||||
|
{KEY_N, "N"},
|
||||||
|
{KEY_M, "M"},
|
||||||
|
{KEY_COMMA, "Comma"},
|
||||||
|
{KEY_DOT, "Dot"},
|
||||||
|
{KEY_SLASH, "Slash"},
|
||||||
|
{KEY_RIGHTSHIFT, "Rightshift"},
|
||||||
|
{KEY_KPASTERISK, "Kpasterisk"},
|
||||||
|
{KEY_LEFTALT, "Leftalt"},
|
||||||
|
{KEY_SPACE, "Space"},
|
||||||
|
{KEY_CAPSLOCK, "Capslock"},
|
||||||
|
{KEY_F1, "F1"},
|
||||||
|
{KEY_F2, "F2"},
|
||||||
|
{KEY_F3, "F3"},
|
||||||
|
{KEY_F4, "F4"},
|
||||||
|
{KEY_F5, "F5"},
|
||||||
|
{KEY_F6, "F6"},
|
||||||
|
{KEY_F7, "F7"},
|
||||||
|
{KEY_F8, "F8"},
|
||||||
|
{KEY_F9, "F9"},
|
||||||
|
{KEY_F10, "F10"},
|
||||||
|
{KEY_NUMLOCK, "Numlock"},
|
||||||
|
{KEY_SCROLLLOCK, "Scrolllock"},
|
||||||
|
{KEY_KP7, "Kp7"},
|
||||||
|
{KEY_KP8, "Kp8"},
|
||||||
|
{KEY_KP9, "Kp9"},
|
||||||
|
{KEY_KPMINUS, "Kpminus"},
|
||||||
|
{KEY_KP4, "Kp4"},
|
||||||
|
{KEY_KP5, "Kp5"},
|
||||||
|
{KEY_KP6, "Kp6"},
|
||||||
|
{KEY_KPPLUS, "Kpplus"},
|
||||||
|
{KEY_KP1, "Kp1"},
|
||||||
|
{KEY_KP2, "Kp2"},
|
||||||
|
{KEY_KP3, "Kp3"},
|
||||||
|
{KEY_KP0, "Kp0"},
|
||||||
|
{KEY_KPDOT, "Kpdot"},
|
||||||
|
{KEY_ZENKAKUHANKAKU, "Zenkakuhankaku"},
|
||||||
|
{KEY_102ND, "102nd"},
|
||||||
|
{KEY_F11, "F11"},
|
||||||
|
{KEY_F12, "F12"},
|
||||||
|
{KEY_RO, "Ro"},
|
||||||
|
{KEY_KATAKANA, "Katakana"},
|
||||||
|
{KEY_HIRAGANA, "Hiragana"},
|
||||||
|
{KEY_HENKAN, "Henkan"},
|
||||||
|
{KEY_KATAKANAHIRAGANA, "Katakanahiragana"},
|
||||||
|
{KEY_MUHENKAN, "Muhenkan"},
|
||||||
|
{KEY_KPJPCOMMA, "Kpjpcomma"},
|
||||||
|
{KEY_KPENTER, "Kpenter"},
|
||||||
|
{KEY_RIGHTCTRL, "Rightctrl"},
|
||||||
|
{KEY_KPSLASH, "Kpslash"},
|
||||||
|
{KEY_SYSRQ, "Sysrq"},
|
||||||
|
{KEY_RIGHTALT, "RightAlt"},
|
||||||
|
{KEY_LINEFEED, "Linefeed"},
|
||||||
|
{KEY_HOME, "Home"},
|
||||||
|
{KEY_UP, "Up"},
|
||||||
|
{KEY_PAGEUP, "PageUp"},
|
||||||
|
{KEY_LEFT, "Left"},
|
||||||
|
{KEY_RIGHT, "Right"},
|
||||||
|
{KEY_END, "End"},
|
||||||
|
{KEY_DOWN, "Down"},
|
||||||
|
{KEY_PAGEDOWN, "PageDown"},
|
||||||
|
{KEY_INSERT, "Insert"},
|
||||||
|
{KEY_DELETE, "Delete"},
|
||||||
|
{KEY_MACRO, "Macro"},
|
||||||
|
{KEY_MUTE, "Mute"},
|
||||||
|
{KEY_VOLUMEDOWN, "VolumeDown"},
|
||||||
|
{KEY_VOLUMEUP, "VolumeUp"},
|
||||||
|
{KEY_POWER, "Power"},
|
||||||
|
{KEY_KPEQUAL, "Kpequal"},
|
||||||
|
{KEY_KPPLUSMINUS, "Kpplusminus"},
|
||||||
|
{KEY_PAUSE, "Pause"},
|
||||||
|
{KEY_SCALE, "Scale"},
|
||||||
|
{KEY_KPCOMMA, "Kpcomma"},
|
||||||
|
{KEY_HANGEUL, "Hangeul"},
|
||||||
|
{KEY_HANGUEL, "Hanguel"},
|
||||||
|
{KEY_HANJA, "Hanja"},
|
||||||
|
{KEY_YEN, "Yen"},
|
||||||
|
{KEY_LEFTMETA, "Leftmeta"},
|
||||||
|
{KEY_RIGHTMETA, "Rightmeta"},
|
||||||
|
{KEY_COMPOSE, "Compose"},
|
||||||
|
{KEY_STOP, "Stop"},
|
||||||
|
{KEY_AGAIN, "Again"},
|
||||||
|
{KEY_PROPS, "Props"},
|
||||||
|
{KEY_UNDO, "Undo"},
|
||||||
|
{KEY_FRONT, "Front"},
|
||||||
|
{KEY_COPY, "Copy"},
|
||||||
|
{KEY_OPEN, "Open"},
|
||||||
|
{KEY_PASTE, "Paste"},
|
||||||
|
{KEY_FIND, "Find"},
|
||||||
|
{KEY_CUT, "Cut"},
|
||||||
|
{KEY_HELP, "Help"},
|
||||||
|
{KEY_MENU, "Menu"},
|
||||||
|
{KEY_CALC, "Calc"},
|
||||||
|
{KEY_SETUP, "Setup"},
|
||||||
|
{KEY_SLEEP, "Sleep"},
|
||||||
|
{KEY_WAKEUP, "Wakeup"},
|
||||||
|
{KEY_FILE, "File"},
|
||||||
|
{KEY_SENDFILE, "Sendfile"},
|
||||||
|
{KEY_DELETEFILE, "Deletefile"},
|
||||||
|
{KEY_XFER, "Xfer"},
|
||||||
|
{KEY_PROG1, "Prog1"},
|
||||||
|
{KEY_PROG2, "Prog2"},
|
||||||
|
{KEY_WWW, "Www"},
|
||||||
|
{KEY_MSDOS, "Msdos"},
|
||||||
|
{KEY_COFFEE, "Coffee"},
|
||||||
|
{KEY_SCREENLOCK, "Screenlock"},
|
||||||
|
{KEY_ROTATE_DISPLAY, "Rotate_display"},
|
||||||
|
{KEY_DIRECTION, "Direction"},
|
||||||
|
{KEY_CYCLEWINDOWS, "Cyclewindows"},
|
||||||
|
{KEY_MAIL, "Mail"},
|
||||||
|
{KEY_BOOKMARKS, "Bookmarks"},
|
||||||
|
{KEY_COMPUTER, "Computer"},
|
||||||
|
{KEY_BACK, "Back"},
|
||||||
|
{KEY_FORWARD, "Forward"},
|
||||||
|
{KEY_CLOSECD, "Closecd"},
|
||||||
|
{KEY_EJECTCD, "Ejectcd"},
|
||||||
|
{KEY_EJECTCLOSECD, "Ejectclosecd"},
|
||||||
|
{KEY_NEXTSONG, "Nextsong"},
|
||||||
|
{KEY_PLAYPAUSE, "Playpause"},
|
||||||
|
{KEY_PREVIOUSSONG, "Previoussong"},
|
||||||
|
{KEY_STOPCD, "Stopcd"},
|
||||||
|
{KEY_RECORD, "Record"},
|
||||||
|
{KEY_REWIND, "Rewind"},
|
||||||
|
{KEY_PHONE, "Phone"},
|
||||||
|
{KEY_ISO, "Iso"},
|
||||||
|
{KEY_CONFIG, "Config"},
|
||||||
|
{KEY_HOMEPAGE, "Homepage"},
|
||||||
|
{KEY_REFRESH, "Refresh"},
|
||||||
|
{KEY_EXIT, "Exit"},
|
||||||
|
{KEY_MOVE, "Move"},
|
||||||
|
{KEY_EDIT, "Edit"},
|
||||||
|
{KEY_SCROLLUP, "Scrollup"},
|
||||||
|
{KEY_SCROLLDOWN, "Scrolldown"},
|
||||||
|
{KEY_KPLEFTPAREN, "Kpleftparen"},
|
||||||
|
{KEY_KPRIGHTPAREN, "Kprightparen"},
|
||||||
|
{KEY_NEW, "New"},
|
||||||
|
{KEY_REDO, "Redo"},
|
||||||
|
{KEY_F13, "F13"},
|
||||||
|
{KEY_F14, "F14"},
|
||||||
|
{KEY_F15, "F15"},
|
||||||
|
{KEY_F16, "F16"},
|
||||||
|
{KEY_F17, "F17"},
|
||||||
|
{KEY_F18, "F18"},
|
||||||
|
{KEY_F19, "F19"},
|
||||||
|
{KEY_F20, "F20"},
|
||||||
|
{KEY_F21, "F21"},
|
||||||
|
{KEY_F22, "F22"},
|
||||||
|
{KEY_F23, "F23"},
|
||||||
|
{KEY_F24, "F24"},
|
||||||
|
{KEY_PLAYCD, "Playcd"},
|
||||||
|
{KEY_PAUSECD, "Pausecd"},
|
||||||
|
{KEY_PROG3, "Prog3"},
|
||||||
|
{KEY_PROG4, "Prog4"},
|
||||||
|
{KEY_DASHBOARD, "Dashboard"},
|
||||||
|
{KEY_SUSPEND, "Suspend"},
|
||||||
|
{KEY_CLOSE, "Close"},
|
||||||
|
{KEY_PLAY, "Play"},
|
||||||
|
{KEY_FASTFORWARD, "Fastforward"},
|
||||||
|
{KEY_BASSBOOST, "Bassboost"},
|
||||||
|
{KEY_PRINT, "Print"},
|
||||||
|
{KEY_HP, "Hp"},
|
||||||
|
{KEY_CAMERA, "Camera"},
|
||||||
|
{KEY_SOUND, "Sound"},
|
||||||
|
{KEY_QUESTION, "Question"},
|
||||||
|
{KEY_EMAIL, "Email"},
|
||||||
|
{KEY_CHAT, "Chat"},
|
||||||
|
{KEY_SEARCH, "Search"},
|
||||||
|
{KEY_CONNECT, "Connect"},
|
||||||
|
{KEY_FINANCE, "Finance"},
|
||||||
|
{KEY_SPORT, "Sport"},
|
||||||
|
{KEY_SHOP, "Shop"},
|
||||||
|
{KEY_ALTERASE, "Alterase"},
|
||||||
|
{KEY_CANCEL, "Cancel"},
|
||||||
|
{KEY_BRIGHTNESSDOWN, "Brightnessdown"},
|
||||||
|
{KEY_BRIGHTNESSUP, "Brightnessup"},
|
||||||
|
{KEY_MEDIA, "Media"},
|
||||||
|
{KEY_SWITCHVIDEOMODE, "Switchvideomode"},
|
||||||
|
{KEY_KBDILLUMTOGGLE, "Kbdillumtoggle"},
|
||||||
|
{KEY_KBDILLUMDOWN, "Kbdillumdown"},
|
||||||
|
{KEY_KBDILLUMUP, "Kbdillumup"},
|
||||||
|
{KEY_SEND, "Send"},
|
||||||
|
{KEY_REPLY, "Reply"},
|
||||||
|
{KEY_FORWARDMAIL, "Forwardmail"},
|
||||||
|
{KEY_SAVE, "Save"},
|
||||||
|
{KEY_DOCUMENTS, "Documents"},
|
||||||
|
{KEY_BATTERY, "Battery"},
|
||||||
|
{KEY_BLUETOOTH, "Bluetooth"},
|
||||||
|
{KEY_WLAN, "Wlan"},
|
||||||
|
{KEY_UWB, "Uwb"},
|
||||||
|
{KEY_UNKNOWN, "Unknown"},
|
||||||
|
{KEY_VIDEO_NEXT, "Video_next"},
|
||||||
|
{KEY_VIDEO_PREV, "Video_prev"},
|
||||||
|
{KEY_BRIGHTNESS_CYCLE, "Brightness_cycle"},
|
||||||
|
{KEY_BRIGHTNESS_AUTO, "Brightness_auto"},
|
||||||
|
{KEY_BRIGHTNESS_ZERO, "Brightness_zero"},
|
||||||
|
{KEY_DISPLAY_OFF, "Display_off"},
|
||||||
|
{KEY_WWAN, "Wwan"},
|
||||||
|
{KEY_WIMAX, "Wimax"},
|
||||||
|
{KEY_RFKILL, "Rfkill"},
|
||||||
|
{KEY_MICMUTE, "Micmute"}};
|
||||||
|
|
||||||
|
const char* GetKeyName(int key)
|
||||||
|
{
|
||||||
|
const auto it = s_evdev_key_names.find(key);
|
||||||
|
return it == s_evdev_key_names.end() ? nullptr : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> GetKeyCodeForName(const std::string_view key_name)
|
||||||
|
{
|
||||||
|
for (const auto& it : s_evdev_key_names)
|
||||||
|
{
|
||||||
|
if (key_name == it.second)
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace EvDevKeyNames
|
|
@ -131,7 +131,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplSDL2_Init(SDL_Window* window)
|
void ImGui_ImplSDL2_Init(SDL_Window* window)
|
||||||
{
|
{
|
||||||
g_Window = window;
|
g_Window = window;
|
||||||
|
|
||||||
|
@ -176,7 +176,6 @@ bool ImGui_ImplSDL2_Init(SDL_Window* window)
|
||||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplSDL2_Shutdown()
|
void ImGui_ImplSDL2_Shutdown()
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
typedef union SDL_Event SDL_Event;
|
typedef union SDL_Event SDL_Event;
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_Init(SDL_Window* window);
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Init(SDL_Window* window);
|
||||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||||
|
|
|
@ -1,48 +1,129 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/file_system.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
#include "frontend-common/sdl_initializer.h"
|
|
||||||
#include "sdl_host_interface.h"
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
#ifdef USE_DRMKMS
|
||||||
|
#include "drm_host_interface.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_SDL2
|
||||||
|
#include "sdl_host_interface.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
#include "win32_host_interface.h"
|
||||||
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static std::unique_ptr<NoGUIHostInterface> CreateHostInterface(const char* platform)
|
||||||
{
|
{
|
||||||
FrontendCommon::EnsureSDLInitialized();
|
std::unique_ptr<NoGUIHostInterface> host_interface;
|
||||||
|
|
||||||
std::unique_ptr<SDLHostInterface> host_interface = SDLHostInterface::Create();
|
#ifdef USE_DRMKMS
|
||||||
std::unique_ptr<SystemBootParameters> boot_params;
|
// TODO: We should detect if we have a display here...
|
||||||
if (!host_interface->ParseCommandLineParameters(argc, argv, &boot_params))
|
if (!host_interface && (!platform || StringUtil::Strcasecmp(platform, "drm") == 0))
|
||||||
{
|
host_interface = DRMHostInterface::Create();
|
||||||
SDL_Quit();
|
#endif
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifdef WITH_SDL2
|
||||||
|
if (!host_interface && (!platform || StringUtil::Strcasecmp(platform, "sdl") == 0))
|
||||||
|
host_interface = SDLHostInterface::Create();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!host_interface && (!platform || StringUtil::Strcasecmp(platform, "win32") == 0))
|
||||||
|
host_interface = Win32HostInterface::Create();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return host_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Run(std::unique_ptr<NoGUIHostInterface> host_interface, std::unique_ptr<SystemBootParameters> boot_params)
|
||||||
|
{
|
||||||
if (!host_interface->Initialize())
|
if (!host_interface->Initialize())
|
||||||
{
|
{
|
||||||
host_interface->Shutdown();
|
host_interface->Shutdown();
|
||||||
SDL_Quit();
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boot_params)
|
if (boot_params)
|
||||||
{
|
host_interface->BootSystem(*boot_params);
|
||||||
if (!host_interface->BootSystem(*boot_params) && host_interface->InBatchMode())
|
|
||||||
{
|
|
||||||
host_interface->Shutdown();
|
|
||||||
host_interface.reset();
|
|
||||||
SDL_Quit();
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_params.reset();
|
int result;
|
||||||
|
if (System::IsValid() || !host_interface->InBatchMode())
|
||||||
|
{
|
||||||
|
host_interface->Run();
|
||||||
|
result = EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
host_interface->ReportError("No file specified, and we're in batch mode. Exiting.");
|
||||||
|
result = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
host_interface->Run();
|
|
||||||
host_interface->Shutdown();
|
host_interface->Shutdown();
|
||||||
host_interface.reset();
|
return result;
|
||||||
|
|
||||||
SDL_Quit();
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
|
||||||
|
{
|
||||||
|
std::unique_ptr<NoGUIHostInterface> host_interface = CreateHostInterface(nullptr);
|
||||||
|
std::unique_ptr<SystemBootParameters> boot_params;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<std::string> argc_strings;
|
||||||
|
argc_strings.reserve(1);
|
||||||
|
|
||||||
|
// CommandLineToArgvW() only adds the program path if the command line is empty?!
|
||||||
|
argc_strings.push_back(FileSystem::GetProgramPath());
|
||||||
|
|
||||||
|
if (std::wcslen(lpCmdLine) > 0)
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
LPWSTR* argv_wide = CommandLineToArgvW(lpCmdLine, &argc);
|
||||||
|
if (argv_wide)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
argc_strings.push_back(StringUtil::WideStringToUTF8String(argv_wide[i]));
|
||||||
|
|
||||||
|
LocalFree(argv_wide);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char*> argc_pointers;
|
||||||
|
argc_pointers.reserve(argc_strings.size());
|
||||||
|
for (std::string& arg : argc_strings)
|
||||||
|
argc_pointers.push_back(arg.data());
|
||||||
|
|
||||||
|
if (!host_interface->ParseCommandLineParameters(static_cast<int>(argc_pointers.size()), argc_pointers.data(),
|
||||||
|
&boot_params))
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Run(std::move(host_interface), std::move(boot_params));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
std::unique_ptr<NoGUIHostInterface> host_interface = CreateHostInterface(nullptr);
|
||||||
|
std::unique_ptr<SystemBootParameters> boot_params;
|
||||||
|
if (!host_interface->ParseCommandLineParameters(argc, argv, &boot_params))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
return Run(std::move(host_interface), std::move(boot_params));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,410 @@
|
||||||
|
#include "nogui_host_interface.h"
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/byte_stream.h"
|
||||||
|
#include "common/file_system.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/controller.h"
|
||||||
|
#include "core/gpu.h"
|
||||||
|
#include "core/host_display.h"
|
||||||
|
#include "core/system.h"
|
||||||
|
#include "frontend-common/controller_interface.h"
|
||||||
|
#include "frontend-common/fullscreen_ui.h"
|
||||||
|
#include "frontend-common/icon.h"
|
||||||
|
#include "frontend-common/imgui_fullscreen.h"
|
||||||
|
#include "frontend-common/imgui_styles.h"
|
||||||
|
#include "frontend-common/ini_settings_interface.h"
|
||||||
|
#include "frontend-common/opengl_host_display.h"
|
||||||
|
#include "frontend-common/vulkan_host_display.h"
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cmath>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_stdlib.h>
|
||||||
|
Log_SetChannel(NoGUIHostInterface);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include "frontend-common/d3d11_host_display.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NoGUIHostInterface::NoGUIHostInterface() = default;
|
||||||
|
|
||||||
|
NoGUIHostInterface::~NoGUIHostInterface() = default;
|
||||||
|
|
||||||
|
const char* NoGUIHostInterface::GetFrontendName() const
|
||||||
|
{
|
||||||
|
return "DuckStation NoGUI Frontend";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoGUIHostInterface::Initialize()
|
||||||
|
{
|
||||||
|
// TODO: Make command line.
|
||||||
|
m_fullscreen_ui_enabled = true;
|
||||||
|
|
||||||
|
// we're always in batch mode for now
|
||||||
|
m_command_line_flags.batch_mode = !m_fullscreen_ui_enabled;
|
||||||
|
|
||||||
|
if (!CommonHostInterface::Initialize())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CreateImGuiContext();
|
||||||
|
|
||||||
|
if (!CreatePlatformWindow())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to create platform window");
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateDisplay())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to create host display");
|
||||||
|
DestroyPlatformWindow();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process events to pick up controllers before updating input map
|
||||||
|
PollAndUpdate();
|
||||||
|
UpdateInputMap();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::Shutdown()
|
||||||
|
{
|
||||||
|
DestroySystem();
|
||||||
|
|
||||||
|
CommonHostInterface::Shutdown();
|
||||||
|
|
||||||
|
if (m_display)
|
||||||
|
{
|
||||||
|
DestroyDisplay();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyPlatformWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NoGUIHostInterface::GetStringSettingValue(const char* section, const char* key,
|
||||||
|
const char* default_value /*= ""*/)
|
||||||
|
{
|
||||||
|
return m_settings_interface->GetStringValue(section, key, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoGUIHostInterface::GetBoolSettingValue(const char* section, const char* key, bool default_value /* = false */)
|
||||||
|
{
|
||||||
|
return m_settings_interface->GetBoolValue(section, key, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NoGUIHostInterface::GetIntSettingValue(const char* section, const char* key, int default_value /* = 0 */)
|
||||||
|
{
|
||||||
|
return m_settings_interface->GetIntValue(section, key, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
float NoGUIHostInterface::GetFloatSettingValue(const char* section, const char* key, float default_value /* = 0.0f */)
|
||||||
|
{
|
||||||
|
return m_settings_interface->GetFloatValue(section, key, default_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::LoadSettings()
|
||||||
|
{
|
||||||
|
m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName());
|
||||||
|
CommonHostInterface::LoadSettings(*m_settings_interface.get());
|
||||||
|
CommonHostInterface::FixIncompatibleSettings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::UpdateInputMap()
|
||||||
|
{
|
||||||
|
CommonHostInterface::UpdateInputMap(*m_settings_interface.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::ApplySettings(bool display_osd_messages)
|
||||||
|
{
|
||||||
|
Settings old_settings(std::move(g_settings));
|
||||||
|
CommonHostInterface::LoadSettings(*m_settings_interface.get());
|
||||||
|
CommonHostInterface::ApplyGameSettings(display_osd_messages);
|
||||||
|
CommonHostInterface::FixIncompatibleSettings(display_osd_messages);
|
||||||
|
CheckForSettingsChanges(old_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::CreateImGuiContext()
|
||||||
|
{
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGui::GetIO().IniFilename = nullptr;
|
||||||
|
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::OnPlatformWindowResized(u32 new_width, u32 new_height, float new_scale)
|
||||||
|
{
|
||||||
|
if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x)
|
||||||
|
{
|
||||||
|
ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale);
|
||||||
|
ImGui::GetStyle() = ImGuiStyle();
|
||||||
|
ImGui::StyleColorsDarker();
|
||||||
|
ImGui::GetStyle().ScaleAllSizes(new_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGuiFullscreen::UpdateLayoutScale())
|
||||||
|
{
|
||||||
|
if (ImGuiFullscreen::UpdateFonts())
|
||||||
|
{
|
||||||
|
if (!m_display->UpdateImGuiFontTexture())
|
||||||
|
Panic("Failed to update font texture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!System::IsShutdown())
|
||||||
|
g_gpu->UpdateResolutionScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoGUIHostInterface::CreateDisplay()
|
||||||
|
{
|
||||||
|
std::optional<WindowInfo> wi = GetPlatformWindowInfo();
|
||||||
|
if (!wi)
|
||||||
|
{
|
||||||
|
ReportError("Failed to get platform window info");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// imgui init from window
|
||||||
|
ImGui::GetIO().DisplayFramebufferScale.x = wi->surface_scale;
|
||||||
|
ImGui::GetIO().DisplayFramebufferScale.y = wi->surface_scale;
|
||||||
|
ImGui::GetStyle() = ImGuiStyle();
|
||||||
|
ImGui::GetStyle().ScaleAllSizes(wi->surface_scale);
|
||||||
|
ImGui::StyleColorsDarker();
|
||||||
|
|
||||||
|
Assert(!m_display);
|
||||||
|
switch (g_settings.gpu_renderer)
|
||||||
|
{
|
||||||
|
case GPURenderer::HardwareVulkan:
|
||||||
|
m_display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPURenderer::HardwareOpenGL:
|
||||||
|
#ifndef WIN32
|
||||||
|
default:
|
||||||
|
#endif
|
||||||
|
m_display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
case GPURenderer::HardwareD3D11:
|
||||||
|
default:
|
||||||
|
m_display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_display->CreateRenderDevice(wi.value(), g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
|
||||||
|
g_settings.gpu_threaded_presentation) ||
|
||||||
|
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
|
||||||
|
g_settings.gpu_threaded_presentation))
|
||||||
|
{
|
||||||
|
ReportError("Failed to create/initialize display render device");
|
||||||
|
m_display->DestroyRenderDevice();
|
||||||
|
m_display.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_display->CreateImGuiContext() ||
|
||||||
|
(m_fullscreen_ui_enabled && !FullscreenUI::Initialize(this, m_settings_interface.get())) ||
|
||||||
|
!m_display->UpdateImGuiFontTexture())
|
||||||
|
{
|
||||||
|
ReportError("Failed to initialize imgui/fonts/fullscreen UI");
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::Shutdown();
|
||||||
|
|
||||||
|
m_display->DestroyImGuiContext();
|
||||||
|
m_display->DestroyRenderDevice();
|
||||||
|
m_display.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::DestroyDisplay()
|
||||||
|
{
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::Shutdown();
|
||||||
|
|
||||||
|
if (m_display)
|
||||||
|
{
|
||||||
|
m_display->DestroyImGuiContext();
|
||||||
|
m_display->DestroyRenderDevice();
|
||||||
|
}
|
||||||
|
m_display.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoGUIHostInterface::AcquireHostDisplay()
|
||||||
|
{
|
||||||
|
// Handle renderer switch if required.
|
||||||
|
const HostDisplay::RenderAPI render_api = m_display->GetRenderAPI();
|
||||||
|
bool needs_switch = false;
|
||||||
|
switch (g_settings.gpu_renderer)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
case GPURenderer::HardwareD3D11:
|
||||||
|
needs_switch = (render_api != HostDisplay::RenderAPI::D3D11);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case GPURenderer::HardwareVulkan:
|
||||||
|
needs_switch = (render_api != HostDisplay::RenderAPI::Vulkan);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPURenderer::HardwareOpenGL:
|
||||||
|
needs_switch = (render_api != HostDisplay::RenderAPI::OpenGL && render_api != HostDisplay::RenderAPI::OpenGLES);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPURenderer::Software:
|
||||||
|
default:
|
||||||
|
needs_switch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_switch)
|
||||||
|
{
|
||||||
|
ImGui::EndFrame();
|
||||||
|
DestroyDisplay();
|
||||||
|
|
||||||
|
// We need to recreate the window, otherwise bad things happen...
|
||||||
|
DestroyPlatformWindow();
|
||||||
|
if (!CreatePlatformWindow())
|
||||||
|
Panic("Failed to recreate platform window on GPU renderer switch");
|
||||||
|
|
||||||
|
if (!CreateDisplay())
|
||||||
|
Panic("Failed to recreate display on GPU renderer switch");
|
||||||
|
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CreateHostDisplayResources())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::ReleaseHostDisplay()
|
||||||
|
{
|
||||||
|
ReleaseHostDisplayResources();
|
||||||
|
|
||||||
|
// restore vsync, since we don't want to burn cycles at the menu
|
||||||
|
m_display->SetVSync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::OnSystemCreated()
|
||||||
|
{
|
||||||
|
CommonHostInterface::OnSystemCreated();
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::SystemCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::OnSystemPaused(bool paused)
|
||||||
|
{
|
||||||
|
CommonHostInterface::OnSystemPaused(paused);
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::SystemPaused(paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::OnSystemDestroyed()
|
||||||
|
{
|
||||||
|
CommonHostInterface::OnSystemDestroyed();
|
||||||
|
ReportFormattedMessage("System shut down.");
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::SystemDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::OnRunningGameChanged()
|
||||||
|
{
|
||||||
|
CommonHostInterface::OnRunningGameChanged();
|
||||||
|
|
||||||
|
// TODO: Move to common
|
||||||
|
if (g_settings.apply_game_settings)
|
||||||
|
ApplySettings(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::RequestExit()
|
||||||
|
{
|
||||||
|
m_quit_request = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::PollAndUpdate()
|
||||||
|
{
|
||||||
|
CommonHostInterface::PollAndUpdate();
|
||||||
|
|
||||||
|
if (m_controller_interface)
|
||||||
|
m_controller_interface->PollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::Run()
|
||||||
|
{
|
||||||
|
while (!m_quit_request)
|
||||||
|
{
|
||||||
|
RunCallbacks();
|
||||||
|
PollAndUpdate();
|
||||||
|
if (m_fullscreen_ui_enabled)
|
||||||
|
FullscreenUI::SetImGuiNavInputs();
|
||||||
|
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
if (System::IsRunning())
|
||||||
|
{
|
||||||
|
if (m_display_all_frames)
|
||||||
|
System::RunFrame();
|
||||||
|
else
|
||||||
|
System::RunFrames();
|
||||||
|
|
||||||
|
UpdateControllerRumble();
|
||||||
|
if (m_frame_step_request)
|
||||||
|
{
|
||||||
|
m_frame_step_request = false;
|
||||||
|
PauseSystem(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rendering
|
||||||
|
{
|
||||||
|
DrawImGuiWindows();
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui::EndFrame();
|
||||||
|
|
||||||
|
m_display->Render();
|
||||||
|
|
||||||
|
if (System::IsRunning())
|
||||||
|
{
|
||||||
|
System::UpdatePerformanceCounters();
|
||||||
|
|
||||||
|
if (m_throttler_enabled)
|
||||||
|
System::Throttle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save state on exit so it can be resumed
|
||||||
|
if (!System::IsShutdown())
|
||||||
|
{
|
||||||
|
if (g_settings.save_state_on_exit)
|
||||||
|
SaveResumeSaveState();
|
||||||
|
DestroySystem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::RunLater(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_queued_callbacks_lock);
|
||||||
|
m_queued_callbacks.push_back(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoGUIHostInterface::RunCallbacks()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_queued_callbacks_lock);
|
||||||
|
|
||||||
|
while (!m_queued_callbacks.empty())
|
||||||
|
{
|
||||||
|
auto callback = std::move(m_queued_callbacks.front());
|
||||||
|
m_queued_callbacks.pop_front();
|
||||||
|
lock.unlock();
|
||||||
|
callback();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/window_info.h"
|
||||||
|
#include "core/host_display.h"
|
||||||
|
#include "core/host_interface.h"
|
||||||
|
#include "frontend-common/common_host_interface.h"
|
||||||
|
#include <array>
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class INISettingsInterface;
|
||||||
|
|
||||||
|
class NoGUIHostInterface : public CommonHostInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NoGUIHostInterface();
|
||||||
|
~NoGUIHostInterface();
|
||||||
|
|
||||||
|
const char* GetFrontendName() const override;
|
||||||
|
|
||||||
|
virtual bool Initialize() override;
|
||||||
|
virtual void Shutdown() override;
|
||||||
|
virtual void Run();
|
||||||
|
|
||||||
|
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") override;
|
||||||
|
bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false) override;
|
||||||
|
int GetIntSettingValue(const char* section, const char* key, int default_value = 0) override;
|
||||||
|
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
||||||
|
|
||||||
|
void RunLater(std::function<void()> callback) override;
|
||||||
|
void ApplySettings(bool display_osd_messages) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum : u32
|
||||||
|
{
|
||||||
|
DEFAULT_WINDOW_WIDTH = 1280,
|
||||||
|
DEFAULT_WINDOW_HEIGHT = 720
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void LoadSettings() override;
|
||||||
|
|
||||||
|
bool AcquireHostDisplay() override;
|
||||||
|
void ReleaseHostDisplay() override;
|
||||||
|
|
||||||
|
void UpdateInputMap() override;
|
||||||
|
|
||||||
|
void OnSystemCreated() override;
|
||||||
|
void OnSystemPaused(bool paused) override;
|
||||||
|
void OnSystemDestroyed() override;
|
||||||
|
void OnRunningGameChanged() override;
|
||||||
|
|
||||||
|
void RequestExit() override;
|
||||||
|
virtual void PollAndUpdate() override;
|
||||||
|
|
||||||
|
virtual bool CreatePlatformWindow() = 0;
|
||||||
|
virtual void DestroyPlatformWindow() = 0;
|
||||||
|
virtual std::optional<WindowInfo> GetPlatformWindowInfo() = 0;
|
||||||
|
void OnPlatformWindowResized(u32 new_width, u32 new_height, float new_scale);
|
||||||
|
|
||||||
|
bool CreateDisplay();
|
||||||
|
void DestroyDisplay();
|
||||||
|
void CreateImGuiContext();
|
||||||
|
void RunCallbacks();
|
||||||
|
|
||||||
|
std::unique_ptr<INISettingsInterface> m_settings_interface;
|
||||||
|
std::deque<std::function<void()>> m_queued_callbacks;
|
||||||
|
std::mutex m_queued_callbacks_lock;
|
||||||
|
|
||||||
|
bool m_quit_request = false;
|
||||||
|
};
|
|
@ -1,41 +1,61 @@
|
||||||
#include "sdl_host_interface.h"
|
#include "sdl_host_interface.h"
|
||||||
#include "common/assert.h"
|
#include "frontend-common/controller_interface.h"
|
||||||
#include "common/byte_stream.h"
|
|
||||||
#include "common/file_system.h"
|
|
||||||
#include "common/image.h"
|
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/string_util.h"
|
|
||||||
#include "core/gpu.h"
|
|
||||||
#include "core/host_display.h"
|
|
||||||
#include "core/system.h"
|
|
||||||
#include "frontend-common/fullscreen_ui.h"
|
|
||||||
#include "frontend-common/icon.h"
|
#include "frontend-common/icon.h"
|
||||||
#include "frontend-common/imgui_fullscreen.h"
|
|
||||||
#include "frontend-common/imgui_styles.h"
|
|
||||||
#include "frontend-common/ini_settings_interface.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/sdl_controller_interface.h"
|
||||||
#include "frontend-common/vulkan_host_display.h"
|
#include "frontend-common/sdl_initializer.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_sdl.h"
|
#include "imgui_impl_sdl.h"
|
||||||
#include "imgui_stdlib.h"
|
|
||||||
#include "scmversion/scmversion.h"
|
#include "scmversion/scmversion.h"
|
||||||
#include "sdl_key_names.h"
|
#include "sdl_key_names.h"
|
||||||
#include "sdl_util.h"
|
#include <SDL_syswm.h>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
Log_SetChannel(SDLHostInterface);
|
Log_SetChannel(SDLHostInterface);
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef __APPLE__
|
||||||
#include "frontend-common/d3d11_host_display.h"
|
#include <objc/message.h>
|
||||||
|
struct NSView;
|
||||||
|
|
||||||
|
static NSView* GetContentViewFromWindow(NSWindow* window)
|
||||||
|
{
|
||||||
|
// window.contentView
|
||||||
|
return reinterpret_cast<NSView* (*)(id, SEL)>(objc_msgSend)(reinterpret_cast<id>(window), sel_getUid("contentView"));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SDLHostInterface::SDLHostInterface()
|
static float GetDPIScaleFactor(SDL_Window* window)
|
||||||
{
|
{
|
||||||
m_run_later_event_id = SDL_RegisterEvents(1);
|
#ifdef __APPLE__
|
||||||
|
static constexpr float DEFAULT_DPI = 72.0f;
|
||||||
|
#else
|
||||||
|
static constexpr float DEFAULT_DPI = 96.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
SDL_Window* dummy_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1,
|
||||||
|
SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
||||||
|
if (!dummy_window)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
const float scale = GetDPIScaleFactor(dummy_window);
|
||||||
|
|
||||||
|
SDL_DestroyWindow(dummy_window);
|
||||||
|
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
int display_index = SDL_GetWindowDisplayIndex(window);
|
||||||
|
float display_dpi = DEFAULT_DPI;
|
||||||
|
if (SDL_GetDisplayDPI(display_index, &display_dpi, nullptr, nullptr) != 0)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
return display_dpi / DEFAULT_DPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDLHostInterface::SDLHostInterface() = default;
|
||||||
|
|
||||||
SDLHostInterface::~SDLHostInterface() = default;
|
SDLHostInterface::~SDLHostInterface() = default;
|
||||||
|
|
||||||
const char* SDLHostInterface::GetFrontendName() const
|
const char* SDLHostInterface::GetFrontendName() const
|
||||||
|
@ -43,16 +63,76 @@ const char* SDLHostInterface::GetFrontendName() const
|
||||||
return "DuckStation NoGUI Frontend";
|
return "DuckStation NoGUI Frontend";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<SDLHostInterface> SDLHostInterface::Create()
|
||||||
|
{
|
||||||
|
return std::make_unique<SDLHostInterface>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLHostInterface::Initialize()
|
||||||
|
{
|
||||||
|
FrontendCommon::EnsureSDLInitialized();
|
||||||
|
|
||||||
|
if (!NoGUIHostInterface::Initialize())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLHostInterface::Shutdown()
|
||||||
|
{
|
||||||
|
NoGUIHostInterface::Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLHostInterface::IsFullscreen() const
|
||||||
|
{
|
||||||
|
return m_fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLHostInterface::SetFullscreen(bool enabled)
|
||||||
|
{
|
||||||
|
if (m_fullscreen == enabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||||
|
|
||||||
|
int window_width, window_height;
|
||||||
|
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||||
|
m_display->ResizeRenderWindow(window_width, window_height);
|
||||||
|
OnPlatformWindowResized(window_width, window_height, GetDPIScaleFactor(m_window));
|
||||||
|
|
||||||
|
m_fullscreen = enabled;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_window_height)
|
||||||
|
{
|
||||||
|
if (new_window_width <= 0 || new_window_height <= 0 || m_fullscreen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// use imgui scale as the dpr
|
||||||
|
const float dpi_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||||
|
const s32 scaled_width =
|
||||||
|
std::max<s32>(static_cast<s32>(std::ceil(static_cast<float>(new_window_width) * dpi_scale)), 1);
|
||||||
|
const s32 scaled_height = std::max<s32>(
|
||||||
|
static_cast<s32>(std::ceil(static_cast<float>(new_window_height) * dpi_scale)) + m_display->GetDisplayTopMargin(),
|
||||||
|
1);
|
||||||
|
|
||||||
|
SDL_SetWindowSize(m_window, scaled_width, scaled_height);
|
||||||
|
|
||||||
|
s32 window_width, window_height;
|
||||||
|
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||||
|
m_display->ResizeRenderWindow(window_width, window_height);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE static TinyString GetWindowTitle()
|
ALWAYS_INLINE static TinyString GetWindowTitle()
|
||||||
{
|
{
|
||||||
return TinyString::FromFormat("DuckStation %s (%s)", g_scm_tag_str, g_scm_branch_str);
|
return TinyString::FromFormat("DuckStation %s (%s)", g_scm_tag_str, g_scm_branch_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLHostInterface::CreateSDLWindow()
|
bool SDLHostInterface::CreatePlatformWindow()
|
||||||
{
|
{
|
||||||
static constexpr u32 DEFAULT_WINDOW_WIDTH = 1280;
|
|
||||||
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 720;
|
|
||||||
|
|
||||||
// Create window.
|
// Create window.
|
||||||
const u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
const u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
|
|
||||||
|
@ -63,7 +143,7 @@ bool SDLHostInterface::CreateSDLWindow()
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
{
|
{
|
||||||
// scale by default monitor's DPI
|
// scale by default monitor's DPI
|
||||||
float scale = SDLUtil::GetDPIScaleFactor(nullptr);
|
float scale = GetDPIScaleFactor(nullptr);
|
||||||
window_width = static_cast<u32>(std::round(static_cast<float>(window_width) * scale));
|
window_width = static_cast<u32>(std::round(static_cast<float>(window_width) * scale));
|
||||||
window_height = static_cast<u32>(std::round(static_cast<float>(window_height) * scale));
|
window_height = static_cast<u32>(std::round(static_cast<float>(window_height) * scale));
|
||||||
}
|
}
|
||||||
|
@ -88,179 +168,77 @@ bool SDLHostInterface::CreateSDLWindow()
|
||||||
if (m_fullscreen)
|
if (m_fullscreen)
|
||||||
SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_Init(m_window);
|
||||||
|
|
||||||
// Process events so that we have everything sorted out before creating a child window for the GL context (X11).
|
// Process events so that we have everything sorted out before creating a child window for the GL context (X11).
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLHostInterface::DestroySDLWindow()
|
void SDLHostInterface::DestroyPlatformWindow()
|
||||||
{
|
{
|
||||||
|
ImGui_ImplSDL2_Shutdown();
|
||||||
SDL_DestroyWindow(m_window);
|
SDL_DestroyWindow(m_window);
|
||||||
m_window = nullptr;
|
m_window = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLHostInterface::CreateDisplay()
|
std::optional<WindowInfo> SDLHostInterface::GetPlatformWindowInfo()
|
||||||
{
|
{
|
||||||
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
|
SDL_SysWMinfo syswm = {};
|
||||||
if (!wi.has_value())
|
SDL_VERSION(&syswm.version);
|
||||||
|
if (!SDL_GetWindowWMInfo(m_window, &syswm))
|
||||||
{
|
{
|
||||||
ReportError("Failed to get window info from SDL window");
|
Log_ErrorPrintf("SDL_GetWindowWMInfo failed");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (g_settings.gpu_renderer)
|
int window_width, window_height;
|
||||||
|
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||||
|
|
||||||
|
WindowInfo wi;
|
||||||
|
wi.surface_width = static_cast<u32>(window_width);
|
||||||
|
wi.surface_height = static_cast<u32>(window_height);
|
||||||
|
wi.surface_scale = GetDPIScaleFactor(m_window);
|
||||||
|
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
||||||
|
|
||||||
|
switch (syswm.subsystem)
|
||||||
{
|
{
|
||||||
case GPURenderer::HardwareVulkan:
|
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||||
m_display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
|
case SDL_SYSWM_WINDOWS:
|
||||||
break;
|
wi.type = WindowInfo::Type::Win32;
|
||||||
|
wi.window_handle = syswm.info.win.window;
|
||||||
case GPURenderer::HardwareOpenGL:
|
|
||||||
#ifndef WIN32
|
|
||||||
default:
|
|
||||||
#endif
|
|
||||||
m_display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
case GPURenderer::HardwareD3D11:
|
|
||||||
default:
|
|
||||||
m_display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert(m_display);
|
|
||||||
if (!m_display->CreateRenderDevice(wi.value(), g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
|
|
||||||
g_settings.gpu_threaded_presentation) ||
|
|
||||||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
|
|
||||||
g_settings.gpu_threaded_presentation))
|
|
||||||
{
|
|
||||||
ReportError("Failed to create/initialize display render device");
|
|
||||||
m_display.reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ImGui_ImplSDL2_Init(m_window) || !m_display->CreateImGuiContext())
|
|
||||||
{
|
|
||||||
ReportError("Failed to initialize ImGui SDL2 wrapper");
|
|
||||||
ImGui_ImplSDL2_Shutdown();
|
|
||||||
m_display->DestroyRenderDevice();
|
|
||||||
m_display.reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FullscreenUI::Initialize(this, m_settings_interface.get()) || !m_display->UpdateImGuiFontTexture())
|
|
||||||
{
|
|
||||||
ReportError("Failed to initialize fonts/fullscreen UI");
|
|
||||||
FullscreenUI::Shutdown();
|
|
||||||
m_display->DestroyImGuiContext();
|
|
||||||
ImGui_ImplSDL2_Shutdown();
|
|
||||||
m_display->DestroyRenderDevice();
|
|
||||||
m_display.reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fullscreen_ui_enabled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::DestroyDisplay()
|
|
||||||
{
|
|
||||||
FullscreenUI::Shutdown();
|
|
||||||
m_display->DestroyImGuiContext();
|
|
||||||
m_display->DestroyRenderDevice();
|
|
||||||
m_display.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::CreateImGuiContext()
|
|
||||||
{
|
|
||||||
const float framebuffer_scale = SDLUtil::GetDPIScaleFactor(m_window);
|
|
||||||
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGui::GetIO().IniFilename = nullptr;
|
|
||||||
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
|
|
||||||
ImGui::GetIO().DisplayFramebufferScale.x = framebuffer_scale;
|
|
||||||
ImGui::GetIO().DisplayFramebufferScale.y = framebuffer_scale;
|
|
||||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
|
||||||
|
|
||||||
ImGui::StyleColorsDarker();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::UpdateFramebufferScale()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
const float framebuffer_scale = SDLUtil::GetDPIScaleFactor(m_window);
|
|
||||||
if (framebuffer_scale != io.DisplayFramebufferScale.x)
|
|
||||||
{
|
|
||||||
io.DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale);
|
|
||||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGuiFullscreen::UpdateLayoutScale())
|
|
||||||
{
|
|
||||||
if (ImGuiFullscreen::UpdateFonts())
|
|
||||||
{
|
|
||||||
if (!m_display->UpdateImGuiFontTexture())
|
|
||||||
Panic("Failed to update font texture");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::AcquireHostDisplay()
|
|
||||||
{
|
|
||||||
// Handle renderer switch if required.
|
|
||||||
const HostDisplay::RenderAPI render_api = m_display->GetRenderAPI();
|
|
||||||
bool needs_switch = false;
|
|
||||||
switch (g_settings.gpu_renderer)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
case GPURenderer::HardwareD3D11:
|
|
||||||
needs_switch = (render_api != HostDisplay::RenderAPI::D3D11);
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case GPURenderer::HardwareVulkan:
|
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||||
needs_switch = (render_api != HostDisplay::RenderAPI::Vulkan);
|
case SDL_SYSWM_COCOA:
|
||||||
|
wi.type = WindowInfo::Type::MacOS;
|
||||||
|
wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case GPURenderer::HardwareOpenGL:
|
#ifdef SDL_VIDEO_DRIVER_X11
|
||||||
needs_switch = (render_api != HostDisplay::RenderAPI::OpenGL && render_api != HostDisplay::RenderAPI::OpenGLES);
|
case SDL_SYSWM_X11:
|
||||||
|
wi.type = WindowInfo::Type::X11;
|
||||||
|
wi.window_handle = reinterpret_cast<void*>(static_cast<uintptr_t>(syswm.info.x11.window));
|
||||||
|
wi.display_connection = syswm.info.x11.display;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
|
case SDL_SYSWM_WAYLAND:
|
||||||
|
wi.type = WindowInfo::Type::Wayland;
|
||||||
|
wi.window_handle = syswm.info.wl.surface;
|
||||||
|
wi.display_connection = syswm.info.wl.display;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case GPURenderer::Software:
|
|
||||||
default:
|
default:
|
||||||
needs_switch = false;
|
Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast<u32>(syswm.subsystem));
|
||||||
break;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_switch)
|
return wi;
|
||||||
{
|
|
||||||
ImGui::EndFrame();
|
|
||||||
DestroyDisplay();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CreateHostDisplayResources())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::ReleaseHostDisplay()
|
|
||||||
{
|
|
||||||
ReleaseHostDisplayResources();
|
|
||||||
|
|
||||||
// restore vsync, since we don't want to burn cycles at the menu
|
|
||||||
m_display->SetVSync(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CommonHostInterface::HostKeyCode> SDLHostInterface::GetHostKeyCode(const std::string_view key_code) const
|
std::optional<CommonHostInterface::HostKeyCode> SDLHostInterface::GetHostKeyCode(const std::string_view key_code) const
|
||||||
|
@ -272,197 +250,6 @@ std::optional<CommonHostInterface::HostKeyCode> SDLHostInterface::GetHostKeyCode
|
||||||
return static_cast<HostKeyCode>(*code);
|
return static_cast<HostKeyCode>(*code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLHostInterface::UpdateInputMap()
|
|
||||||
{
|
|
||||||
CommonHostInterface::UpdateInputMap(*m_settings_interface.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::OnSystemCreated()
|
|
||||||
{
|
|
||||||
CommonHostInterface::OnSystemCreated();
|
|
||||||
FullscreenUI::SystemCreated();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::OnSystemPaused(bool paused)
|
|
||||||
{
|
|
||||||
CommonHostInterface::OnSystemPaused(paused);
|
|
||||||
FullscreenUI::SystemPaused(paused);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::OnSystemDestroyed()
|
|
||||||
{
|
|
||||||
CommonHostInterface::OnSystemDestroyed();
|
|
||||||
ReportFormattedMessage("System shut down.");
|
|
||||||
FullscreenUI::SystemDestroyed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::OnRunningGameChanged()
|
|
||||||
{
|
|
||||||
CommonHostInterface::OnRunningGameChanged();
|
|
||||||
|
|
||||||
Settings old_settings(std::move(g_settings));
|
|
||||||
CommonHostInterface::LoadSettings(*m_settings_interface.get());
|
|
||||||
CommonHostInterface::ApplyGameSettings(true);
|
|
||||||
CommonHostInterface::FixIncompatibleSettings(true);
|
|
||||||
CheckForSettingsChanges(old_settings);
|
|
||||||
|
|
||||||
if (!System::GetRunningTitle().empty())
|
|
||||||
SDL_SetWindowTitle(m_window, System::GetRunningTitle().c_str());
|
|
||||||
else
|
|
||||||
SDL_SetWindowTitle(m_window, GetWindowTitle());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::RequestExit()
|
|
||||||
{
|
|
||||||
m_quit_request = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::RunLater(std::function<void()> callback)
|
|
||||||
{
|
|
||||||
SDL_Event ev = {};
|
|
||||||
ev.type = SDL_USEREVENT;
|
|
||||||
ev.user.code = m_run_later_event_id;
|
|
||||||
ev.user.data1 = new std::function<void()>(std::move(callback));
|
|
||||||
SDL_PushEvent(&ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::ApplySettings(bool display_osd_messages)
|
|
||||||
{
|
|
||||||
Settings old_settings(std::move(g_settings));
|
|
||||||
CommonHostInterface::LoadSettings(*m_settings_interface.get());
|
|
||||||
CommonHostInterface::ApplyGameSettings(display_osd_messages);
|
|
||||||
CommonHostInterface::FixIncompatibleSettings(display_osd_messages);
|
|
||||||
CheckForSettingsChanges(old_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::IsFullscreen() const
|
|
||||||
{
|
|
||||||
return m_fullscreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::SetFullscreen(bool enabled)
|
|
||||||
{
|
|
||||||
if (m_fullscreen == enabled)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
||||||
|
|
||||||
int window_width, window_height;
|
|
||||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
|
||||||
m_display->ResizeRenderWindow(window_width, window_height);
|
|
||||||
|
|
||||||
if (!System::IsShutdown())
|
|
||||||
g_gpu->UpdateResolutionScale();
|
|
||||||
|
|
||||||
m_fullscreen = enabled;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SDLHostInterface> SDLHostInterface::Create()
|
|
||||||
{
|
|
||||||
return std::make_unique<SDLHostInterface>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::Initialize()
|
|
||||||
{
|
|
||||||
if (!CommonHostInterface::Initialize())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Change to the user directory so that all default/relative paths in the config are after this.
|
|
||||||
if (!FileSystem::SetWorkingDirectory(m_user_directory.c_str()))
|
|
||||||
Log_ErrorPrintf("Failed to set working directory to '%s'", m_user_directory.c_str());
|
|
||||||
|
|
||||||
if (!CreateSDLWindow())
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Failed to create SDL window");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateImGuiContext();
|
|
||||||
if (!CreateDisplay())
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("Failed to create host display");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process events to pick up controllers before updating input map
|
|
||||||
ProcessEvents();
|
|
||||||
UpdateInputMap();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::Shutdown()
|
|
||||||
{
|
|
||||||
DestroySystem();
|
|
||||||
|
|
||||||
CommonHostInterface::Shutdown();
|
|
||||||
|
|
||||||
if (m_display)
|
|
||||||
{
|
|
||||||
DestroyDisplay();
|
|
||||||
ImGui::DestroyContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_window)
|
|
||||||
DestroySDLWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SDLHostInterface::GetStringSettingValue(const char* section, const char* key,
|
|
||||||
const char* default_value /*= ""*/)
|
|
||||||
{
|
|
||||||
return m_settings_interface->GetStringValue(section, key, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::GetBoolSettingValue(const char* section, const char* key, bool default_value /* = false */)
|
|
||||||
{
|
|
||||||
return m_settings_interface->GetBoolValue(section, key, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SDLHostInterface::GetIntSettingValue(const char* section, const char* key, int default_value /* = 0 */)
|
|
||||||
{
|
|
||||||
return m_settings_interface->GetIntValue(section, key, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
float SDLHostInterface::GetFloatSettingValue(const char* section, const char* key, float default_value /* = 0.0f */)
|
|
||||||
{
|
|
||||||
return m_settings_interface->GetFloatValue(section, key, default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_window_height)
|
|
||||||
{
|
|
||||||
if (new_window_width <= 0 || new_window_height <= 0 || m_fullscreen)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// use imgui scale as the dpr
|
|
||||||
const float dpi_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
|
||||||
const s32 scaled_width =
|
|
||||||
std::max<s32>(static_cast<s32>(std::ceil(static_cast<float>(new_window_width) * dpi_scale)), 1);
|
|
||||||
const s32 scaled_height = std::max<s32>(
|
|
||||||
static_cast<s32>(std::ceil(static_cast<float>(new_window_height) * dpi_scale)) + m_display->GetDisplayTopMargin(),
|
|
||||||
1);
|
|
||||||
|
|
||||||
SDL_SetWindowSize(m_window, scaled_width, scaled_height);
|
|
||||||
|
|
||||||
s32 window_width, window_height;
|
|
||||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
|
||||||
m_display->ResizeRenderWindow(window_width, window_height);
|
|
||||||
|
|
||||||
UpdateFramebufferScale();
|
|
||||||
|
|
||||||
if (!System::IsShutdown())
|
|
||||||
g_gpu->UpdateResolutionScale();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::LoadSettings()
|
|
||||||
{
|
|
||||||
// Settings need to be loaded prior to creating the window for OpenGL bits.
|
|
||||||
m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName());
|
|
||||||
CommonHostInterface::LoadSettings(*m_settings_interface.get());
|
|
||||||
CommonHostInterface::FixIncompatibleSettings(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::ReportError(const char* message)
|
void SDLHostInterface::ReportError(const char* message)
|
||||||
{
|
{
|
||||||
const bool was_fullscreen = IsFullscreen();
|
const bool was_fullscreen = IsFullscreen();
|
||||||
|
@ -514,16 +301,35 @@ bool SDLHostInterface::ConfirmMessage(const char* message)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDLHostInterface::PollAndUpdate()
|
||||||
|
{
|
||||||
|
// Process SDL events before the controller interface can steal them.
|
||||||
|
const bool is_sdl_controller_interface =
|
||||||
|
(m_controller_interface && m_controller_interface->GetBackend() == ControllerInterface::Backend::SDL);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
SDL_Event ev;
|
||||||
|
if (!SDL_PollEvent(&ev))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (is_sdl_controller_interface &&
|
||||||
|
static_cast<SDLControllerInterface*>(m_controller_interface.get())->ProcessSDLEvent(&ev))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleSDLEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_NewFrame();
|
||||||
|
CommonHostInterface::PollAndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
||||||
{
|
{
|
||||||
ImGui_ImplSDL2_ProcessEvent(event);
|
ImGui_ImplSDL2_ProcessEvent(event);
|
||||||
|
|
||||||
if (m_controller_interface &&
|
|
||||||
static_cast<SDLControllerInterface*>(m_controller_interface.get())->ProcessSDLEvent(event))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event->type)
|
switch (event->type)
|
||||||
{
|
{
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
|
@ -531,14 +337,11 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
||||||
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
||||||
{
|
{
|
||||||
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
|
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
|
||||||
UpdateFramebufferScale();
|
OnPlatformWindowResized(event->window.data1, event->window.data2, GetDPIScaleFactor(m_window));
|
||||||
|
|
||||||
if (!System::IsShutdown())
|
|
||||||
g_gpu->UpdateResolutionScale();
|
|
||||||
}
|
}
|
||||||
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
|
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
|
||||||
{
|
{
|
||||||
UpdateFramebufferScale();
|
// TODO: Do we want to update DPI scale here?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -576,86 +379,5 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_USEREVENT:
|
|
||||||
{
|
|
||||||
if (static_cast<u32>(event->user.code) == m_run_later_event_id)
|
|
||||||
{
|
|
||||||
std::function<void()>* callback = static_cast<std::function<void()>*>(event->user.data1);
|
|
||||||
Assert(callback);
|
|
||||||
(*callback)();
|
|
||||||
delete callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::PollAndUpdate()
|
|
||||||
{
|
|
||||||
ProcessEvents();
|
|
||||||
CommonHostInterface::PollAndUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::ProcessEvents()
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
SDL_Event ev;
|
|
||||||
if (SDL_PollEvent(&ev))
|
|
||||||
HandleSDLEvent(&ev);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLHostInterface::Run()
|
|
||||||
{
|
|
||||||
while (!m_quit_request)
|
|
||||||
{
|
|
||||||
PollAndUpdate();
|
|
||||||
|
|
||||||
if (System::IsRunning())
|
|
||||||
{
|
|
||||||
if (m_display_all_frames)
|
|
||||||
System::RunFrame();
|
|
||||||
else
|
|
||||||
System::RunFrames();
|
|
||||||
|
|
||||||
UpdateControllerRumble();
|
|
||||||
if (m_frame_step_request)
|
|
||||||
{
|
|
||||||
m_frame_step_request = false;
|
|
||||||
PauseSystem(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rendering
|
|
||||||
{
|
|
||||||
ImGui_ImplSDL2_NewFrame();
|
|
||||||
FullscreenUI::SetImGuiNavInputs();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
DrawImGuiWindows();
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui::EndFrame();
|
|
||||||
|
|
||||||
m_display->Render();
|
|
||||||
|
|
||||||
if (System::IsRunning())
|
|
||||||
{
|
|
||||||
System::UpdatePerformanceCounters();
|
|
||||||
|
|
||||||
if (m_throttler_enabled)
|
|
||||||
System::Throttle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save state on exit so it can be resumed
|
|
||||||
if (!System::IsShutdown())
|
|
||||||
{
|
|
||||||
if (g_settings.save_state_on_exit)
|
|
||||||
SaveResumeSaveState();
|
|
||||||
DestroySystem();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/gl/program.h"
|
#include "nogui_host_interface.h"
|
||||||
#include "common/gl/texture.h"
|
|
||||||
#include "core/host_display.h"
|
|
||||||
#include "core/host_interface.h"
|
|
||||||
#include "frontend-common/common_host_interface.h"
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <array>
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class AudioStream;
|
class SDLHostInterface final : public NoGUIHostInterface
|
||||||
|
|
||||||
class INISettingsInterface;
|
|
||||||
|
|
||||||
struct GameListEntry;
|
|
||||||
|
|
||||||
class SDLHostInterface final : public CommonHostInterface
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDLHostInterface();
|
SDLHostInterface();
|
||||||
|
@ -35,53 +19,23 @@ public:
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") override;
|
|
||||||
bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false) override;
|
|
||||||
int GetIntSettingValue(const char* section, const char* key, int default_value = 0) override;
|
|
||||||
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
|
||||||
|
|
||||||
bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override;
|
bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override;
|
||||||
|
|
||||||
bool IsFullscreen() const override;
|
bool IsFullscreen() const override;
|
||||||
bool SetFullscreen(bool enabled) override;
|
bool SetFullscreen(bool enabled) override;
|
||||||
|
|
||||||
void RunLater(std::function<void()> callback) override;
|
|
||||||
void ApplySettings(bool display_osd_messages) override;
|
|
||||||
|
|
||||||
void Run();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void LoadSettings() override;
|
|
||||||
|
|
||||||
bool AcquireHostDisplay() override;
|
|
||||||
void ReleaseHostDisplay() override;
|
|
||||||
|
|
||||||
void OnSystemCreated() override;
|
|
||||||
void OnSystemPaused(bool paused) override;
|
|
||||||
void OnSystemDestroyed() override;
|
|
||||||
void OnRunningGameChanged() override;
|
|
||||||
|
|
||||||
void RequestExit() override;
|
|
||||||
void PollAndUpdate() override;
|
void PollAndUpdate() override;
|
||||||
|
|
||||||
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
|
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
|
||||||
void UpdateInputMap() override;
|
|
||||||
|
bool CreatePlatformWindow() override;
|
||||||
|
void DestroyPlatformWindow() override;
|
||||||
|
std::optional<WindowInfo> GetPlatformWindowInfo() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateSDLWindow();
|
|
||||||
void DestroySDLWindow();
|
|
||||||
bool CreateDisplay();
|
|
||||||
void DestroyDisplay();
|
|
||||||
void CreateImGuiContext();
|
|
||||||
void UpdateFramebufferScale();
|
|
||||||
|
|
||||||
void HandleSDLEvent(const SDL_Event* event);
|
void HandleSDLEvent(const SDL_Event* event);
|
||||||
void ProcessEvents();
|
|
||||||
|
|
||||||
SDL_Window* m_window = nullptr;
|
SDL_Window* m_window = nullptr;
|
||||||
std::unique_ptr<INISettingsInterface> m_settings_interface;
|
|
||||||
u32 m_run_later_event_id = 0;
|
|
||||||
|
|
||||||
bool m_fullscreen = false;
|
bool m_fullscreen = false;
|
||||||
bool m_quit_request = false;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
#include "sdl_util.h"
|
|
||||||
#include "common/log.h"
|
|
||||||
#include <SDL_syswm.h>
|
|
||||||
Log_SetChannel(SDLUtil);
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <objc/message.h>
|
|
||||||
struct NSView;
|
|
||||||
|
|
||||||
static NSView* GetContentViewFromWindow(NSWindow* window)
|
|
||||||
{
|
|
||||||
// window.contentView
|
|
||||||
return reinterpret_cast<NSView* (*)(id, SEL)>(objc_msgSend)(reinterpret_cast<id>(window), sel_getUid("contentView"));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace SDLUtil {
|
|
||||||
|
|
||||||
std::optional<WindowInfo> GetWindowInfoForSDLWindow(SDL_Window* window)
|
|
||||||
{
|
|
||||||
SDL_SysWMinfo syswm = {};
|
|
||||||
SDL_VERSION(&syswm.version);
|
|
||||||
if (!SDL_GetWindowWMInfo(window, &syswm))
|
|
||||||
{
|
|
||||||
Log_ErrorPrintf("SDL_GetWindowWMInfo failed");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int window_width, window_height;
|
|
||||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
|
||||||
|
|
||||||
WindowInfo wi;
|
|
||||||
wi.surface_width = static_cast<u32>(window_width);
|
|
||||||
wi.surface_height = static_cast<u32>(window_height);
|
|
||||||
wi.surface_scale = GetDPIScaleFactor(window);
|
|
||||||
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
|
||||||
|
|
||||||
switch (syswm.subsystem)
|
|
||||||
{
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
|
||||||
case SDL_SYSWM_WINDOWS:
|
|
||||||
wi.type = WindowInfo::Type::Win32;
|
|
||||||
wi.window_handle = syswm.info.win.window;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_COCOA
|
|
||||||
case SDL_SYSWM_COCOA:
|
|
||||||
wi.type = WindowInfo::Type::MacOS;
|
|
||||||
wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11
|
|
||||||
case SDL_SYSWM_X11:
|
|
||||||
wi.type = WindowInfo::Type::X11;
|
|
||||||
wi.window_handle = reinterpret_cast<void*>(static_cast<uintptr_t>(syswm.info.x11.window));
|
|
||||||
wi.display_connection = syswm.info.x11.display;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
|
||||||
case SDL_SYSWM_WAYLAND:
|
|
||||||
wi.type = WindowInfo::Type::Wayland;
|
|
||||||
wi.window_handle = syswm.info.wl.surface;
|
|
||||||
wi.display_connection = syswm.info.wl.display;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast<u32>(syswm.subsystem));
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wi;
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetDPIScaleFactor(SDL_Window* window)
|
|
||||||
{
|
|
||||||
#ifdef __APPLE__
|
|
||||||
static constexpr float DEFAULT_DPI = 72.0f;
|
|
||||||
#else
|
|
||||||
static constexpr float DEFAULT_DPI = 96.0f;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!window)
|
|
||||||
{
|
|
||||||
SDL_Window* dummy_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1,
|
|
||||||
SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
|
||||||
if (!dummy_window)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
const float scale = GetDPIScaleFactor(dummy_window);
|
|
||||||
|
|
||||||
SDL_DestroyWindow(dummy_window);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
int display_index = SDL_GetWindowDisplayIndex(window);
|
|
||||||
float display_dpi = DEFAULT_DPI;
|
|
||||||
if (SDL_GetDisplayDPI(display_index, &display_dpi, nullptr, nullptr) != 0)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
return display_dpi / DEFAULT_DPI;
|
|
||||||
}
|
|
||||||
} // namespace SDLUtil
|
|
|
@ -1,11 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "common/types.h"
|
|
||||||
#include "common/window_info.h"
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
struct SDL_Window;
|
|
||||||
|
|
||||||
namespace SDLUtil {
|
|
||||||
std::optional<WindowInfo> GetWindowInfoForSDLWindow(SDL_Window* window);
|
|
||||||
float GetDPIScaleFactor(SDL_Window* window);
|
|
||||||
}
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
#include "win32_host_interface.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "resource.h"
|
||||||
|
#include <tchar.h>
|
||||||
|
Log_SetChannel(Win32HostInterface);
|
||||||
|
|
||||||
|
static constexpr _TCHAR WINDOW_CLASS_NAME[] = _T("DuckStationNoGUI");
|
||||||
|
|
||||||
|
Win32HostInterface::Win32HostInterface() = default;
|
||||||
|
|
||||||
|
Win32HostInterface::~Win32HostInterface() = default;
|
||||||
|
|
||||||
|
std::unique_ptr<NoGUIHostInterface> Win32HostInterface::Create()
|
||||||
|
{
|
||||||
|
return std::make_unique<Win32HostInterface>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32HostInterface::Initialize()
|
||||||
|
{
|
||||||
|
if (!RegisterWindowClass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!NoGUIHostInterface::Initialize())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32HostInterface::Shutdown()
|
||||||
|
{
|
||||||
|
NoGUIHostInterface::Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32HostInterface::RegisterWindowClass()
|
||||||
|
{
|
||||||
|
WNDCLASSEXW wc = {};
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||||
|
wc.style = 0;
|
||||||
|
wc.lpfnWndProc = WndProc;
|
||||||
|
wc.cbClsExtra = 0;
|
||||||
|
wc.cbWndExtra = 0;
|
||||||
|
wc.hInstance = GetModuleHandle(nullptr);
|
||||||
|
wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_ICON1);
|
||||||
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||||
|
wc.lpszMenuName = NULL;
|
||||||
|
wc.lpszClassName = WINDOW_CLASS_NAME;
|
||||||
|
wc.hIconSm = LoadIconA(NULL, (LPCSTR)IDI_ICON1);
|
||||||
|
|
||||||
|
if (!RegisterClassExW(&wc))
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "Window registration failed.", "Error", MB_ICONERROR | MB_OK);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Win32HostInterface::CreatePlatformWindow()
|
||||||
|
{
|
||||||
|
m_hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WINDOW_CLASS_NAME, _T("DuckStation"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
|
||||||
|
CW_USEDEFAULT, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, nullptr, nullptr,
|
||||||
|
GetModuleHandleA(nullptr), this);
|
||||||
|
if (!m_hwnd)
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "CreateWindowEx failed.", "Error", MB_ICONERROR | MB_OK);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowWindow(m_hwnd, SW_SHOW);
|
||||||
|
UpdateWindow(m_hwnd);
|
||||||
|
ProcessWin32Events();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32HostInterface::DestroyPlatformWindow()
|
||||||
|
{
|
||||||
|
if (m_hwnd)
|
||||||
|
{
|
||||||
|
DestroyWindow(m_hwnd);
|
||||||
|
m_hwnd = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<WindowInfo> Win32HostInterface::GetPlatformWindowInfo()
|
||||||
|
{
|
||||||
|
RECT rc = {};
|
||||||
|
GetClientRect(m_hwnd, &rc);
|
||||||
|
|
||||||
|
WindowInfo wi;
|
||||||
|
wi.window_handle = static_cast<void*>(m_hwnd);
|
||||||
|
wi.type = WindowInfo::Type::Win32;
|
||||||
|
wi.surface_width = static_cast<u32>(rc.right - rc.left);
|
||||||
|
wi.surface_height = static_cast<u32>(rc.bottom - rc.top);
|
||||||
|
// wi.surface_format = WindowInfo::SurfaceFormat::Auto;
|
||||||
|
return wi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32HostInterface::PollAndUpdate()
|
||||||
|
{
|
||||||
|
ProcessWin32Events();
|
||||||
|
|
||||||
|
NoGUIHostInterface::PollAndUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Win32HostInterface::ProcessWin32Events()
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
while (PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT Win32HostInterface::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
Win32HostInterface* hi = static_cast<Win32HostInterface*>(g_host_interface);
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_SIZE:
|
||||||
|
{
|
||||||
|
const u32 width = LOWORD(lParam);
|
||||||
|
const u32 height = HIWORD(lParam);
|
||||||
|
if (hi->m_display)
|
||||||
|
hi->m_display->ResizeRenderWindow(static_cast<s32>(width), static_cast<s32>(height));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_CLOSE:
|
||||||
|
hi->m_quit_request = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Win32HostInterface::HostKeyCode> Win32HostInterface::GetHostKeyCode(const std::string_view key_code) const
|
||||||
|
{
|
||||||
|
std::optional<int> kc; // = EvDevKeyNames::GetKeyCodeForName(key_code);
|
||||||
|
if (!kc.has_value())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return static_cast<HostKeyCode>(kc.value());
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
#include "nogui_host_interface.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Win32HostInterface final : public NoGUIHostInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Win32HostInterface();
|
||||||
|
~Win32HostInterface();
|
||||||
|
|
||||||
|
bool Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
static std::unique_ptr<NoGUIHostInterface> Create();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool CreatePlatformWindow() override;
|
||||||
|
void DestroyPlatformWindow() override;
|
||||||
|
std::optional<WindowInfo> GetPlatformWindowInfo() override;
|
||||||
|
|
||||||
|
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
|
||||||
|
|
||||||
|
void PollAndUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
bool RegisterWindowClass();
|
||||||
|
void ProcessWin32Events();
|
||||||
|
|
||||||
|
HWND m_hwnd{};
|
||||||
|
};
|
Loading…
Reference in New Issue