diff --git a/aurora/CMakeLists.txt b/aurora/CMakeLists.txt index 8d5592b4d..40498711c 100644 --- a/aurora/CMakeLists.txt +++ b/aurora/CMakeLists.txt @@ -17,7 +17,10 @@ add_library(aurora STATIC target_compile_definitions(aurora PRIVATE IMGUI_USER_CONFIG="imconfig_user.h") # IMGUI_USE_WCHAR32 target_include_directories(aurora PUBLIC include ../) target_include_directories(aurora PRIVATE ../imgui ../extern/imgui) -target_link_libraries(aurora PRIVATE dawn_native dawncpp webgpu_dawn zeus logvisor SDL2-static xxhash +if(NOT TARGET SDL2::SDL2-static) + find_package(SDL2 REQUIRED) +endif() +target_link_libraries(aurora PRIVATE dawn_native dawncpp webgpu_dawn zeus logvisor SDL2::SDL2-static xxhash absl::btree absl::flat_hash_map) if (DAWN_ENABLE_VULKAN) target_compile_definitions(aurora PRIVATE DAWN_ENABLE_BACKEND_VULKAN) @@ -36,3 +39,7 @@ if (DAWN_ENABLE_DESKTOP_GL) target_compile_definitions(aurora PRIVATE DAWN_ENABLE_BACKEND_OPENGL DAWN_ENABLE_BACKEND_DESKTOP_GL) target_sources(aurora PRIVATE lib/dawn/OpenGLBinding.cpp) endif () +if (DAWN_ENABLE_NULL) + target_compile_definitions(aurora PRIVATE DAWN_ENABLE_BACKEND_NULL) + target_sources(aurora PRIVATE lib/dawn/NullBinding.cpp) +endif () diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index 8870d104f..9c4ef91a5 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -65,7 +65,9 @@ static bool poll_events() noexcept { break; } case SDL_WINDOWEVENT_EXPOSED: +#if SDL_VERSION_ATLEAST(2, 0, 18) case SDL_WINDOWEVENT_DISPLAY_CHANGED: +#endif case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_MINIMIZED: @@ -224,7 +226,7 @@ static bool poll_events() noexcept { static SDL_Window* create_window(wgpu::BackendType type) { Uint32 flags = SDL_WINDOW_ALLOW_HIGHDPI; -#if TARGET_OS_IOS || TARGET_OS_TV +#if TARGET_OS_IOS || TARGET_OS_TV || defined(__SWITCH__) flags |= SDL_WINDOW_FULLSCREEN; #else flags |= SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; @@ -267,9 +269,12 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv, #if !defined(_WIN32) && !defined(__APPLE__) SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); #endif - SDL_SetHint(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, "1"); - +#if SDL_VERSION_ATLEAST(2, 0, 18) SDL_SetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, "Metaforce"); +#endif +#ifdef SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE + SDL_SetHint(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, "1"); +#endif SDL_DisableScreenSaver(); /* TODO: Make this an option rather than hard coding it */ @@ -292,8 +297,23 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv, unreachable(); } set_window_icon(std::move(icon)); - SDL_ShowWindow(g_window); + // Initialize SDL_Renderer for ImGui when we can't use a Dawn backend + SDL_Renderer* renderer = nullptr; + if (gpu::g_backendType == wgpu::BackendType::Null) { + const auto flags = SDL_RENDERER_PRESENTVSYNC; + renderer = SDL_CreateRenderer(g_window, -1, flags | SDL_RENDERER_ACCELERATED); + if (renderer == nullptr) { + // Attempt fallback to SW renderer + renderer = SDL_CreateRenderer(g_window, -1, flags); + } + if (renderer == nullptr) { + Log.report(logvisor::Fatal, FMT_STRING("Failed to initialize SDL renderer: {}"), SDL_GetError()); + unreachable(); + } + } + + SDL_ShowWindow(g_window); gfx::initialize(); imgui::create_context(); @@ -301,7 +321,7 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv, 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); + imgui::initialize(g_window, renderer); g_AppDelegate->onImGuiAddTextures(); g_AppDelegate->onAppLaunched(); @@ -360,6 +380,9 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv, imgui::shutdown(); gfx::shutdown(); gpu::shutdown(); + if (renderer != nullptr) { + SDL_DestroyRenderer(renderer); + } SDL_DestroyWindow(g_window); SDL_EnableScreenSaver(); SDL_Quit(); diff --git a/aurora/lib/dawn/BackendBinding.cpp b/aurora/lib/dawn/BackendBinding.cpp index 4615064fa..9a6f7e0ad 100644 --- a/aurora/lib/dawn/BackendBinding.cpp +++ b/aurora/lib/dawn/BackendBinding.cpp @@ -13,6 +13,9 @@ #include #include #endif +#if defined(DAWN_ENABLE_BACKEND_NULL) +#include +#endif namespace aurora::gpu::utils { @@ -69,6 +72,11 @@ bool DiscoverAdapter(dawn::native::Instance* instance, SDL_Window* window, wgpu: return instance->DiscoverAdapters(&adapterOptions); } } +#endif +#if defined(DAWN_ENABLE_BACKEND_NULL) + case wgpu::BackendType::Null: + instance->DiscoverDefaultAdapters(); + return true; #endif default: return false; diff --git a/aurora/lib/dawn/NullBinding.cpp b/aurora/lib/dawn/NullBinding.cpp new file mode 100644 index 000000000..7db94102e --- /dev/null +++ b/aurora/lib/dawn/NullBinding.cpp @@ -0,0 +1,27 @@ +#include "BackendBinding.hpp" + +#include +#include + +namespace aurora::gpu::utils { +class NullBinding : public BackendBinding { +public: + NullBinding(SDL_Window* window, WGPUDevice device) : BackendBinding(window, device) {} + + uint64_t GetSwapChainImplementation() override { + if (m_swapChainImpl.userData == nullptr) { + m_swapChainImpl = dawn::native::null::CreateNativeSwapChainImpl(); + } + return reinterpret_cast(&m_swapChainImpl); + } + + WGPUTextureFormat GetPreferredSwapChainTextureFormat() override { + return WGPUTextureFormat_RGBA8Unorm; + } + +private: + DawnSwapChainImplementation m_swapChainImpl{}; +}; + +BackendBinding* CreateNullBinding(SDL_Window* window, WGPUDevice device) { return new NullBinding(window, device); } +} // namespace aurora::gpu::utils diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index f0945d4b3..2b4a008e5 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -265,7 +265,7 @@ const stream::State& get_state() { } template <> void push_draw_command(stream::DrawData data) { - push_draw_command({.type = ShaderType::Stream, .stream = data}); + push_draw_command(ShaderDrawCommand{.type = ShaderType::Stream, .stream = data}); } template <> PipelineRef pipeline_ref(stream::PipelineConfig config) { @@ -274,7 +274,7 @@ PipelineRef pipeline_ref(stream::PipelineConfig config) { template <> void push_draw_command(model::DrawData data) { - push_draw_command({.type = ShaderType::Model, .model = data}); + push_draw_command(ShaderDrawCommand{.type = ShaderType::Model, .model = data}); } template <> PipelineRef pipeline_ref(model::PipelineConfig config) { diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 8ae8361c3..7dcbfa342 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -29,6 +29,8 @@ static inline std::string_view chan_comp(GX::TevColorChan chan) noexcept { return "b"; case GX::CH_ALPHA: return "a"; + default: + return "?"; } } @@ -116,26 +118,6 @@ static void color_arg_reg_info(GX::TevColorArg arg, const TevStage& stage, Shade static bool formatHasAlpha(GX::TextureFormat format) { switch (format) { - case GX::TF_I4: - case GX::TF_I8: - case GX::TF_RGB565: - case GX::TF_C4: - case GX::TF_C8: - case GX::TF_C14X2: - case GX::TF_Z8: - case GX::TF_Z16: - case GX::TF_Z24X8: - case GX::CTF_R4: - case GX::CTF_R8: - case GX::CTF_G8: - case GX::CTF_B8: - case GX::CTF_RG8: - case GX::CTF_GB8: - case GX::CTF_Z4: - case GX::CTF_Z8M: - case GX::CTF_Z8L: - case GX::CTF_Z16L: - return false; case GX::TF_IA4: case GX::TF_IA8: case GX::TF_RGB5A3: @@ -146,6 +128,8 @@ static bool formatHasAlpha(GX::TextureFormat format) { case GX::CTF_YUVA8: case GX::CTF_A8: return true; + default: + return false; } } diff --git a/aurora/lib/gpu.hpp b/aurora/lib/gpu.hpp index eb827ed5f..fb6f85639 100644 --- a/aurora/lib/gpu.hpp +++ b/aurora/lib/gpu.hpp @@ -47,6 +47,9 @@ constexpr std::array PreferredBackendOrder{ #ifdef DAWN_ENABLE_BACKEND_OPENGLES wgpu::BackendType::OpenGLES, #endif +#ifdef DAWN_ENABLE_BACKEND_NULL + wgpu::BackendType::Null, +#endif }; extern wgpu::Device g_device; diff --git a/aurora/lib/imgui.cpp b/aurora/lib/imgui.cpp index 2379f4e7b..24a35bc62 100644 --- a/aurora/lib/imgui.cpp +++ b/aurora/lib/imgui.cpp @@ -9,6 +9,7 @@ #include #include "../extern/imgui/backends/imgui_impl_sdl.cpp" +#include "../extern/imgui/backends/imgui_impl_sdlrenderer.cpp" #include "../extern/imgui/backends/imgui_impl_wgpu.cpp" namespace aurora::imgui { @@ -29,17 +30,27 @@ void create_context() noexcept { io.LogFilename = g_imguiLog.c_str(); } -void initialize(SDL_Window* window) noexcept { - ImGui_ImplSDL2_Init(window, nullptr); +static bool g_useSdlRenderer = false; +void initialize(SDL_Window* window, SDL_Renderer* renderer) noexcept { + ImGui_ImplSDL2_Init(window, renderer); #ifdef __APPLE__ // Disable MouseCanUseGlobalState for scaling purposes ImGui_ImplSDL2_GetBackendData()->MouseCanUseGlobalState = false; #endif - ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast(gpu::g_graphicsConfig.colorFormat)); + g_useSdlRenderer = renderer != nullptr; + if (g_useSdlRenderer) { + ImGui_ImplSDLRenderer_Init(renderer); + } else { + ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast(gpu::g_graphicsConfig.colorFormat)); + } } void shutdown() noexcept { - ImGui_ImplWGPU_Shutdown(); + if (g_useSdlRenderer) { + ImGui_ImplSDLRenderer_Shutdown(); + } else { + ImGui_ImplWGPU_Shutdown(); + } ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); } @@ -49,8 +60,7 @@ void process_event(const SDL_Event& event) noexcept { if (event.type == SDL_MOUSEMOTION) { auto& io = ImGui::GetIO(); // Scale up mouse coordinates - io.AddMousePosEvent(static_cast(event.motion.x) * g_scale, - static_cast(event.motion.y) * g_scale); + io.AddMousePosEvent(static_cast(event.motion.x) * g_scale, static_cast(event.motion.y) * g_scale); return; } #endif @@ -58,15 +68,19 @@ void process_event(const SDL_Event& event) noexcept { } void new_frame(const WindowSize& size) noexcept { - if (g_scale != size.scale) { - if (g_scale > 0.f) { - // TODO wgpu backend bug: doesn't clear bind groups on invalidate - g_resources.ImageBindGroups.Clear(); - ImGui_ImplWGPU_CreateDeviceObjects(); + if (g_useSdlRenderer) { + ImGui_ImplSDLRenderer_NewFrame(); + } else { + if (g_scale != size.scale) { + if (g_scale > 0.f) { + // TODO wgpu backend bug: doesn't clear bind groups on invalidate + g_resources.ImageBindGroups.Clear(); + ImGui_ImplWGPU_CreateDeviceObjects(); + } + g_scale = size.scale; } - g_scale = size.scale; + ImGui_ImplWGPU_NewFrame(); } - ImGui_ImplWGPU_NewFrame(); ImGui_ImplSDL2_NewFrame(); // Render at full DPI @@ -80,10 +94,24 @@ void render(const wgpu::RenderPassEncoder& pass) noexcept { 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()); + if (g_useSdlRenderer) { + SDL_Renderer* renderer = ImGui_ImplSDLRenderer_GetBackendData()->SDLRenderer; + SDL_RenderClear(renderer); + ImGui_ImplSDLRenderer_RenderDrawData(data); + SDL_RenderPresent(renderer); + } else { + ImGui_ImplWGPU_RenderDrawData(data, pass.Get()); + } } ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef data) noexcept { + if (g_useSdlRenderer) { + SDL_Renderer* renderer = ImGui_ImplSDLRenderer_GetBackendData()->SDLRenderer; + SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); + SDL_UpdateTexture(texture, nullptr, data.data(), width * 4); + SDL_SetTextureScaleMode(texture, SDL_ScaleModeLinear); + return texture; + } const auto size = wgpu::Extent3D{ .width = width, .height = height, diff --git a/aurora/lib/imgui.hpp b/aurora/lib/imgui.hpp index febbfb800..dba424277 100644 --- a/aurora/lib/imgui.hpp +++ b/aurora/lib/imgui.hpp @@ -1,5 +1,6 @@ #pragma once +struct SDL_Renderer; struct SDL_Window; union SDL_Event; @@ -13,7 +14,7 @@ struct WindowSize; namespace aurora::imgui { void create_context() noexcept; -void initialize(SDL_Window* window) noexcept; +void initialize(SDL_Window* window, SDL_Renderer* renderer) noexcept; void shutdown() noexcept; void process_event(const SDL_Event& event) noexcept; diff --git a/aurora/lib/input.cpp b/aurora/lib/input.cpp index f1ff32b1d..527e8da0e 100644 --- a/aurora/lib/input.cpp +++ b/aurora/lib/input.cpp @@ -5,6 +5,7 @@ #include "magic_enum.hpp" #include +#include #include #include @@ -103,7 +104,7 @@ static std::optional remap_controller_layout(std::string_view mappi Log.report(logvisor::Error, FMT_STRING("Controller has unsupported layout: {}"), mapping); return {}; } - for (const auto [k, v] : entries) { + for (auto [k, v] : entries) { newMapping.push_back(','); newMapping.append(k); newMapping.push_back(':'); @@ -140,7 +141,11 @@ Sint32 add_controller(Sint32 which) noexcept { return -1; } controller.m_isGameCube = controller.m_vid == 0x057E && controller.m_pid == 0x0337; +#if SDL_VERSION_ATLEAST(2, 0, 18) controller.m_hasRumble = (SDL_GameControllerHasRumble(ctrl) != 0u); +#else + controller.m_hasRumble = true; +#endif Sint32 instance = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)); g_GameControllers[instance] = controller; return instance;