mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +00:00
SDL: Support high-dpi displays
This commit is contained in:
parent
a0a0cd48fa
commit
ce31c85983
|
@ -17,6 +17,7 @@ if(WIN32)
|
|||
target_sources(duckstation-sdl PRIVATE
|
||||
d3d11_host_display.cpp
|
||||
d3d11_host_display.h
|
||||
duckstation-sdl.manifest
|
||||
)
|
||||
target_link_libraries(duckstation-sdl PRIVATE d3d11.lib dxgi.lib ${SDL2MAIN_LIBRARIES})
|
||||
endif()
|
||||
|
|
|
@ -156,10 +156,6 @@ std::tuple<u32, u32> D3D11HostDisplay::GetWindowSize() const
|
|||
|
||||
void D3D11HostDisplay::WindowResized()
|
||||
{
|
||||
SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
m_swap_chain_rtv.Reset();
|
||||
|
||||
HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN,
|
||||
|
@ -169,6 +165,15 @@ void D3D11HostDisplay::WindowResized()
|
|||
|
||||
if (!CreateSwapChainRTV())
|
||||
Panic("Failed to recreate swap chain RTV after resize");
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC desc;
|
||||
if (SUCCEEDED(m_swap_chain->GetDesc(&desc)))
|
||||
{
|
||||
m_window_width = static_cast<int>(desc.BufferDesc.Width);
|
||||
m_window_height = static_cast<int>(desc.BufferDesc.Height);
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
}
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateD3DDevice(bool debug_device)
|
||||
|
@ -334,6 +339,9 @@ bool D3D11HostDisplay::CreateD3DResources()
|
|||
|
||||
bool D3D11HostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
if (!ImGui_ImplSDL2_InitForD3D(m_window) || !ImGui_ImplDX11_Init(m_device.Get(), m_context.Get()))
|
||||
return false;
|
||||
|
||||
|
|
17
src/duckstation-sdl/duckstation-sdl.manifest
Normal file
17
src/duckstation-sdl/duckstation-sdl.manifest
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
|
@ -66,6 +66,9 @@
|
|||
<ClInclude Include="sdl_host_interface.h" />
|
||||
<ClInclude Include="sdl_settings_interface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="duckstation-sdl.manifest" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
|
|
|
@ -15,4 +15,7 @@
|
|||
<ClInclude Include="sdl_settings_interface.h" />
|
||||
<ClInclude Include="imgui_impl_sdl.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="duckstation-sdl.manifest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -388,15 +388,6 @@ void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
|
|||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||
|
|
|
@ -138,7 +138,7 @@ std::tuple<u32, u32> OpenGLHostDisplay::GetWindowSize() const
|
|||
|
||||
void OpenGLHostDisplay::WindowResized()
|
||||
{
|
||||
SDL_GetWindowSize(m_window, &m_window_width, &m_window_height);
|
||||
SDL_GL_GetDrawableSize(m_window, &m_window_width, &m_window_height);
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
}
|
||||
|
@ -264,6 +264,9 @@ bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
|
|||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
// this can change due to retina scaling on macos?
|
||||
SDL_GL_GetDrawableSize(m_window, &m_window_width, &m_window_height);
|
||||
|
||||
// start with vsync on
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
return true;
|
||||
|
@ -271,6 +274,9 @@ bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
|
|||
|
||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, m_gl_context) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -43,17 +43,60 @@ SDLHostInterface::~SDLHostInterface()
|
|||
DestroySDLWindow();
|
||||
}
|
||||
|
||||
float SDLHostInterface::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;
|
||||
}
|
||||
|
||||
bool SDLHostInterface::CreateSDLWindow()
|
||||
{
|
||||
constexpr u32 DEFAULT_WINDOW_WIDTH = 900;
|
||||
constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
|
||||
static constexpr u32 DEFAULT_WINDOW_WIDTH = 900;
|
||||
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
|
||||
|
||||
// Create window.
|
||||
const u32 window_flags =
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | (UseOpenGLRenderer() ? SDL_WINDOW_OPENGL : 0);
|
||||
|
||||
m_window = SDL_CreateWindow("DuckStation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DEFAULT_WINDOW_WIDTH,
|
||||
DEFAULT_WINDOW_HEIGHT, window_flags);
|
||||
u32 window_width = DEFAULT_WINDOW_WIDTH;
|
||||
u32 window_height = DEFAULT_WINDOW_HEIGHT;
|
||||
|
||||
// macOS does DPI scaling differently..
|
||||
#ifndef __APPLE__
|
||||
{
|
||||
// scale by default monitor's DPI
|
||||
float scale = GetDPIScaleFactor(nullptr);
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
m_window = SDL_CreateWindow("DuckStation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width,
|
||||
window_height, window_flags);
|
||||
if (!m_window)
|
||||
return false;
|
||||
|
||||
|
@ -113,12 +156,24 @@ void SDLHostInterface::DestroyDisplay()
|
|||
|
||||
void SDLHostInterface::CreateImGuiContext()
|
||||
{
|
||||
const float framebuffer_scale = GetDPIScaleFactor(m_window);
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
ImGui::GetIO().DisplayFramebufferScale.x = framebuffer_scale;
|
||||
ImGui::GetIO().DisplayFramebufferScale.y = framebuffer_scale;
|
||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||
|
||||
ImGui::StyleColorsDarker();
|
||||
ImGui::AddRobotoRegularFont();
|
||||
ImGui::AddRobotoRegularFont(15.0f * framebuffer_scale);
|
||||
}
|
||||
|
||||
void SDLHostInterface::UpdateFramebufferScale()
|
||||
{
|
||||
const float framebuffer_scale = GetDPIScaleFactor(m_window);
|
||||
ImGui::GetIO().DisplayFramebufferScale.x = framebuffer_scale;
|
||||
ImGui::GetIO().DisplayFramebufferScale.y = framebuffer_scale;
|
||||
}
|
||||
|
||||
bool SDLHostInterface::AcquireHostDisplay()
|
||||
|
@ -315,7 +370,14 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
|||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
||||
{
|
||||
m_display->WindowResized();
|
||||
UpdateFramebufferScale();
|
||||
}
|
||||
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
|
||||
{
|
||||
UpdateFramebufferScale();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -722,9 +784,11 @@ void SDLHostInterface::DrawMainMenuBar()
|
|||
|
||||
if (m_system)
|
||||
{
|
||||
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
if (!m_paused)
|
||||
{
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - 210.0f);
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - (210.0f * framebuffer_scale));
|
||||
|
||||
const float speed = m_system->GetEmulationSpeed();
|
||||
const u32 rounded_speed = static_cast<u32>(std::round(speed));
|
||||
|
@ -735,15 +799,15 @@ void SDLHostInterface::DrawMainMenuBar()
|
|||
else
|
||||
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%u%%", rounded_speed);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - 165.0f);
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - (165.0f * framebuffer_scale));
|
||||
ImGui::Text("FPS: %.2f", m_system->GetFPS());
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - 80.0f);
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - (80.0f * framebuffer_scale));
|
||||
ImGui::Text("VPS: %.2f", m_system->GetVPS());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - 50.0f);
|
||||
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - (50.0f * framebuffer_scale));
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Paused");
|
||||
}
|
||||
}
|
||||
|
@ -875,12 +939,14 @@ void SDLHostInterface::DrawDebugMenu()
|
|||
|
||||
void SDLHostInterface::DrawPoweredOffWindow()
|
||||
{
|
||||
constexpr int WINDOW_WIDTH = 400;
|
||||
constexpr int WINDOW_HEIGHT = 650;
|
||||
constexpr int BUTTON_WIDTH = 200;
|
||||
constexpr int BUTTON_HEIGHT = 40;
|
||||
static constexpr int WINDOW_WIDTH = 400;
|
||||
static constexpr int WINDOW_HEIGHT = 650;
|
||||
static constexpr int BUTTON_WIDTH = 200;
|
||||
static constexpr int BUTTON_HEIGHT = 40;
|
||||
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(WINDOW_WIDTH, WINDOW_HEIGHT));
|
||||
ImGui::SetNextWindowSize(ImVec2(static_cast<float>(WINDOW_WIDTH) * framebuffer_scale,
|
||||
static_cast<float>(WINDOW_HEIGHT) * framebuffer_scale));
|
||||
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f),
|
||||
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
|
||||
|
@ -892,15 +958,17 @@ void SDLHostInterface::DrawPoweredOffWindow()
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::SetCursorPosX((WINDOW_WIDTH - APP_ICON_WIDTH) / 2);
|
||||
ImGui::Image(m_app_icon_texture->GetHandle(), ImVec2(APP_ICON_WIDTH, APP_ICON_HEIGHT));
|
||||
ImGui::SetCursorPosY(APP_ICON_HEIGHT + 32);
|
||||
ImGui::SetCursorPosX(static_cast<float>((WINDOW_WIDTH - APP_ICON_WIDTH) / 2) * framebuffer_scale);
|
||||
ImGui::Image(m_app_icon_texture->GetHandle(), ImVec2(static_cast<float>(APP_ICON_WIDTH) * framebuffer_scale,
|
||||
static_cast<float>(APP_ICON_HEIGHT) * framebuffer_scale));
|
||||
ImGui::SetCursorPosY(static_cast<float>(APP_ICON_HEIGHT + 32) * framebuffer_scale);
|
||||
|
||||
static const ImVec2 button_size(static_cast<float>(BUTTON_WIDTH), static_cast<float>(BUTTON_HEIGHT));
|
||||
constexpr float button_left = static_cast<float>((WINDOW_WIDTH - BUTTON_WIDTH) / 2);
|
||||
const ImVec2 button_size(static_cast<float>(BUTTON_WIDTH) * framebuffer_scale,
|
||||
static_cast<float>(BUTTON_HEIGHT) * framebuffer_scale);
|
||||
const float button_left = static_cast<float>((WINDOW_WIDTH - BUTTON_WIDTH) / 2) * framebuffer_scale;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.0f * framebuffer_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * framebuffer_scale);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, 0xFF202020);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF808080);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF575757);
|
||||
|
@ -972,9 +1040,11 @@ static bool DrawSettingsSectionHeader(const char* title)
|
|||
|
||||
void SDLHostInterface::DrawSettingsWindow()
|
||||
{
|
||||
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f),
|
||||
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(500 * framebuffer_scale, 400.0f * framebuffer_scale), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (!ImGui::Begin("Settings", &m_settings_window_open, ImGuiWindowFlags_NoResize))
|
||||
{
|
||||
|
@ -986,7 +1056,7 @@ void SDLHostInterface::DrawSettingsWindow()
|
|||
|
||||
if (ImGui::BeginTabBar("SettingsTabBar", 0))
|
||||
{
|
||||
const float indent = 150.0f;
|
||||
const float indent = 150.0f * framebuffer_scale;
|
||||
|
||||
if (ImGui::BeginTabItem("General"))
|
||||
{
|
||||
|
@ -1203,12 +1273,6 @@ void SDLHostInterface::DrawSettingsWindow()
|
|||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
const auto window_size = ImGui::GetWindowSize();
|
||||
ImGui::SetCursorPosX(window_size.x - 50.0f);
|
||||
ImGui::SetCursorPosY(window_size.y - 30.0f);
|
||||
if (ImGui::Button("Close"))
|
||||
m_settings_window_open = false;
|
||||
|
||||
ImGui::End();
|
||||
|
||||
if (settings_changed)
|
||||
|
@ -1222,6 +1286,8 @@ void SDLHostInterface::DrawSettingsWindow()
|
|||
|
||||
void SDLHostInterface::DrawAboutWindow()
|
||||
{
|
||||
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f),
|
||||
ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
|
@ -1243,8 +1309,8 @@ void SDLHostInterface::DrawAboutWindow()
|
|||
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x - 60.0f) / 2.0f);
|
||||
if (ImGui::Button("Close", ImVec2(60.0f, 20.0f)))
|
||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x - (60.0f * framebuffer_scale)) / 2.0f);
|
||||
if (ImGui::Button("Close", ImVec2(60.0f * framebuffer_scale, 20.0f * framebuffer_scale)))
|
||||
m_about_window_open = false;
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
@ -1252,11 +1318,13 @@ void SDLHostInterface::DrawAboutWindow()
|
|||
|
||||
bool SDLHostInterface::DrawFileChooser(const char* label, std::string* path, const char* filter /* = nullptr */)
|
||||
{
|
||||
ImGui::SetNextItemWidth(ImGui::CalcItemWidth() - 50.0f);
|
||||
const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
ImGui::SetNextItemWidth((ImGui::CalcItemWidth() - 50.0f) * framebuffer_scale);
|
||||
bool result = ImGui::InputText(label, path);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetNextItemWidth(50.0f);
|
||||
ImGui::SetNextItemWidth(50.0f * framebuffer_scale);
|
||||
if (ImGui::Button("..."))
|
||||
{
|
||||
nfdchar_t* out_path = nullptr;
|
||||
|
|
|
@ -78,11 +78,14 @@ private:
|
|||
bool UseOpenGLRenderer() const { return true; }
|
||||
#endif
|
||||
|
||||
static float GetDPIScaleFactor(SDL_Window* window);
|
||||
|
||||
bool CreateSDLWindow();
|
||||
void DestroySDLWindow();
|
||||
bool CreateDisplay();
|
||||
void DestroyDisplay();
|
||||
void CreateImGuiContext();
|
||||
void UpdateFramebufferScale();
|
||||
|
||||
/// Executes a callback later, after the UI has finished rendering. Needed to boot while rendering ImGui.
|
||||
void RunLater(std::function<void()> callback);
|
||||
|
|
Loading…
Reference in a new issue