mirror of https://github.com/AxioDL/metaforce.git
aurora: Null graphics backend with SDL_Renderer fallback
This commit is contained in:
parent
4048492279
commit
40a444d800
|
@ -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 ()
|
||||
|
|
|
@ -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<AppDelegate> 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<AppDelegate> 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<AppDelegate> 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<AppDelegate> 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();
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
#include <SDL_video.h>
|
||||
#include <dawn/native/OpenGLBackend.h>
|
||||
#endif
|
||||
#if defined(DAWN_ENABLE_BACKEND_NULL)
|
||||
#include <dawn/native/NullBackend.h>
|
||||
#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;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include "BackendBinding.hpp"
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include <dawn/native/NullBackend.h>
|
||||
|
||||
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<uint64_t>(&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
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <dawn/webgpu_cpp.h>
|
||||
|
||||
#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<WGPUTextureFormat>(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<WGPUTextureFormat>(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<float>(event.motion.x) * g_scale,
|
||||
static_cast<float>(event.motion.y) * g_scale);
|
||||
io.AddMousePosEvent(static_cast<float>(event.motion.x) * g_scale, static_cast<float>(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<uint8_t> 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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "magic_enum.hpp"
|
||||
|
||||
#include <SDL_haptic.h>
|
||||
#include <SDL_version.h>
|
||||
|
||||
#include <absl/container/btree_map.h>
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
|
@ -103,7 +104,7 @@ static std::optional<std::string> 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;
|
||||
|
|
Loading…
Reference in New Issue