@ -11,6 +11,8 @@
# ifdef __EMSCRIPTEN__
# include <emscripten.h>
# endif
# define SDL_MAIN_USE_CALLBACKS 1
# include <SDL3/SDL_main.h>
# include <fmt/ostream.h>
@ -43,9 +45,7 @@
# ifdef _WIN32
// windows.h needs to be included before shellapi.h
# include <windows.h>
# include <shellapi.h>
# include "common/windows/timer_resolution.h"
# endif
@ -178,8 +178,15 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) {
std : : cout < < std : : endl < < " * " < < message < < std : : endl < < std : : endl ;
}
/// Application entry point
int main ( int argc , char * * argv ) {
struct SdlState {
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
if ( AttachConsole ( ATTACH_PARENT_PROCESS ) ) {
freopen ( " CONOUT$ " , " wb " , stdout ) ;
@ -190,16 +197,14 @@ int main(int argc, char** argv) {
Common : : Log : : Initialize ( ) ;
Common : : Log : : SetColorConsoleBackendEnabled ( true ) ;
Common : : Log : : Start ( ) ;
Common : : DetachedTasks detached_tasks ;
int option_index = 0 ;
# ifdef _WIN32
int argc_w ;
auto argv_w = CommandLineToArgvW ( GetCommandLineW ( ) , & argc_w ) ;
if ( argv_w = = nullptr ) {
LOG_CRITICAL ( Frontend , " Failed to get command line arguments " ) ;
return - 1 ;
return SDL_APP_FAILURE ;
}
# endif
std : : string filepath ;
@ -247,7 +252,7 @@ int main(int argc, char** argv) {
break ;
case ' h ' :
PrintHelp ( argv [ 0 ] ) ;
return 0 ;
return SDL_APP_FAILURE ;
case ' g ' :
filepath = std : : string ( optarg ) ;
break ;
@ -264,7 +269,7 @@ int main(int argc, char** argv) {
if ( ! std : : regex_match ( str_arg , re ) ) {
std : : cout < < " Wrong format for option --multiplayer \n " ;
PrintHelp ( argv [ 0 ] ) ;
return 0 ;
return SDL_APP_FAILURE ;
}
std : : smatch match ;
@ -274,17 +279,16 @@ int main(int argc, char** argv) {
password = match [ 2 ] ;
address = match [ 3 ] ;
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._ \\ - ]+$ " ) ;
if ( ! std : : regex_match ( nickname , nickname_re ) ) {
std : : cout
< < " Nickname is not valid. Must be 4 to 20 alphanumeric characters. \n " ;
return 0 ;
LOG_ERROR ( Frontend , " Nickname is not valid. Must be 4 to 20 alphanumeric characters " ) ;
return SDL_APP_FAILURE ;
}
if ( address . empty ( ) ) {
std : : cout < < " Address to room must not be empty. \n " ;
return 0 ;
LOG_ERROR ( Frontend , " Address to room must not be empty " ) ;
return SDL_APP_FAILURE ;
}
break ;
}
@ -297,7 +301,7 @@ int main(int argc, char** argv) {
break ;
case ' v ' :
PrintVersion ( ) ;
return 0 ;
return SDL_APP_FAILURE ;
}
} else {
# ifdef _WIN32
@ -341,79 +345,73 @@ int main(int argc, char** argv) {
if ( filepath . empty ( ) ) {
LOG_CRITICAL ( Frontend , " Failed to load ROM: No ROM specified " ) ;
return - 1 ;
return SDL_APP_FAILURE ;
}
Core : : System system { } ;
system . Initialize ( ) ;
state - > system . Initialize ( ) ;
InputCommon : : InputSubsystem input_subsystem { } ;
// Apply the command line arguments
system . ApplySettings ( ) ;
state - > s ystem . ApplySettings ( ) ;
std : : unique_ptr < EmuWindow_SDL3 > emu_window ;
switch ( Settings : : values . renderer_backend . GetValue ( ) ) {
# ifdef HAS_OPENGL
case Settings : : RendererBackend : : OpenGL_GLSL :
case Settings : : RendererBackend : : OpenGL_GLASM :
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 ;
# endif
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 ;
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 ;
default :
LOG_CRITICAL ( Frontend , " Invalid renderer backend " ) ;
return - 1 ;
return SDL_APP_FAILURE ;
}
# ifdef _WIN32
Common : : Windows : : SetCurrentTimerResolutionToMaximum ( ) ;
system . CoreTiming ( ) . SetTimerResolutionNs ( Common : : Windows : : GetCurrentTimerResolution ( ) ) ;
state - > s ystem . CoreTiming ( ) . SetTimerResolutionNs ( Common : : Windows : : GetCurrentTimerResolution ( ) ) ;
# endif
system . SetContentProvider ( std : : make_unique < FileSys : : ContentProviderUnion > ( ) ) ;
system . SetFilesystem ( std : : make_shared < FileSys : : RealVfsFilesystem > ( ) ) ;
system . GetFileSystemController ( ) . CreateFactories ( * system . GetFilesystem ( ) ) ;
system . GetUserChannel ( ) . clear ( ) ;
state - > s ystem . SetContentProvider ( std : : make_unique < FileSys : : ContentProviderUnion > ( ) ) ;
state - > s ystem . SetFilesystem ( std : : make_shared < FileSys : : RealVfsFilesystem > ( ) ) ;
state - > s ystem . GetFileSystemController ( ) . CreateFactories ( * state - > system . GetFilesystem ( ) ) ;
state - > s ystem . GetUserChannel ( ) . clear ( ) ;
Service : : AM : : FrontendAppletParameters load_parameters {
. 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 ) {
case Core : : SystemResultStatus : : Success :
break ; // Expected case
case Core : : SystemResultStatus : : ErrorGetLoader :
LOG_CRITICAL ( Frontend , " Failed to obtain loader for {}! " , filepath ) ;
return - 1 ;
return SDL_APP_FAILURE ;
case Core : : SystemResultStatus : : ErrorLoader :
LOG_CRITICAL ( Frontend , " Failed to load ROM! " ) ;
return - 1 ;
return SDL_APP_FAILURE ;
case Core : : SystemResultStatus : : ErrorNotInitialized :
LOG_CRITICAL ( Frontend , " CPUCore not initialized " ) ;
return - 1 ;
return SDL_APP_FAILURE ;
case Core : : SystemResultStatus : : ErrorVideoCore :
LOG_CRITICAL ( Frontend , " Failed to initialize VideoCore! " ) ;
return - 1 ;
case Core : : SystemResultStatus : : Success :
break ; // Expected case
return SDL_APP_FAILURE ;
default :
if ( static_cast < u32 > ( load_result ) >
static_cast < u32 > ( Core : : SystemResultStatus : : ErrorLoader ) ) {
const u16 loader_id = static_cast < u16 > ( Core : : SystemResultStatus : : ErrorLoader ) ;
const u16 error_id = static_cast < u16 > ( load_result ) - loader_id ;
LOG_CRITICAL ( Frontend ,
" While attempting to load the ROM requested, an error occurred. Please "
" refer to the Eden wiki for more information or the Eden discord for "
" additional help. \n \n Error Code: {:04X}-{:04X} \n Error Description: {} " ,
loader_id , error_id , static_cast < Loader : : ResultStatus > ( error_id ) ) ;
}
break ;
const u16 loader_id = u16 ( Core : : SystemResultStatus : : ErrorLoader ) ;
const u16 error_id = u16 ( load_result ) - loader_id ;
LOG_CRITICAL ( Frontend ,
" While attempting to load the ROM requested, an error occurred. Please "
" refer to the Eden wiki for more information or the Eden discord for "
" additional help. \n \n Error Code: {:04X}-{:04X} \n Error Description: {} " ,
loader_id , error_id , Loader : : ResultStatus ( error_id ) ) ;
return SDL_APP_FAILURE ;
}
if ( use_multiplayer ) {
@ -422,49 +420,47 @@ int main(int argc, char** argv) {
member - > BindOnStatusMessageReceived ( OnStatusMessageReceived ) ;
member - > BindOnStateChanged ( OnStateChanged ) ;
member - > BindOnError ( OnNetworkError ) ;
LOG_DEBUG ( Network , " Start connection to {}:{} with nickname {} " , address , port ,
nickname ) ;
LOG_DEBUG ( Network , " Start connection to {}:{} with nickname {} " , address , port , nickname ) ;
member - > Join ( nickname , address . c_str ( ) , port , 0 , Network : : NoPreferredIP , password ) ;
} else {
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)
system . GPU ( ) . Start ( ) ;
system . GetCpuManager ( ) . OnGpuReady ( ) ;
state - > s ystem . GPU ( ) . Start ( ) ;
state - > s ystem . GetCpuManager ( ) . OnGpuReady ( ) ;
if ( Settings : : values . use_disk_shader_cache . GetValue ( ) ) {
system . Renderer ( ) . ReadRasterizer ( ) - > LoadDiskResources (
system . GetApplicationProcessProgramID ( ) , std : : stop_token { } ,
state - > s ystem . Renderer ( ) . ReadRasterizer ( ) - > LoadDiskResources (
state - > s ystem . GetApplicationProcessProgramID ( ) , std : : stop_token { } ,
[ ] ( VideoCore : : LoadCallbackStage , size_t value , size_t total ) { } ) ;
}
system . RegisterExitCallback ( [ & ] {
// Just exit right away.
exit ( 0 ) ;
} ) ;
void ( system . Run ( ) ) ;
if ( system . DebuggerEnabled ( ) ) {
system . InitializeDebugger ( ) ;
}
# ifdef __EMSCRIPTEN__
// Required so lambda fits snuggly into our "main loop"
static EmuWindow_SDL3 * static_ems_emu_window = emu_window . get ( ) ;
emscripten_set_main_loop ( [ ] ( ) {
static_ems_emu_window - > WaitEvent ( ) ;
} , 0 , 1 ) ;
# else
while ( emu_window - > IsOpen ( ) )
emu_window - > WaitEvent ( ) ;
# endif
system . DetachDebugger ( ) ;
void ( system . Pause ( ) ) ;
system . ShutdownMainProcess ( ) ;
detached_tasks . WaitForAllTasks ( ) ;
return 0 ;
// don't do anything, SDL3 already exists for us :D
state - > system . RegisterExitCallback ( [ ] { } ) ;
void ( state - > system . Run ( ) ) ;
if ( state - > system . DebuggerEnabled ( ) )
state - > system . InitializeDebugger ( ) ;
return SDL_APP_SUCCESS ;
}
extern " C " SDL_AppResult SDL_AppIterate ( void * appstate ) {
SdlState * state = ( SdlState * ) appstate ;
return state - > emu_window - > IsOpen ( ) ? SDL_APP_CONTINUE : SDL_APP_SUCCESS ;
}
extern " C " SDL_AppResult SDL_AppEvent ( void * appstate , SDL_Event * event ) {
SdlState * state = ( SdlState * ) appstate ;
state - > emu_window - > OnEvent ( * event ) ;
return SDL_APP_SUCCESS ;
}
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