mirror of
https://github.com/encounter/aurora.git
synced 2025-07-25 14:35:47 +00:00
If we try and initialize anything controller related before the event subsystem is initialized we lose all controllers detected on startup. To solve this we simply wait until the first frame is about to be rendered *then* initialize the controller subsystems
226 lines
5.8 KiB
C++
226 lines
5.8 KiB
C++
#include <aurora/aurora.h>
|
|
|
|
#include "gfx/common.hpp"
|
|
#include "imgui.hpp"
|
|
#include "input.hpp"
|
|
#include "internal.hpp"
|
|
#include "webgpu/gpu.hpp"
|
|
#include "window.hpp"
|
|
|
|
#include <SDL.h>
|
|
#include <SDL_filesystem.h>
|
|
#include <imgui.h>
|
|
|
|
namespace aurora {
|
|
static Module Log("aurora");
|
|
|
|
AuroraConfig g_config;
|
|
|
|
// GPU
|
|
using webgpu::g_device;
|
|
using webgpu::g_queue;
|
|
using webgpu::g_swapChain;
|
|
|
|
constexpr std::array PreferredBackendOrder{
|
|
#ifdef ENABLE_BACKEND_WEBGPU
|
|
BACKEND_WEBGPU,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_D3D12
|
|
// BACKEND_D3D12,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_METAL
|
|
BACKEND_METAL,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_VULKAN
|
|
BACKEND_VULKAN,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_DESKTOP_GL
|
|
BACKEND_OPENGL,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_OPENGLES
|
|
BACKEND_OPENGLES,
|
|
#endif
|
|
#ifdef DAWN_ENABLE_BACKEND_NULL
|
|
BACKEND_NULL,
|
|
#endif
|
|
};
|
|
|
|
static bool g_initialFrame = false;
|
|
|
|
static AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexcept {
|
|
g_config = config;
|
|
if (g_config.appName == nullptr) {
|
|
g_config.appName = "Aurora";
|
|
}
|
|
if (g_config.configPath == nullptr) {
|
|
g_config.configPath = SDL_GetPrefPath(nullptr, g_config.appName);
|
|
}
|
|
if (g_config.msaa == 0) {
|
|
g_config.msaa = 1;
|
|
}
|
|
if (g_config.maxTextureAnisotropy == 0) {
|
|
g_config.maxTextureAnisotropy = 16;
|
|
}
|
|
window::initialize();
|
|
|
|
/* Attempt to create a window using the calling application's desired backend */
|
|
AuroraBackend selectedBackend = config.desiredBackend;
|
|
bool windowCreated = false;
|
|
if (selectedBackend != BACKEND_AUTO && window::create_window(selectedBackend)) {
|
|
if (webgpu::initialize(selectedBackend)) {
|
|
windowCreated = true;
|
|
} else {
|
|
window::destroy_window();
|
|
}
|
|
}
|
|
|
|
if (!windowCreated) {
|
|
for (const auto backendType : PreferredBackendOrder) {
|
|
selectedBackend = backendType;
|
|
if (!window::create_window(selectedBackend)) {
|
|
continue;
|
|
}
|
|
if (webgpu::initialize(selectedBackend)) {
|
|
windowCreated = true;
|
|
break;
|
|
} else {
|
|
window::destroy_window();
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(windowCreated, "Error creating window: {}", SDL_GetError());
|
|
|
|
// Initialize SDL_Renderer for ImGui when we can't use a Dawn backend
|
|
if (webgpu::g_backendType == wgpu::BackendType::Null) {
|
|
ASSERT(window::create_renderer(), "Failed to initialize SDL renderer: {}", SDL_GetError());
|
|
}
|
|
|
|
window::show_window();
|
|
|
|
gfx::initialize();
|
|
|
|
imgui::create_context();
|
|
const auto size = window::get_window_size();
|
|
Log.report(LOG_INFO, FMT_STRING("Using framebuffer size {}x{} scale {}"), size.fb_width, size.fb_height, size.scale);
|
|
if (g_config.imGuiInitCallback != nullptr) {
|
|
g_config.imGuiInitCallback(&size);
|
|
}
|
|
imgui::initialize();
|
|
|
|
if (aurora_begin_frame()) {
|
|
g_initialFrame = true;
|
|
}
|
|
g_config.desiredBackend = selectedBackend;
|
|
return {
|
|
.backend = selectedBackend,
|
|
.configPath = g_config.configPath,
|
|
.window = window::get_sdl_window(),
|
|
.windowSize = size,
|
|
};
|
|
}
|
|
|
|
#ifndef EMSCRIPTEN
|
|
static wgpu::TextureView g_currentView;
|
|
#endif
|
|
|
|
static void shutdown() noexcept {
|
|
#ifndef EMSCRIPTEN
|
|
g_currentView = {};
|
|
#endif
|
|
imgui::shutdown();
|
|
gfx::shutdown();
|
|
webgpu::shutdown();
|
|
window::shutdown();
|
|
}
|
|
|
|
static const AuroraEvent* update() noexcept {
|
|
if (g_initialFrame) {
|
|
aurora_end_frame();
|
|
g_initialFrame = false;
|
|
input::initialize();
|
|
}
|
|
const auto* events = window::poll_events();
|
|
imgui::new_frame(window::get_window_size());
|
|
return events;
|
|
}
|
|
|
|
static bool begin_frame() noexcept {
|
|
#ifndef EMSCRIPTEN
|
|
g_currentView = g_swapChain.GetCurrentTextureView();
|
|
if (!g_currentView) {
|
|
ImGui::EndFrame();
|
|
// Force swapchain recreation
|
|
const auto size = window::get_window_size();
|
|
webgpu::resize_swapchain(size.fb_width, size.fb_height, true);
|
|
return false;
|
|
}
|
|
#endif
|
|
gfx::begin_frame();
|
|
return true;
|
|
}
|
|
|
|
static void end_frame() noexcept {
|
|
const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{
|
|
.label = "Redraw encoder",
|
|
};
|
|
auto encoder = g_device.CreateCommandEncoder(&encoderDescriptor);
|
|
gfx::end_frame(encoder);
|
|
gfx::render(encoder);
|
|
{
|
|
const std::array attachments{
|
|
wgpu::RenderPassColorAttachment{
|
|
#ifdef EMSCRIPTEN
|
|
.view = g_swapChain.GetCurrentTextureView(),
|
|
#else
|
|
.view = g_currentView,
|
|
#endif
|
|
.loadOp = wgpu::LoadOp::Clear,
|
|
.storeOp = wgpu::StoreOp::Store,
|
|
},
|
|
};
|
|
const wgpu::RenderPassDescriptor renderPassDescriptor{
|
|
.label = "Post render pass",
|
|
.colorAttachmentCount = attachments.size(),
|
|
.colorAttachments = attachments.data(),
|
|
};
|
|
auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
|
// Copy EFB -> XFB (swapchain)
|
|
pass.SetPipeline(webgpu::g_CopyPipeline);
|
|
pass.SetBindGroup(0, webgpu::g_CopyBindGroup, 0, nullptr);
|
|
pass.Draw(3);
|
|
if (!g_initialFrame) {
|
|
// Render ImGui
|
|
imgui::render(pass);
|
|
}
|
|
pass.End();
|
|
}
|
|
const wgpu::CommandBufferDescriptor cmdBufDescriptor{.label = "Redraw command buffer"};
|
|
const auto buffer = encoder.Finish(&cmdBufDescriptor);
|
|
g_queue.Submit(1, &buffer);
|
|
#ifdef WEBGPU_DAWN
|
|
g_swapChain.Present();
|
|
g_currentView = {};
|
|
#else
|
|
emscripten_sleep(0);
|
|
#endif
|
|
if (!g_initialFrame) {
|
|
ImGui::EndFrame();
|
|
}
|
|
}
|
|
} // namespace aurora
|
|
|
|
// C API bindings
|
|
AuroraInfo aurora_initialize(int argc, char* argv[], const AuroraConfig* config) {
|
|
return aurora::initialize(argc, argv, *config);
|
|
}
|
|
void aurora_shutdown() { aurora::shutdown(); }
|
|
const AuroraEvent* aurora_update() { return aurora::update(); }
|
|
bool aurora_begin_frame() { return aurora::begin_frame(); }
|
|
void aurora_end_frame() { aurora::end_frame(); }
|
|
AuroraBackend aurora_get_backend() { return aurora::g_config.desiredBackend; }
|
|
const AuroraBackend* aurora_get_available_backends(size_t* count) {
|
|
*count = aurora::PreferredBackendOrder.size();
|
|
return aurora::PreferredBackendOrder.data();
|
|
}
|