mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-06-28 09:45:45 +02:00
[eden-cli] rework loop to use new SDL3 event dispatch system
Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
3aa0d46259
commit
c423fdfcd7
4 changed files with 153 additions and 139 deletions
|
|
@ -27,3 +27,6 @@ There are two main applications, an SDL-based app (`eden-cli`) and a Qt based ap
|
||||||
- `--user/-u`: Specify the user index.
|
- `--user/-u`: Specify the user index.
|
||||||
- `--version/-v`: Display version and quit.
|
- `--version/-v`: Display version and quit.
|
||||||
- `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
|
- `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
|
||||||
|
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
||||||
|
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
||||||
|
- `--singlecore/-s`: Forces single-core regardless of settings.
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/scm_rev.h"
|
#include "common/scm_rev.h"
|
||||||
|
|
@ -26,9 +29,16 @@ EmuWindow_SDL3::EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Co
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
titlebar_timer = SDL_AddTimer(2000, [](void *userdata, SDL_TimerID, Uint32) {
|
||||||
|
auto* this_ = (EmuWindow_SDL3*)userdata;
|
||||||
|
auto const results = this_->system.GetAndResetPerfStats();
|
||||||
|
auto const title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps, results.emulation_speed * 100.0f);
|
||||||
|
SDL_SetWindowTitle(this_->render_window, title.c_str());
|
||||||
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
||||||
|
SDL_RemoveTimer(titlebar_timer);
|
||||||
system.HIDCore().UnloadInputDevices();
|
system.HIDCore().UnloadInputDevices();
|
||||||
input_subsystem->Shutdown();
|
input_subsystem->Shutdown();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|
@ -130,8 +140,7 @@ void EmuWindow_SDL3::Fullscreen() {
|
||||||
switch (Settings::values.fullscreen_mode.GetValue()) {
|
switch (Settings::values.fullscreen_mode.GetValue()) {
|
||||||
case Settings::FullscreenMode::Exclusive:
|
case Settings::FullscreenMode::Exclusive:
|
||||||
// Set window size to render size before entering fullscreen in exclusive mode.
|
// Set window size to render size before entering fullscreen in exclusive mode.
|
||||||
if (const SDL_DisplayMode* display_mode_ptr =
|
if (const SDL_DisplayMode* display_mode_ptr = SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
||||||
SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
|
||||||
display_mode = *display_mode_ptr;
|
display_mode = *display_mode_ptr;
|
||||||
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
||||||
SDL_SetWindowFullscreenMode(render_window, &display_mode);
|
SDL_SetWindowFullscreenMode(render_window, &display_mode);
|
||||||
|
|
@ -163,92 +172,60 @@ void EmuWindow_SDL3::Fullscreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL3::WaitEvent() {
|
void EmuWindow_SDL3::OnEvent(SDL_Event& event) {
|
||||||
// Called on main thread
|
// Notice how we skip the "update title" aspect on most events
|
||||||
SDL_Event event;
|
// this is because some WMs do NOT like changing titles while resizing
|
||||||
|
// so let's just... not do that, thanks :)
|
||||||
if (!SDL_WaitEvent(&event)) {
|
// Afterall we don't really expect the user to pay attention to the titlebar
|
||||||
const char* error = SDL_GetError();
|
// while they're moving a lot of shit around...
|
||||||
if (!error || strcmp(error, "") == 0) {
|
|
||||||
// https://github.com/libsdl-org/SDL/issues/5780
|
|
||||||
// Sometimes SDL will return without actually having hit an error condition;
|
|
||||||
// just ignore it in this case.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_EVENT_WINDOW_RESIZED:
|
case SDL_EVENT_WINDOW_RESIZED:
|
||||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||||
is_shown = false;
|
is_shown = false;
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_EXPOSED:
|
case SDL_EVENT_WINDOW_EXPOSED:
|
||||||
is_shown = true;
|
is_shown = true;
|
||||||
OnResize();
|
return OnResize();
|
||||||
break;
|
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
return;
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
OnKeyEvent(static_cast<int>(event.key.scancode), event.key.down ? 1 : 0);
|
return OnKeyEvent(int(event.key.scancode), event.key.down ? 1 : 0);
|
||||||
break;
|
|
||||||
case SDL_EVENT_MOUSE_MOTION:
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID)
|
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||||
OnMouseMotion(event.motion.x, event.motion.y);
|
OnMouseMotion(event.motion.x, event.motion.y);
|
||||||
break;
|
return;
|
||||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
// ignore if it came from touch
|
// ignore if it came from touch
|
||||||
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||||
OnMouseButton(event.button.button, event.button.down ? 1 : 0,
|
OnMouseButton(event.button.button, event.button.down ? 1 : 0, s32(event.button.x), s32(event.button.y));
|
||||||
static_cast<s32>(event.button.x), static_cast<s32>(event.button.y));
|
return;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_DOWN:
|
case SDL_EVENT_FINGER_DOWN:
|
||||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
return OnFingerDown(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||||
static_cast<std::size_t>(event.tfinger.touchID));
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_MOTION:
|
case SDL_EVENT_FINGER_MOTION:
|
||||||
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
return OnFingerMotion(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||||
static_cast<std::size_t>(event.tfinger.touchID));
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_FINGER_UP:
|
case SDL_EVENT_FINGER_UP:
|
||||||
OnFingerUp();
|
return OnFingerUp();
|
||||||
break;
|
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
is_open = false;
|
is_open = false;
|
||||||
break;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 current_time = SDL_GetTicks();
|
|
||||||
if (current_time > last_time + 2000) {
|
|
||||||
const auto results = system.GetAndResetPerfStats();
|
|
||||||
const auto title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)",
|
|
||||||
Common::g_build_fullname,
|
|
||||||
Common::g_scm_branch,
|
|
||||||
Common::g_scm_desc,
|
|
||||||
results.average_game_fps,
|
|
||||||
results.emulation_speed * 100.0);
|
|
||||||
SDL_SetWindowTitle(render_window, title.c_str());
|
|
||||||
last_time = current_time;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credits to Samantas5855 and others for this function.
|
// Credits to Samantas5855 and others for this function.
|
||||||
void EmuWindow_SDL3::SetWindowIcon() {
|
void EmuWindow_SDL3::SetWindowIcon() {
|
||||||
|
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||||
|
// Icons do not work yet
|
||||||
|
#else
|
||||||
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
||||||
if (yuzu_icon_stream == nullptr) {
|
if (yuzu_icon_stream == nullptr) {
|
||||||
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
||||||
|
|
@ -262,6 +239,7 @@ void EmuWindow_SDL3::SetWindowIcon() {
|
||||||
// The icon is attached to the window pointer
|
// The icon is attached to the window pointer
|
||||||
SDL_SetWindowIcon(render_window, window_icon);
|
SDL_SetWindowIcon(render_window, window_icon);
|
||||||
SDL_DestroySurface(window_icon);
|
SDL_DestroySurface(window_icon);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "core/frontend/graphics_context.h"
|
#include "core/frontend/graphics_context.h"
|
||||||
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
union SDL_Event;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
|
|
@ -35,7 +36,7 @@ public:
|
||||||
bool IsShown() const override;
|
bool IsShown() const override;
|
||||||
|
|
||||||
/// Wait for the next event on the main thread.
|
/// Wait for the next event on the main thread.
|
||||||
void WaitEvent();
|
void OnEvent(SDL_Event& event);
|
||||||
|
|
||||||
// Sets the window icon from yuzu.bmp
|
// Sets the window icon from yuzu.bmp
|
||||||
void SetWindowIcon();
|
void SetWindowIcon();
|
||||||
|
|
@ -80,6 +81,9 @@ protected:
|
||||||
/// Called when a configuration change affects the minimal size of the window
|
/// Called when a configuration change affects the minimal size of the window
|
||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||||
|
|
||||||
|
/// Periodic changer of titlebar (independent of event loop)
|
||||||
|
SDL_TimerID titlebar_timer;
|
||||||
|
|
||||||
/// Is the window still open?
|
/// Is the window still open?
|
||||||
bool is_open = true;
|
bool is_open = true;
|
||||||
|
|
||||||
|
|
@ -89,9 +93,6 @@ protected:
|
||||||
/// Internal SDL3 render window
|
/// Internal SDL3 render window
|
||||||
SDL_Window* render_window{};
|
SDL_Window* render_window{};
|
||||||
|
|
||||||
/// Keeps track of how often to update the title bar during gameplay
|
|
||||||
u32 last_time = 0;
|
|
||||||
|
|
||||||
/// Input subsystem to use with this window.
|
/// Input subsystem to use with this window.
|
||||||
InputCommon::InputSubsystem* input_subsystem;
|
InputCommon::InputSubsystem* input_subsystem;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "common/settings_enums.h"
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
#define SDL_MAIN_USE_CALLBACKS 1
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
|
|
@ -40,9 +46,7 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// windows.h needs to be included before shellapi.h
|
// windows.h needs to be included before shellapi.h
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
|
||||||
#include "common/windows/timer_resolution.h"
|
#include "common/windows/timer_resolution.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -175,8 +179,15 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) {
|
||||||
std::cout << std::endl << "* " << message << std::endl << std::endl;
|
std::cout << std::endl << "* " << message << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Application entry point
|
struct SdlState {
|
||||||
int main(int argc, char** argv) {
|
Common::DetachedTasks detached_tasks{};
|
||||||
|
Core::System system{};
|
||||||
|
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
|
||||||
|
SdlState* state = new SdlState();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||||
freopen("CONOUT$", "wb", stdout);
|
freopen("CONOUT$", "wb", stdout);
|
||||||
|
|
@ -187,16 +198,14 @@ int main(int argc, char** argv) {
|
||||||
Common::Log::Initialize();
|
Common::Log::Initialize();
|
||||||
Common::Log::SetColorConsoleBackendEnabled(true);
|
Common::Log::SetColorConsoleBackendEnabled(true);
|
||||||
Common::Log::Start();
|
Common::Log::Start();
|
||||||
Common::DetachedTasks detached_tasks;
|
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int argc_w;
|
int argc_w;
|
||||||
auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
|
auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
|
||||||
|
|
||||||
if (argv_w == nullptr) {
|
if (argv_w == nullptr) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to get command line arguments");
|
LOG_CRITICAL(Frontend, "Failed to get command line arguments");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
|
@ -206,10 +215,13 @@ int main(int argc, char** argv) {
|
||||||
std::optional<u16> override_gdb_port{};
|
std::optional<u16> override_gdb_port{};
|
||||||
bool use_multiplayer = false;
|
bool use_multiplayer = false;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
|
bool force_null_render = false;
|
||||||
|
bool force_single_core = false;
|
||||||
std::string nickname{};
|
std::string nickname{};
|
||||||
std::string password{};
|
std::string password{};
|
||||||
std::string address{};
|
std::string address{};
|
||||||
std::string input_profile{};
|
std::string input_profile{};
|
||||||
|
std::optional<std::string> log_filter{};
|
||||||
u16 port = Network::DefaultRoomPort;
|
u16 port = Network::DefaultRoomPort;
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
|
|
@ -224,6 +236,9 @@ int main(int argc, char** argv) {
|
||||||
{"user", required_argument, 0, 'u'},
|
{"user", required_argument, 0, 'u'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
{"input-profile", no_argument, 0, 'i'},
|
{"input-profile", no_argument, 0, 'i'},
|
||||||
|
{"null-render", no_argument, 0, 'n'},
|
||||||
|
{"singlecore", no_argument, 0, 's'},
|
||||||
|
{"filter", no_argument, 0, 'x'},
|
||||||
{0, 0, 0, 0},
|
{0, 0, 0, 0},
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
|
@ -244,7 +259,7 @@ int main(int argc, char** argv) {
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
PrintHelp(argv[0]);
|
PrintHelp(argv[0]);
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
case 'g':
|
case 'g':
|
||||||
filepath = std::string(optarg);
|
filepath = std::string(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
@ -261,7 +276,7 @@ int main(int argc, char** argv) {
|
||||||
if (!std::regex_match(str_arg, re)) {
|
if (!std::regex_match(str_arg, re)) {
|
||||||
std::cout << "Wrong format for option --multiplayer\n";
|
std::cout << "Wrong format for option --multiplayer\n";
|
||||||
PrintHelp(argv[0]);
|
PrintHelp(argv[0]);
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
|
|
@ -271,17 +286,16 @@ int main(int argc, char** argv) {
|
||||||
password = match[2];
|
password = match[2];
|
||||||
address = match[3];
|
address = match[3];
|
||||||
if (!match[4].str().empty()) {
|
if (!match[4].str().empty()) {
|
||||||
port = static_cast<u16>(std::strtoul(match[4].str().c_str(), nullptr, 0));
|
port = u16(std::strtoul(match[4].str().c_str(), nullptr, 0));
|
||||||
}
|
}
|
||||||
std::regex nickname_re("^[a-zA-Z0-9._\\- ]+$");
|
std::regex nickname_re("^[a-zA-Z0-9._\\- ]+$");
|
||||||
if (!std::regex_match(nickname, nickname_re)) {
|
if (!std::regex_match(nickname, nickname_re)) {
|
||||||
std::cout
|
LOG_ERROR(Frontend, "Nickname is not valid. Must be 4 to 20 alphanumeric characters");
|
||||||
<< "Nickname is not valid. Must be 4 to 20 alphanumeric characters.\n";
|
return SDL_APP_FAILURE;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (address.empty()) {
|
if (address.empty()) {
|
||||||
std::cout << "Address to room must not be empty.\n";
|
LOG_ERROR(Frontend, "Address to room must not be empty");
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +308,17 @@ int main(int argc, char** argv) {
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
PrintVersion();
|
PrintVersion();
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
|
case 'n':
|
||||||
|
force_null_render = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
force_single_core = true;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
log_filter = argv[optind];
|
||||||
|
++optind;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
@ -311,7 +335,7 @@ int main(int argc, char** argv) {
|
||||||
// apply the log_filter setting
|
// apply the log_filter setting
|
||||||
// the logger was initialized before and doesn't pick up the filter on its own
|
// the logger was initialized before and doesn't pick up the filter on its own
|
||||||
Common::Log::Filter filter;
|
Common::Log::Filter filter;
|
||||||
filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
filter.ParseFilterString(log_filter.value_or(Settings::values.log_filter.GetValue()));
|
||||||
Common::Log::SetGlobalFilter(filter);
|
Common::Log::SetGlobalFilter(filter);
|
||||||
|
|
||||||
if (!program_args.empty()) {
|
if (!program_args.empty()) {
|
||||||
|
|
@ -332,85 +356,87 @@ int main(int argc, char** argv) {
|
||||||
Settings::values.gdbstub_port = *override_gdb_port;
|
Settings::values.gdbstub_port = *override_gdb_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (force_single_core) {
|
||||||
|
Settings::values.use_multi_core = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_null_render) {
|
||||||
|
Settings::values.renderer_backend = Settings::RendererBackend::Null;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LocalFree(argv_w);
|
LocalFree(argv_w);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (filepath.empty()) {
|
if (filepath.empty()) {
|
||||||
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
|
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System system{};
|
state->system.Initialize();
|
||||||
system.Initialize();
|
|
||||||
|
|
||||||
InputCommon::InputSubsystem input_subsystem{};
|
InputCommon::InputSubsystem input_subsystem{};
|
||||||
|
|
||||||
// Apply the command line arguments
|
// Apply the command line arguments
|
||||||
system.ApplySettings();
|
state->system.ApplySettings();
|
||||||
|
|
||||||
std::unique_ptr<EmuWindow_SDL3> emu_window;
|
|
||||||
switch (Settings::values.renderer_backend.GetValue()) {
|
switch (Settings::values.renderer_backend.GetValue()) {
|
||||||
#ifdef HAS_OPENGL
|
#ifdef HAS_OPENGL
|
||||||
case Settings::RendererBackend::OpenGL_GLSL:
|
case Settings::RendererBackend::OpenGL_GLSL:
|
||||||
case Settings::RendererBackend::OpenGL_GLASM:
|
case Settings::RendererBackend::OpenGL_GLASM:
|
||||||
case Settings::RendererBackend::OpenGL_SPIRV:
|
case Settings::RendererBackend::OpenGL_SPIRV:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_GL>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case Settings::RendererBackend::Vulkan:
|
case Settings::RendererBackend::Vulkan:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_VK>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
case Settings::RendererBackend::Null:
|
case Settings::RendererBackend::Null:
|
||||||
emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, system, fullscreen);
|
state->emu_window = std::make_unique<EmuWindow_SDL3_Null>(&input_subsystem, state->system, fullscreen);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Frontend, "Invalid renderer backend");
|
LOG_CRITICAL(Frontend, "Invalid renderer backend");
|
||||||
return -1;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Common::Windows::SetCurrentTimerResolutionToMaximum();
|
Common::Windows::SetCurrentTimerResolutionToMaximum();
|
||||||
system.CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution());
|
state->system.CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
state->system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||||
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
state->system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
|
state->system.GetFileSystemController().CreateFactories(*state->system.GetFilesystem());
|
||||||
system.GetUserChannel().clear();
|
state->system.GetUserChannel().clear();
|
||||||
|
|
||||||
Service::AM::FrontendAppletParameters load_parameters{
|
Service::AM::FrontendAppletParameters load_parameters{
|
||||||
.applet_id = Service::AM::AppletId::Application,
|
.applet_id = Service::AM::AppletId::Application,
|
||||||
};
|
};
|
||||||
const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)};
|
const Core::SystemResultStatus load_result = state->system.Load(*state->emu_window, filepath, load_parameters);
|
||||||
|
|
||||||
switch (load_result) {
|
switch (load_result) {
|
||||||
case Core::SystemResultStatus::ErrorGetLoader:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorLoader:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to load ROM!");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorNotInitialized:
|
|
||||||
LOG_CRITICAL(Frontend, "CPUCore not initialized");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::ErrorVideoCore:
|
|
||||||
LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
|
|
||||||
return -1;
|
|
||||||
case Core::SystemResultStatus::Success:
|
case Core::SystemResultStatus::Success:
|
||||||
break; // Expected case
|
break; // Expected case
|
||||||
|
case Core::SystemResultStatus::ErrorGetLoader:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorLoader:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to load ROM!");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorNotInitialized:
|
||||||
|
LOG_CRITICAL(Frontend, "CPUCore not initialized");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
|
case Core::SystemResultStatus::ErrorVideoCore:
|
||||||
|
LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
|
||||||
|
return SDL_APP_FAILURE;
|
||||||
default:
|
default:
|
||||||
if (static_cast<u32>(load_result) >
|
const u16 loader_id = u16(Core::SystemResultStatus::ErrorLoader);
|
||||||
static_cast<u32>(Core::SystemResultStatus::ErrorLoader)) {
|
const u16 error_id = u16(load_result) - loader_id;
|
||||||
const u16 loader_id = static_cast<u16>(Core::SystemResultStatus::ErrorLoader);
|
LOG_CRITICAL(Frontend,
|
||||||
const u16 error_id = static_cast<u16>(load_result) - loader_id;
|
"While attempting to load the ROM requested, an error occurred. Please "
|
||||||
LOG_CRITICAL(Frontend,
|
"refer to the Eden wiki for more information or the Eden discord for "
|
||||||
"While attempting to load the ROM requested, an error occurred. Please "
|
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
||||||
"refer to the Eden wiki for more information or the Eden discord for "
|
loader_id, error_id, Loader::ResultStatus(error_id));
|
||||||
"additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
|
return SDL_APP_FAILURE;
|
||||||
loader_id, error_id, static_cast<Loader::ResultStatus>(error_id));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_multiplayer) {
|
if (use_multiplayer) {
|
||||||
|
|
@ -419,41 +445,47 @@ int main(int argc, char** argv) {
|
||||||
member->BindOnStatusMessageReceived(OnStatusMessageReceived);
|
member->BindOnStatusMessageReceived(OnStatusMessageReceived);
|
||||||
member->BindOnStateChanged(OnStateChanged);
|
member->BindOnStateChanged(OnStateChanged);
|
||||||
member->BindOnError(OnNetworkError);
|
member->BindOnError(OnNetworkError);
|
||||||
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port,
|
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port, nickname);
|
||||||
nickname);
|
|
||||||
member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredIP, password);
|
member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredIP, password);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Network, "Could not access RoomMember");
|
LOG_ERROR(Network, "Could not access RoomMember");
|
||||||
return 0;
|
return SDL_APP_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
|
// Core is loaded, start the GPU (makes the GPU contexts current to this thread)
|
||||||
system.GPU().Start();
|
state->system.GPU().Start();
|
||||||
system.GetCpuManager().OnGpuReady();
|
state->system.GetCpuManager().OnGpuReady();
|
||||||
|
|
||||||
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
||||||
system.Renderer().ReadRasterizer()->LoadDiskResources(
|
state->system.Renderer().ReadRasterizer()->LoadDiskResources(
|
||||||
system.GetApplicationProcessProgramID(), std::stop_token{},
|
state->system.GetApplicationProcessProgramID(), std::stop_token{},
|
||||||
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
|
[](VideoCore::LoadCallbackStage, size_t value, size_t total) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
system.RegisterExitCallback([&] {
|
// don't do anything, SDL3 already exists for us :D
|
||||||
// Just exit right away.
|
state->system.RegisterExitCallback([] {});
|
||||||
exit(0);
|
void(state->system.Run());
|
||||||
});
|
if (state->system.DebuggerEnabled())
|
||||||
void(system.Run());
|
state->system.InitializeDebugger();
|
||||||
if (system.DebuggerEnabled()) {
|
return SDL_APP_SUCCESS;
|
||||||
system.InitializeDebugger();
|
}
|
||||||
}
|
extern "C" SDL_AppResult SDL_AppIterate(void *appstate) {
|
||||||
while (emu_window->IsOpen()) {
|
SdlState *state = (SdlState *)appstate;
|
||||||
emu_window->WaitEvent();
|
return state->emu_window->IsOpen() ? SDL_APP_CONTINUE : SDL_APP_SUCCESS;
|
||||||
}
|
}
|
||||||
system.DetachDebugger();
|
extern "C" SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
|
||||||
void(system.Pause());
|
SdlState *state = (SdlState *)appstate;
|
||||||
system.ShutdownMainProcess();
|
state->emu_window->OnEvent(*event);
|
||||||
detached_tasks.WaitForAllTasks();
|
return SDL_APP_SUCCESS;
|
||||||
return 0;
|
}
|
||||||
|
extern "C" void SDL_AppQuit(void *appstate, SDL_AppResult result) {
|
||||||
|
SdlState *state = (SdlState *)appstate;
|
||||||
|
state->system.DetachDebugger();
|
||||||
|
void(state->system.Pause());
|
||||||
|
state->system.ShutdownMainProcess();
|
||||||
|
state->detached_tasks.WaitForAllTasks();
|
||||||
|
delete state;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VMA_IMPLEMENTATION
|
#define VMA_IMPLEMENTATION
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue