/* sys_psvita.c - psvita backend Copyright (C) 2021-2023 fgsfds This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include "platform/platform.h" #include #include #include #include #include #include #include #include #include #define DATA_PATH "data/xash3d" #define MAX_ARGV 5 // "" -log -dev X NULL // 200MB libc heap, 512K main thread stack, 40MB for loading game DLLs // the rest goes to vitaGL SceUInt32 sceUserMainThreadStackSize = 512 * 1024; unsigned int _pthread_stack_default_user = 512 * 1024; unsigned int _newlib_heap_size_user = 200 * 1024 * 1024; #define VGL_MEM_THRESHOLD ( 40 * 1024 * 1024 ) // HACKHACK: create some slack at the end of the RX segment of the ELF // for vita-elf-create to put the generated symbol table into const char vitaelf_slack __attribute__ ((aligned (0x20000))) = 0xFF; /* HACKHACK: force-export stuff required by the dynamic libs */ extern void *__aeabi_idiv; extern void *__aeabi_uidiv; extern void *__aeabi_idivmod; extern void *__aeabi_uidivmod; extern void *__aeabi_d2ulz; extern void *__aeabi_ul2d; static const vrtld_export_t aux_exports[] = { VRTLD_EXPORT_SYMBOL( __aeabi_d2ulz ), VRTLD_EXPORT_SYMBOL( __aeabi_idiv ), VRTLD_EXPORT_SYMBOL( __aeabi_idivmod ), VRTLD_EXPORT_SYMBOL( __aeabi_uidivmod ), VRTLD_EXPORT_SYMBOL( __aeabi_uidiv ), VRTLD_EXPORT_SYMBOL( __aeabi_ul2d ), VRTLD_EXPORT_SYMBOL( _impure_ptr ), VRTLD_EXPORT_SYMBOL( ctime ), VRTLD_EXPORT_SYMBOL( vasprintf ), VRTLD_EXPORT_SYMBOL( vsprintf ), VRTLD_EXPORT_SYMBOL( vprintf ), VRTLD_EXPORT_SYMBOL( printf ), VRTLD_EXPORT_SYMBOL( putchar ), VRTLD_EXPORT_SYMBOL( puts ), VRTLD_EXPORT_SYMBOL( tolower ), VRTLD_EXPORT_SYMBOL( toupper ), VRTLD_EXPORT_SYMBOL( isalnum ), VRTLD_EXPORT_SYMBOL( isalpha ), VRTLD_EXPORT_SYMBOL( strchrnul ), VRTLD_EXPORT_SYMBOL( stpcpy ), VRTLD_EXPORT_SYMBOL( rand ), VRTLD_EXPORT_SYMBOL( srand ), VRTLD_EXPORT_SYMBOL( sceGxmMapMemory ), // needed by vgl_shim VRTLD_EXPORT( "dlopen", vrtld_dlopen ), VRTLD_EXPORT( "dlclose", vrtld_dlclose ), VRTLD_EXPORT( "dlsym", vrtld_dlsym ), }; const vrtld_export_t *__vrtld_exports = aux_exports; const size_t __vrtld_num_exports = sizeof( aux_exports ) / sizeof( *aux_exports ); /* end of export crap */ static const char *PSVita_GetLaunchParameter( char *outbuf ) { SceAppUtilAppEventParam param; memset( ¶m, 0, sizeof( param ) ); sceAppUtilReceiveAppEvent( ¶m ); if( param.type == 0x05 ) { sceAppUtilAppEventParseLiveArea( ¶m, outbuf ); return outbuf; } return NULL; } void Platform_ShellExecute( const char *path, const char *parms ) { Con_Reportf( S_WARN "Tried to shell execute ;%s; -- not supported\n", path ); } /* =========== PSVita_GetArgv On the PS Vita under normal circumstances argv is empty, so we'll construct our own based on which button the user pressed in the LiveArea launcher. =========== */ int PSVita_GetArgv( int in_argc, char **in_argv, char ***out_argv ) { static const char *fake_argv[MAX_ARGV] = { "app0:/eboot.bin", NULL }; int fake_argc = 1; char tmp[2048] = { 0 }; SceAppUtilInitParam initParam = { 0 }; SceAppUtilBootParam bootParam = { 0 }; // on the Vita under normal circumstances argv is empty, unless we're launching from Change Game sceAppUtilInit( &initParam, &bootParam ); if( in_argc > 1 ) { // probably coming from Change Game, in which case we just need to keep the old args *out_argv = in_argv; return in_argc; } // got empty args, which means that we're probably coming from LiveArea // construct argv based on which button the user pressed in the LiveArea launcher if( PSVita_GetLaunchParameter( tmp )) { if( !Q_strcmp( tmp, "dev" )) { // user hit the "Developer Mode" button, inject "-log" and "-dev" arguments fake_argv[fake_argc++] = "-log"; fake_argv[fake_argc++] = "-dev"; fake_argv[fake_argc++] = "2"; } } *out_argv = (char **)fake_argv; return fake_argc; } void PSVita_Init( void ) { char xashdir[1024] = { 0 }; // cd to the base dir immediately for library loading to work if( PSVita_GetBasePath( xashdir, sizeof( xashdir ))) { chdir( xashdir ); } sceTouchSetSamplingState( SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_STOP ); scePowerSetArmClockFrequency( 444 ); scePowerSetBusClockFrequency( 222 ); scePowerSetGpuClockFrequency( 222 ); scePowerSetGpuXbarClockFrequency( 166 ); sceSysmoduleLoadModule( SCE_SYSMODULE_NET ); if( vrtld_init( 0 ) < 0 ) { Sys_Error( "Could not init vrtld:\n%s\n", vrtld_dlerror() ); } // init vitaGL, leaving some memory for DLL mapping // TODO: we don't need to do this for ref_soft vglUseVram( GL_TRUE ); vglUseExtraMem( GL_TRUE ); vglInitExtended( 0, 960, 544, VGL_MEM_THRESHOLD, 0 ); } void PSVita_Shutdown( void ) { vrtld_quit( ); } qboolean PSVita_GetBasePath( char *buf, const size_t buflen ) { // check if a xash3d folder exists on one of these drives // default to the last one (ux0) static const char *drives[] = { "uma0", "imc0", "ux0" }; SceUID dir; size_t i; for ( i = 0; i < sizeof( drives ) / sizeof( *drives ); ++i ) { Q_snprintf( buf, buflen, "%s:" DATA_PATH, drives[i] ); dir = sceIoDopen( buf ); if ( dir >= 0 ) { sceIoDclose( dir ); return true; } } return false; }