aurora: DPI scaling fixes (renderer, imgui)

This commit is contained in:
Luke Street 2022-02-26 15:38:08 -05:00
parent 8e9199429d
commit 4b69cb449d
9 changed files with 86 additions and 61 deletions

View File

@ -417,7 +417,7 @@ public:
} }
void onAppWindowResized(const aurora::WindowSize& size) noexcept override { void onAppWindowResized(const aurora::WindowSize& size) noexcept override {
CGraphics::SetViewportResolution({static_cast<s32>(size.width), static_cast<s32>(size.height)}); CGraphics::SetViewportResolution({static_cast<s32>(size.fb_width), static_cast<s32>(size.fb_height)});
} }
void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept override { void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept override {

View File

@ -27,9 +27,6 @@ add_library(aurora STATIC
lib/gfx/movie_player/shader.cpp lib/gfx/movie_player/shader.cpp
lib/gfx/textured_quad/shader.cpp lib/gfx/textured_quad/shader.cpp
lib/gfx/colored_quad/shader.cpp lib/gfx/colored_quad/shader.cpp
# TODO move to imgui? or move imgui impl to here?
../extern/imgui/backends/imgui_impl_sdl.cpp
../extern/imgui/backends/imgui_impl_wgpu.cpp
) )
target_compile_definitions(aurora PRIVATE IMGUI_USER_CONFIG="imconfig_user.h") # IMGUI_USE_WCHAR32 target_compile_definitions(aurora PRIVATE IMGUI_USER_CONFIG="imconfig_user.h") # IMGUI_USE_WCHAR32
target_include_directories(aurora PUBLIC include ../Runtime) target_include_directories(aurora PUBLIC include ../Runtime)

View File

@ -174,6 +174,11 @@ struct Icon {
struct WindowSize { struct WindowSize {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
uint32_t fb_width;
uint32_t fb_height;
float scale;
bool operator<=>(const WindowSize& rhs) const = default;
}; };
enum class MouseButton { enum class MouseButton {
None = 0, None = 0,

View File

@ -15,10 +15,10 @@ static logvisor::Module Log("aurora");
// TODO: Move global state to a class/struct? // TODO: Move global state to a class/struct?
static std::unique_ptr<AppDelegate> g_AppDelegate; static std::unique_ptr<AppDelegate> g_AppDelegate;
static std::vector<std::string> g_Args; static std::vector<std::string> g_Args;
static float g_AppDpi = 1.f;
// SDL // SDL
static SDL_Window* g_Window; static SDL_Window* g_window;
static WindowSize g_windowSize;
// GPU // GPU
using gpu::g_depthBuffer; using gpu::g_depthBuffer;
@ -40,7 +40,7 @@ static void set_window_icon(Icon icon) noexcept {
Log.report(logvisor::Fatal, FMT_STRING("Failed to create icon surface: {}"), SDL_GetError()); Log.report(logvisor::Fatal, FMT_STRING("Failed to create icon surface: {}"), SDL_GetError());
unreachable(); unreachable();
} }
SDL_SetWindowIcon(g_Window, iconSurface); SDL_SetWindowIcon(g_window, iconSurface);
SDL_FreeSurface(iconSurface); SDL_FreeSurface(iconSurface);
} }
@ -58,26 +58,26 @@ static bool poll_events() noexcept {
case SDL_WINDOWEVENT_HIDDEN: { case SDL_WINDOWEVENT_HIDDEN: {
break; break;
} }
case SDL_WINDOWEVENT_EXPOSED: {
break;
}
case SDL_WINDOWEVENT_MOVED: { case SDL_WINDOWEVENT_MOVED: {
g_AppDelegate->onAppWindowMoved(event.window.data1, event.window.data2); g_AppDelegate->onAppWindowMoved(event.window.data1, event.window.data2);
break; break;
} }
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_DISPLAY_CHANGED:
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_RESIZED: { case SDL_WINDOWEVENT_MINIMIZED:
gpu::resize_swapchain(event.window.data1, event.window.data2);
g_AppDelegate->onAppWindowResized(
{static_cast<uint32_t>(event.window.data1), static_cast<uint32_t>(event.window.data2)});
break;
}
case SDL_WINDOWEVENT_MINIMIZED: {
// TODO: handle minimized event
break;
}
case SDL_WINDOWEVENT_MAXIMIZED: { case SDL_WINDOWEVENT_MAXIMIZED: {
// TODO: handle maximized event const auto size = get_window_size();
if (size == g_windowSize) {
break;
}
if (size.scale != g_windowSize.scale) {
g_AppDelegate->onAppDisplayScaleChanged(size.scale);
}
g_windowSize = size;
gpu::resize_swapchain(size.fb_width, size.fb_height);
g_AppDelegate->onAppWindowResized(size);
break; break;
} }
case SDL_WINDOWEVENT_RESTORED: { case SDL_WINDOWEVENT_RESTORED: {
@ -112,17 +112,6 @@ static bool poll_events() noexcept {
// TODO: handle hit test? // TODO: handle hit test?
break; break;
} }
case SDL_WINDOWEVENT_DISPLAY_CHANGED: {
printf("DISPLAY_CHANGED!\n");
float scale = 1.0f;
if (SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(g_Window), nullptr, &scale, nullptr) == 0) {
scale /= 96.0f;
if (g_AppDpi != scale) {
g_AppDelegate->onAppDisplayScaleChanged(scale);
}
}
break;
}
} }
break; break;
} }
@ -259,30 +248,29 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
default: default:
break; break;
} }
g_Window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, flags); g_window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, flags);
if (g_Window == nullptr) { if (g_window == nullptr) {
Log.report(logvisor::Fatal, FMT_STRING("Error creating window: {}"), SDL_GetError()); Log.report(logvisor::Fatal, FMT_STRING("Error creating window: {}"), SDL_GetError());
unreachable(); unreachable();
} }
set_window_icon(std::move(icon)); set_window_icon(std::move(icon));
gpu::initialize(g_Window); gpu::initialize(g_window);
gfx::initialize(); gfx::initialize();
g_AppDpi = 1.0f;
if (SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(g_Window), nullptr, &g_AppDpi, nullptr) == 0) {
g_AppDpi /= 96.0f;
}
imgui::create_context(); imgui::create_context();
g_AppDelegate->onImGuiInit(g_AppDpi); const auto size = get_window_size();
imgui::initialize(g_Window); Log.report(logvisor::Info, FMT_STRING("Using framebuffer size {}x{} scale {}"), size.fb_width, size.fb_height,
size.scale);
g_AppDelegate->onImGuiInit(size.scale);
imgui::initialize(g_window);
g_AppDelegate->onImGuiAddTextures(); g_AppDelegate->onImGuiAddTextures();
g_AppDelegate->onAppLaunched(); g_AppDelegate->onAppLaunched();
g_AppDelegate->onAppWindowResized(get_window_size()); g_AppDelegate->onAppWindowResized(size);
while (poll_events()) { while (poll_events()) {
imgui::new_frame(); imgui::new_frame(g_windowSize);
if (!g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime)) { if (!g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime)) {
break; break;
} }
@ -354,19 +342,26 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
imgui::shutdown(); imgui::shutdown();
gfx::shutdown(); gfx::shutdown();
gpu::shutdown(); gpu::shutdown();
SDL_DestroyWindow(g_Window); SDL_DestroyWindow(g_window);
SDL_Quit(); SDL_Quit();
} }
std::vector<std::string> get_args() noexcept { return g_Args; } std::vector<std::string> get_args() noexcept { return g_Args; }
WindowSize get_window_size() noexcept { WindowSize get_window_size() noexcept {
int width, height; int width, height, fb_w, fb_h;
SDL_GetWindowSize(g_Window, &width, &height); SDL_GetWindowSize(g_window, &width, &height);
return {static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; SDL_GL_GetDrawableSize(g_window, &fb_w, &fb_h);
return {
.width = static_cast<uint32_t>(width),
.height = static_cast<uint32_t>(height),
.fb_width = static_cast<uint32_t>(fb_w),
.fb_height = static_cast<uint32_t>(fb_h),
.scale = static_cast<float>(fb_w) / static_cast<float>(width),
};
} }
void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_Window, title.c_str()); } void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_window, title.c_str()); }
Backend get_backend() noexcept { Backend get_backend() noexcept {
switch (gpu::g_backendType) { switch (gpu::g_backendType) {
@ -392,7 +387,7 @@ Backend get_backend() noexcept {
std::string_view get_backend_string() noexcept { return magic_enum::enum_name(gpu::g_backendType); } std::string_view get_backend_string() noexcept { return magic_enum::enum_name(gpu::g_backendType); }
void set_fullscreen(bool fullscreen) noexcept { void set_fullscreen(bool fullscreen) noexcept {
SDL_SetWindowFullscreen(g_Window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); SDL_SetWindowFullscreen(g_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
} }
int32_t get_controller_player_index(uint32_t instance) noexcept { return input::player_index(instance); } int32_t get_controller_player_index(uint32_t instance) noexcept { return input::player_index(instance); }
@ -409,5 +404,6 @@ void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t
uint32_t duration_ms) noexcept { uint32_t duration_ms) noexcept {
input::controller_rumble(instance, low_freq_intensity, high_freq_intensity, duration_ms); input::controller_rumble(instance, low_freq_intensity, high_freq_intensity, duration_ms);
} }
std::string get_controller_name(uint32_t instance) noexcept { return input::controller_name(instance); } std::string get_controller_name(uint32_t instance) noexcept { return input::controller_name(instance); }
} // namespace aurora } // namespace aurora

View File

@ -1,10 +1,10 @@
#include "gpu.hpp" #include "gpu.hpp"
#include <SDL.h>
#include <dawn/native/DawnNative.h> #include <dawn/native/DawnNative.h>
#include <dawn/webgpu_cpp.h> #include <dawn/webgpu_cpp.h>
#include <logvisor/logvisor.hpp> #include <logvisor/logvisor.hpp>
#include <magic_enum.hpp> #include <magic_enum.hpp>
#include <SDL.h>
#include <memory> #include <memory>
#include "dawn/BackendBinding.hpp" #include "dawn/BackendBinding.hpp"
@ -168,7 +168,7 @@ void initialize(SDL_Window* window) {
{ {
int width = 0; int width = 0;
int height = 0; int height = 0;
SDL_GetWindowSize(window, &width, &height); SDL_GL_GetDrawableSize(window, &width, &height);
g_graphicsConfig = GraphicsConfig{ g_graphicsConfig = GraphicsConfig{
.width = static_cast<uint32_t>(width), .width = static_cast<uint32_t>(width),
.height = static_cast<uint32_t>(height), .height = static_cast<uint32_t>(height),

View File

@ -2,15 +2,20 @@
#include "gpu.hpp" #include "gpu.hpp"
#include <SDL.h>
#include <aurora/aurora.hpp>
#include <aurora/imgui.hpp> #include <aurora/imgui.hpp>
#include <backends/imgui_impl_sdl.h>
#include <backends/imgui_impl_wgpu.h>
#include <dawn/webgpu_cpp.h> #include <dawn/webgpu_cpp.h>
#include "../extern/imgui/backends/imgui_impl_sdl.cpp"
#include "../extern/imgui/backends/imgui_impl_wgpu.cpp"
namespace aurora::imgui { namespace aurora::imgui {
using gpu::g_device; using gpu::g_device;
using gpu::g_queue; using gpu::g_queue;
static float g_scale;
void create_context() noexcept { void create_context() noexcept {
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
@ -19,9 +24,9 @@ void create_context() noexcept {
} }
void initialize(SDL_Window* window) noexcept { void initialize(SDL_Window* window) noexcept {
// this just passes through to ImGui_ImplSDL2_Init (private) ImGui_ImplSDL2_Init(window, nullptr);
// may need to change in the future // Disable MouseCanUseGlobalState for scaling purposes
ImGui_ImplSDL2_InitForMetal(window); ImGui_ImplSDL2_GetBackendData()->MouseCanUseGlobalState = false;
ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast<WGPUTextureFormat>(gpu::g_graphicsConfig.colorFormat)); ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast<WGPUTextureFormat>(gpu::g_graphicsConfig.colorFormat));
} }
@ -31,17 +36,35 @@ void shutdown() noexcept {
ImGui::DestroyContext(); ImGui::DestroyContext();
} }
void process_event(const SDL_Event& event) noexcept { ImGui_ImplSDL2_ProcessEvent(&event); } void process_event(const SDL_Event& event) noexcept {
auto newEvent = event;
if (newEvent.type == SDL_MOUSEMOTION) {
auto& io = ImGui::GetIO();
// Scale up mouse coordinates
io.AddMousePosEvent(static_cast<float>(newEvent.motion.x) * g_scale,
static_cast<float>(newEvent.motion.y) * g_scale);
return;
}
ImGui_ImplSDL2_ProcessEvent(&newEvent);
}
void new_frame() noexcept { void new_frame(const WindowSize& size) noexcept {
ImGui_ImplWGPU_NewFrame(); ImGui_ImplWGPU_NewFrame();
ImGui_ImplSDL2_NewFrame(); ImGui_ImplSDL2_NewFrame();
// Render at full DPI
g_scale = size.scale;
ImGui::GetIO().DisplaySize = ImVec2{static_cast<float>(size.fb_width), static_cast<float>(size.fb_height)};
ImGui::NewFrame(); ImGui::NewFrame();
} }
void render(const wgpu::RenderPassEncoder& pass) noexcept { void render(const wgpu::RenderPassEncoder& pass) noexcept {
ImGui::Render(); ImGui::Render();
ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass.Get());
auto* data = ImGui::GetDrawData();
// io.DisplayFramebufferScale is informational; we're rendering at full DPI
data->FramebufferScale = {1.f, 1.f};
ImGui_ImplWGPU_RenderDrawData(data, pass.Get());
} }
ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data) noexcept { ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef<uint8_t> data) noexcept {

View File

@ -7,12 +7,16 @@ namespace wgpu {
class RenderPassEncoder; class RenderPassEncoder;
} // namespace wgpu } // namespace wgpu
namespace aurora {
struct WindowSize;
} // namespace aurora
namespace aurora::imgui { namespace aurora::imgui {
void create_context() noexcept; void create_context() noexcept;
void initialize(SDL_Window* window) noexcept; void initialize(SDL_Window* window) noexcept;
void shutdown() noexcept; void shutdown() noexcept;
void process_event(const SDL_Event& event) noexcept; void process_event(const SDL_Event& event) noexcept;
void new_frame() noexcept; void new_frame(const WindowSize& size) noexcept;
void render(const wgpu::RenderPassEncoder& pass) noexcept; void render(const wgpu::RenderPassEncoder& pass) noexcept;
} // namespace aurora::imgui } // namespace aurora::imgui

View File

@ -59,6 +59,7 @@ void ImGuiEngine_Initialize(float scale) {
ImGuiEngine::fontLarge = io.Fonts->AddFont(&fontConfig); ImGuiEngine::fontLarge = io.Fonts->AddFont(&fontConfig);
auto& style = ImGui::GetStyle(); auto& style = ImGui::GetStyle();
style = {}; // Reset sizes
style.WindowPadding = ImVec2(15, 15); style.WindowPadding = ImVec2(15, 15);
style.WindowRounding = 5.0f; style.WindowRounding = 5.0f;
style.FrameBorderSize = 1.f; style.FrameBorderSize = 1.f;

View File

@ -12,7 +12,6 @@ public:
static ImTextureID metaforceIcon; static ImTextureID metaforceIcon;
}; };
// Called from Rust
void ImGuiEngine_Initialize(float scale); void ImGuiEngine_Initialize(float scale);
void ImGuiEngine_AddTextures(); void ImGuiEngine_AddTextures();