mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
f61c219ef2
* Add functionality to lock GX framebuffer aspect ratio This leaves the imgui (so including OS) framebuffer alone. AuroraWindowSize now has new fields for the native framebuffer, the aspect ratio controls modify the existing fields. * Fix from merge * fix gx_test_stubs.cpp
275 lines
7.7 KiB
C++
275 lines
7.7 KiB
C++
#include <aurora/aurora.h>
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
#include "gfx/common.hpp"
|
|
#include "gx/fifo.hpp"
|
|
#include "imgui.hpp"
|
|
#include "webgpu/gpu.hpp"
|
|
#include <webgpu/webgpu_cpp.h>
|
|
#endif
|
|
|
|
#include "input.hpp"
|
|
#include "internal.hpp"
|
|
#include "window.hpp"
|
|
|
|
#include <SDL3/SDL_filesystem.h>
|
|
#include <magic_enum.hpp>
|
|
|
|
namespace aurora {
|
|
AuroraConfig g_config;
|
|
|
|
namespace {
|
|
Module Log("aurora");
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
// GPU
|
|
using webgpu::g_device;
|
|
using webgpu::g_queue;
|
|
using webgpu::g_surface;
|
|
#endif
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
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_D3D11
|
|
BACKEND_D3D11,
|
|
#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
|
|
};
|
|
#else
|
|
constexpr std::array<AuroraBackend, 0> PreferredBackendOrder{};
|
|
#endif
|
|
|
|
bool g_initialFrame = false;
|
|
|
|
AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexcept {
|
|
g_config = config;
|
|
Log.info("Aurora initializing");
|
|
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;
|
|
}
|
|
ASSERT(window::initialize(), "Error initializing window");
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
/* 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());
|
|
}
|
|
#else
|
|
AuroraBackend selectedBackend = BACKEND_NULL;
|
|
ASSERT(window::create_window(BACKEND_NULL), "Error creating window: {}", SDL_GetError());
|
|
ASSERT(window::create_renderer(), "Failed to initialize SDL renderer: {}", SDL_GetError());
|
|
#endif
|
|
|
|
window::show_window();
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
gfx::initialize();
|
|
|
|
imgui::create_context();
|
|
#endif
|
|
const auto size = window::get_window_size();
|
|
Log.info("Using framebuffer size {}x{} scale {}", size.fb_width, size.fb_height, size.scale);
|
|
#ifdef AURORA_ENABLE_GX
|
|
if (g_config.imGuiInitCallback != nullptr) {
|
|
g_config.imGuiInitCallback(&size);
|
|
}
|
|
imgui::initialize();
|
|
#endif
|
|
|
|
g_initialFrame = true;
|
|
g_config.desiredBackend = selectedBackend;
|
|
return {
|
|
.backend = selectedBackend,
|
|
.configPath = g_config.configPath,
|
|
.window = window::get_sdl_window(),
|
|
.windowSize = size,
|
|
};
|
|
}
|
|
|
|
void aurora_set_log_level(AuroraLogLevel level) noexcept {
|
|
g_config.logLevel = level;
|
|
}
|
|
|
|
|
|
#ifdef AURORA_ENABLE_GX
|
|
wgpu::TextureView g_currentView;
|
|
#endif
|
|
|
|
void shutdown() noexcept {
|
|
#ifdef AURORA_ENABLE_GX
|
|
g_currentView = {};
|
|
imgui::shutdown();
|
|
gfx::shutdown();
|
|
webgpu::shutdown();
|
|
#endif
|
|
window::shutdown();
|
|
}
|
|
|
|
const AuroraEvent* update() noexcept {
|
|
if (g_initialFrame) {
|
|
g_initialFrame = false;
|
|
input::initialize();
|
|
}
|
|
return window::poll_events();
|
|
}
|
|
|
|
bool begin_frame() noexcept {
|
|
#ifdef AURORA_ENABLE_GX
|
|
if (!g_surface) {
|
|
webgpu::refresh_surface(true);
|
|
if (!g_surface) {
|
|
return false;
|
|
}
|
|
}
|
|
wgpu::SurfaceTexture surfaceTexture;
|
|
g_surface.GetCurrentTexture(&surfaceTexture);
|
|
switch (surfaceTexture.status) {
|
|
case wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal:
|
|
g_currentView = surfaceTexture.texture.CreateView();
|
|
break;
|
|
case wgpu::SurfaceGetCurrentTextureStatus::Timeout:
|
|
Log.warn("Surface texture acquisition timed out");
|
|
return false;
|
|
case wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal:
|
|
case wgpu::SurfaceGetCurrentTextureStatus::Outdated:
|
|
Log.info("Surface texture is {}, reconfiguring swapchain", magic_enum::enum_name(surfaceTexture.status));
|
|
webgpu::refresh_surface(false);
|
|
return false;
|
|
case wgpu::SurfaceGetCurrentTextureStatus::Lost:
|
|
case wgpu::SurfaceGetCurrentTextureStatus::Error:
|
|
Log.warn("Surface texture is {}, recreating surface", magic_enum::enum_name(surfaceTexture.status));
|
|
webgpu::refresh_surface(true);
|
|
return false;
|
|
default:
|
|
Log.error("Failed to get surface texture: {}", magic_enum::enum_name(surfaceTexture.status));
|
|
return false;
|
|
}
|
|
imgui::new_frame(window::get_window_size());
|
|
gfx::begin_frame();
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void end_frame() noexcept {
|
|
#ifdef AURORA_ENABLE_GX
|
|
gx::fifo::drain();
|
|
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{
|
|
.view = g_currentView,
|
|
.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);
|
|
|
|
// Center viewport to framebuffer size in case we're at an aspect ratio lock.
|
|
{
|
|
uint32_t pos_x = (webgpu::g_graphicsConfig.surfaceConfiguration.width - webgpu::g_frameBuffer.size.width) / 2;
|
|
uint32_t pos_y = (webgpu::g_graphicsConfig.surfaceConfiguration.height - webgpu::g_frameBuffer.size.height) / 2;
|
|
|
|
pass.SetViewport(pos_x, pos_y, webgpu::g_frameBuffer.size.width, webgpu::g_frameBuffer.size.height, 0, 1);
|
|
}
|
|
|
|
pass.Draw(3);
|
|
imgui::render(pass);
|
|
pass.End();
|
|
}
|
|
const wgpu::CommandBufferDescriptor cmdBufDescriptor{.label = "Redraw command buffer"};
|
|
const auto buffer = encoder.Finish(&cmdBufDescriptor);
|
|
g_queue.Submit(1, &buffer);
|
|
auto presentStatus = g_surface.Present();
|
|
if (presentStatus != wgpu::Status::Success) {
|
|
Log.warn("Surface present failed: {}", static_cast<int>(presentStatus));
|
|
}
|
|
g_currentView = {};
|
|
#endif
|
|
}
|
|
} // namespace
|
|
} // 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();
|
|
}
|