2021-03-02 20:42:55 -08:00
# include "ppsspp_config.h"
2018-03-24 12:44:53 +01:00
# include <cstring>
# include <cassert>
# include <thread>
# include <atomic>
2018-03-25 23:07:02 +01:00
# include <vector>
2020-10-04 10:10:55 +02:00
# include <cstdlib>
2021-12-05 17:31:36 +01:00
# include <mutex>
2018-03-24 12:44:53 +01:00
2021-06-12 23:42:52 +02:00
# include "Common/CPUDetect.h"
2020-10-04 10:10:55 +02:00
# include "Common/Log.h"
# include "Common/LogManager.h"
# include "Common/System/Display.h"
2020-10-04 10:30:18 +02:00
# include "Common/System/NativeApp.h"
# include "Common/System/System.h"
2020-08-15 20:53:08 +02:00
# include "Common/TimeUtil.h"
2020-10-04 20:48:47 +02:00
# include "Common/File/FileUtil.h"
2020-08-10 00:12:51 -07:00
# include "Common/Serialize/Serializer.h"
2020-10-04 10:10:55 +02:00
# include "Common/ConsoleListener.h"
# include "Common/Input/InputState.h"
# include "Common/Thread/ThreadUtil.h"
2021-06-12 23:42:52 +02:00
# include "Common/Thread/ThreadManager.h"
2020-10-04 10:10:55 +02:00
# include "Common/File/VFS/VFS.h"
# include "Common/File/VFS/AssetReader.h"
2021-07-18 14:59:21 +09:00
# include "Common/Data/Text/I18n.h"
2020-10-04 10:10:55 +02:00
2018-03-24 12:44:53 +01:00
# include "Core/Config.h"
2018-06-16 18:42:31 -07:00
# include "Core/ConfigValues.h"
2018-03-24 12:44:53 +01:00
# include "Core/Core.h"
# include "Core/HLE/sceCtrl.h"
# include "Core/HLE/sceUtility.h"
# include "Core/HLE/__sceAudio.h"
# include "Core/HW/MemoryStick.h"
# include "Core/Host.h"
2018-07-31 23:57:10 -04:00
# include "Core/MemMap.h"
2018-03-24 12:44:53 +01:00
# include "Core/System.h"
2022-05-16 16:25:56 +01:00
# include "Core/CoreTiming.h"
# include "Core/HW/Display.h"
2020-10-04 10:10:55 +02:00
2018-03-24 12:44:53 +01:00
# include "GPU/GPUState.h"
# include "GPU/GPUInterface.h"
2020-08-03 23:17:22 +02:00
# include "GPU/Common/FramebufferManagerCommon.h"
2018-03-24 12:44:53 +01:00
# include "GPU/Common/TextureScalerCommon.h"
2020-10-11 20:26:39 +02:00
# include "GPU/Common/PresentationCommon.h"
2018-03-24 12:44:53 +01:00
# include "libretro/libretro.h"
# include "libretro/LibretroGraphicsContext.h"
2020-08-03 19:04:40 +02:00
# if PPSSPP_PLATFORM(ANDROID)
# include <sys/system_properties.h>
# endif
2018-03-24 12:44:53 +01:00
# define DIR_SEP " / "
# ifdef _WIN32
# define DIR_SEP_CHRS " / \\"
# else
# define DIR_SEP_CHRS " / "
# endif
# define SAMPLERATE 44100
2021-12-05 17:31:36 +01:00
# define AUDIO_RING_BUFFER_SIZE (1 << 16)
# define AUDIO_RING_BUFFER_SIZE_MASK (AUDIO_RING_BUFFER_SIZE - 1)
// An alpha factor of 1/180 is *somewhat* equivalent
// to calculating the average for the last 180
// frames, or 3 seconds of runtime...
# define AUDIO_FRAMES_MOVING_AVG_ALPHA (1.0f / 180.0f)
2022-05-16 16:25:56 +01:00
// Calculated swap interval is 'stable' if the same
// value is recorded for a number of retro_run()
// calls equal to VSYNC_SWAP_INTERVAL_FRAMES
# define VSYNC_SWAP_INTERVAL_FRAMES 6
// Calculated swap interval is 'valid' if it is
// within VSYNC_SWAP_INTERVAL_THRESHOLD of an integer
// value
# define VSYNC_SWAP_INTERVAL_THRESHOLD 0.05f
// Swap interval detection is only enabled if the
// core is running at 'normal' speed - i.e. if
// run speed is within VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD
// percent of 100
# define VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD 5.0f
2020-07-13 19:13:18 +02:00
static bool libretro_supports_bitmasks = false ;
2022-05-13 16:48:06 +02:00
static std : : string changeProAdhocServer ;
2020-07-13 19:13:18 +02:00
2020-07-13 21:11:26 +02:00
namespace Libretro
{
LibretroGraphicsContext * ctx ;
retro_environment_t environ_cb ;
static retro_audio_sample_batch_t audio_batch_cb ;
static retro_input_poll_t input_poll_cb ;
static retro_input_state_t input_state_cb ;
2018-03-26 17:37:34 +01:00
} // namespace Libretro
2018-03-24 12:44:53 +01:00
2022-05-16 16:25:56 +01:00
namespace Libretro
{
static bool detectVsyncSwapInterval = false ;
static bool detectVsyncSwapIntervalOptShown = true ;
static s64 expectedTimeUsPerRun = 0 ;
static uint32_t vsyncSwapInterval = 1 ;
static uint32_t vsyncSwapIntervalLast = 1 ;
static uint32_t vsyncSwapIntervalCounter = 0 ;
static int numVBlanksLast = 0 ;
static double fpsTimeLast = 0.0 ;
static float runSpeed = 0.0f ;
static s64 runTicksLast = 0 ;
static void VsyncSwapIntervalReset ( )
{
expectedTimeUsPerRun = ( s64 ) ( 1000000.0f / ( 60.0f / 1.001f ) ) ;
vsyncSwapInterval = 1 ;
vsyncSwapIntervalLast = 1 ;
vsyncSwapIntervalCounter = 0 ;
numVBlanksLast = 0 ;
fpsTimeLast = 0.0 ;
runSpeed = 0.0f ;
runTicksLast = 0 ;
detectVsyncSwapIntervalOptShown = true ;
}
static void VsyncSwapIntervalDetect ( )
{
if ( ! detectVsyncSwapInterval )
return ;
// All bets are off if core is running at
// the 'wrong' speed (i.e. cycle count for
// this run will be meaningless if internal
// frame rate is dropping below expected
// value, or fast forward is enabled)
double fpsTime = time_now_d ( ) ;
int numVBlanks = __DisplayGetNumVblanks ( ) ;
int frames = numVBlanks - numVBlanksLast ;
if ( frames > = VSYNC_SWAP_INTERVAL_FRAMES < < 1 )
{
double fps = ( double ) frames / ( fpsTime - fpsTimeLast ) ;
runSpeed = fps / ( ( 60.0f / 1.001f ) / 100.0f ) ;
fpsTimeLast = fpsTime ;
numVBlanksLast = numVBlanks ;
}
float speedDelta = 100.0f - runSpeed ;
speedDelta = ( speedDelta < 0.0f ) ? - speedDelta : speedDelta ;
// Speed is measured relative to a 60 Hz refresh
// rate. If we are transitioning from a low internal
// frame rate to a higher internal frame rate, then
// 'full speed' may actually equate to
// (100 / current_swap_interval)...
if ( ( vsyncSwapInterval > 1 ) & &
( speedDelta > = VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD ) )
{
speedDelta = 100.0f - ( runSpeed * ( float ) vsyncSwapInterval ) ;
speedDelta = ( speedDelta < 0.0f ) ? - speedDelta : speedDelta ;
}
if ( speedDelta > = VSYNC_SWAP_INTERVAL_RUN_SPEED_THRESHOLD )
{
// Swap interval detection is invalid - bail out
vsyncSwapIntervalCounter = 0 ;
return ;
}
// Get elapsed time (us) for this run
s64 runTicks = CoreTiming : : GetTicks ( ) ;
s64 runTimeUs = cyclesToUs ( runTicks - runTicksLast ) ;
// Check if current internal frame rate is a
// factor of the default ~60 Hz
float swapRatio = ( float ) runTimeUs / ( float ) expectedTimeUsPerRun ;
uint32_t swapInteger ;
float swapRemainder ;
// If internal frame rate is equal to (within threshold)
// or higher than the default ~60 Hz, fall back to a
// swap interval of 1
if ( swapRatio < ( 1.0f + VSYNC_SWAP_INTERVAL_THRESHOLD ) )
{
swapInteger = 1 ;
swapRemainder = 0.0f ;
}
else
{
swapInteger = ( uint32_t ) ( swapRatio + 0.5f ) ;
swapRemainder = swapRatio - ( float ) swapInteger ;
swapRemainder = ( swapRemainder < 0.0f ) ?
- swapRemainder : swapRemainder ;
}
// > Swap interval is considered 'valid' if it is
// within VSYNC_SWAP_INTERVAL_THRESHOLD of an integer
// value
// > If valid, check if new swap interval differs from
// previously logged value
if ( ( swapRemainder < = VSYNC_SWAP_INTERVAL_THRESHOLD ) & &
( swapInteger ! = vsyncSwapInterval ) )
{
vsyncSwapIntervalCounter =
( swapInteger = = vsyncSwapIntervalLast ) ?
( vsyncSwapIntervalCounter + 1 ) : 0 ;
// Check whether swap interval is 'stable'
if ( vsyncSwapIntervalCounter > = VSYNC_SWAP_INTERVAL_FRAMES )
{
vsyncSwapInterval = swapInteger ;
vsyncSwapIntervalCounter = 0 ;
// Notify frontend
retro_system_av_info avInfo ;
retro_get_system_av_info ( & avInfo ) ;
environ_cb ( RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO , & avInfo ) ;
}
vsyncSwapIntervalLast = swapInteger ;
}
else
vsyncSwapIntervalCounter = 0 ;
runTicksLast = runTicks ;
}
} // namespace Libretro
2021-12-05 17:31:36 +01:00
namespace Libretro
{
static std : : mutex audioSampleLock_ ;
static int16_t audioRingBuffer [ AUDIO_RING_BUFFER_SIZE ] = { 0 } ;
static uint32_t audioRingBufferBase = 0 ;
static uint32_t audioRingBufferIndex = 0 ;
static int16_t * audioOutBuffer = NULL ;
static uint32_t audioOutBufferSize = 0 ;
static float audioOutFramesAvg = 0.0f ;
2021-12-07 16:21:59 +00:00
// Set this to an arbitrarily large value,
// it will be fine tuned in AudioUploadSamples()
static uint32_t audioBatchFramesMax = AUDIO_RING_BUFFER_SIZE > > 1 ;
2021-12-05 17:31:36 +01:00
static void AudioBufferFlush ( )
{
const std : : lock_guard < std : : mutex > lock ( audioSampleLock_ ) ;
audioRingBufferBase = 0 ;
audioRingBufferIndex = 0 ;
audioOutFramesAvg = ( float ) SAMPLERATE / ( 60.0f / 1.001f ) ;
}
static void AudioBufferInit ( )
{
audioOutFramesAvg = ( float ) SAMPLERATE / ( 60.0f / 1.001f ) ;
audioOutBufferSize = ( ( uint32_t ) audioOutFramesAvg + 1 ) * 2 ;
audioOutBuffer = ( int16_t * ) malloc ( audioOutBufferSize * sizeof ( int16_t ) ) ;
2021-12-07 16:21:59 +00:00
audioBatchFramesMax = AUDIO_RING_BUFFER_SIZE > > 1 ;
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
}
static void AudioBufferDeinit ( )
{
if ( audioOutBuffer )
free ( audioOutBuffer ) ;
audioOutBuffer = NULL ;
audioOutBufferSize = 0 ;
audioOutFramesAvg = 0.0f ;
2021-12-07 16:21:59 +00:00
audioBatchFramesMax = AUDIO_RING_BUFFER_SIZE > > 1 ;
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
}
static uint32_t AudioBufferOccupancy ( )
{
const std : : lock_guard < std : : mutex > lock ( audioSampleLock_ ) ;
uint32_t occupancy = ( audioRingBufferIndex - audioRingBufferBase ) &
AUDIO_RING_BUFFER_SIZE_MASK ;
return occupancy > > 1 ;
}
static void AudioBufferWrite ( int16_t * audio , uint32_t frames )
{
const std : : lock_guard < std : : mutex > lock ( audioSampleLock_ ) ;
uint32_t frameIndex ;
uint32_t bufferIndex = audioRingBufferIndex ;
for ( frameIndex = 0 ; frameIndex < frames ; frameIndex + + )
{
audioRingBuffer [ audioRingBufferIndex ] = * ( audio + + ) ;
audioRingBuffer [ audioRingBufferIndex + 1 ] = * ( audio + + ) ;
audioRingBufferIndex = ( audioRingBufferIndex + 2 ) % AUDIO_RING_BUFFER_SIZE ;
}
}
static uint32_t AudioBufferRead ( int16_t * audio , uint32_t frames )
{
const std : : lock_guard < std : : mutex > lock ( audioSampleLock_ ) ;
uint32_t framesAvailable = ( ( audioRingBufferIndex - audioRingBufferBase ) &
AUDIO_RING_BUFFER_SIZE_MASK ) > > 1 ;
uint32_t frameIndex ;
if ( frames > framesAvailable )
frames = framesAvailable ;
for ( frameIndex = 0 ; frameIndex < frames ; frameIndex + + )
{
uint32_t bufferIndex = ( audioRingBufferBase + ( frameIndex < < 1 ) ) &
AUDIO_RING_BUFFER_SIZE_MASK ;
* ( audio + + ) = audioRingBuffer [ bufferIndex ] ;
* ( audio + + ) = audioRingBuffer [ bufferIndex + 1 ] ;
}
audioRingBufferBase + = frames < < 1 ;
audioRingBufferBase & = AUDIO_RING_BUFFER_SIZE_MASK ;
return frames ;
}
static void AudioUploadSamples ( )
{
2022-05-16 16:25:56 +01:00
// - If 'Detect Frame Rate Changes' is disabled, then
// the core specifies a fixed frame rate of (60.0f / 1.001f)
// - At the audio sample rate of 44100, this means the
// frontend expects exactly 735.735 sample frames per call of
// retro_run()
// - If g_Config.bRenderDuplicateFrames is enabled and
// frameskip is disabled, the mean of the buffer occupancy
// willapproximate to this value in most cases
2021-12-05 17:31:36 +01:00
uint32_t framesAvailable = AudioBufferOccupancy ( ) ;
if ( framesAvailable > 0 )
{
// Update 'running average' of buffer occupancy.
// Note that this is not a true running
// average, but just a leaky-integrator/
// exponential moving average, used because
// it is simple and fast (i.e. requires no
// window of samples).
audioOutFramesAvg = ( AUDIO_FRAMES_MOVING_AVG_ALPHA * ( float ) framesAvailable ) +
( ( 1.0f - AUDIO_FRAMES_MOVING_AVG_ALPHA ) * audioOutFramesAvg ) ;
uint32_t frames = ( uint32_t ) audioOutFramesAvg ;
if ( audioOutBufferSize < ( frames < < 1 ) )
{
audioOutBufferSize = ( frames < < 1 ) ;
audioOutBuffer = ( int16_t * ) realloc ( audioOutBuffer ,
audioOutBufferSize * sizeof ( int16_t ) ) ;
}
frames = AudioBufferRead ( audioOutBuffer , frames ) ;
int16_t * audioOutBufferPtr = audioOutBuffer ;
while ( frames > 0 )
{
2021-12-07 16:21:59 +00:00
uint32_t framesToWrite = ( frames > audioBatchFramesMax ) ?
audioBatchFramesMax : frames ;
uint32_t framesWritten = audio_batch_cb ( audioOutBufferPtr ,
framesToWrite ) ;
if ( ( framesWritten < framesToWrite ) & &
( framesWritten > 0 ) )
audioBatchFramesMax = framesWritten ;
2021-12-05 17:31:36 +01:00
frames - = framesToWrite ;
audioOutBufferPtr + = framesToWrite < < 1 ;
}
}
}
} // namespace Libretro
2018-03-24 12:44:53 +01:00
using namespace Libretro ;
2020-07-13 21:11:26 +02:00
class LibretroHost : public Host
{
public :
LibretroHost ( ) { }
bool InitGraphics ( std : : string * error_message , GraphicsContext * * ctx ) override { return true ; }
void ShutdownGraphics ( ) override { }
void InitSound ( ) override { }
void UpdateSound ( ) override
{
extern int hostAttemptBlockSize ;
const int blockSizeMax = 512 ;
static int16_t audio [ blockSizeMax * 2 ] ;
assert ( hostAttemptBlockSize < = blockSizeMax ) ;
int samples = __AudioMix ( audio , hostAttemptBlockSize , SAMPLERATE ) ;
2021-12-05 17:31:36 +01:00
AudioBufferWrite ( audio , samples ) ;
2020-07-13 21:11:26 +02:00
}
void ShutdownSound ( ) override { }
bool IsDebuggingEnabled ( ) override { return false ; }
bool AttemptLoadSymbolMap ( ) override { return false ; }
2018-03-24 12:44:53 +01:00
} ;
2020-07-13 21:11:26 +02:00
class PrintfLogger : public LogListener
{
public :
PrintfLogger ( retro_log_callback log ) : log_ ( log . log ) { }
void Log ( const LogMessage & message )
{
switch ( message . level )
{
case LogTypes : : LVERBOSE :
case LogTypes : : LDEBUG :
log_ ( RETRO_LOG_DEBUG , " [%s] %s " ,
message . log , message . msg . c_str ( ) ) ;
break ;
case LogTypes : : LERROR :
log_ ( RETRO_LOG_ERROR , " [%s] %s " ,
message . log , message . msg . c_str ( ) ) ;
break ;
case LogTypes : : LNOTICE :
case LogTypes : : LWARNING :
log_ ( RETRO_LOG_WARN , " [%s] %s " ,
message . log , message . msg . c_str ( ) ) ;
break ;
case LogTypes : : LINFO :
default :
log_ ( RETRO_LOG_INFO , " [%s] %s " ,
message . log , message . msg . c_str ( ) ) ;
break ;
}
}
private :
retro_log_printf_t log_ ;
2018-03-24 12:44:53 +01:00
} ;
static PrintfLogger * printfLogger ;
2020-07-13 21:11:26 +02:00
template < typename T > class RetroOption
{
public :
RetroOption ( const char * id , const char * name , std : : initializer_list < std : : pair < const char * , T > > list ) : id_ ( id ) , name_ ( name ) , list_ ( list . begin ( ) , list . end ( ) ) { }
RetroOption ( const char * id , const char * name , std : : initializer_list < const char * > list ) : id_ ( id ) , name_ ( name ) {
for ( auto option : list )
list_ . push_back ( { option , ( T ) list_ . size ( ) } ) ;
}
RetroOption ( const char * id , const char * name , T first , std : : initializer_list < const char * > list ) : id_ ( id ) , name_ ( name ) {
for ( auto option : list )
list_ . push_back ( { option , first + ( int ) list_ . size ( ) } ) ;
}
RetroOption ( const char * id , const char * name , T first , int count , int step = 1 ) : id_ ( id ) , name_ ( name ) {
for ( T i = first ; i < first + count ; i + = step )
list_ . push_back ( { std : : to_string ( i ) , i } ) ;
}
RetroOption ( const char * id , const char * name , bool initial ) : id_ ( id ) , name_ ( name ) {
list_ . push_back ( { initial ? " enabled " : " disabled " , initial } ) ;
list_ . push_back ( { ! initial ? " enabled " : " disabled " , ! initial } ) ;
}
retro_variable GetOptions ( )
{
if ( options_ . empty ( ) )
{
options_ = name_ ;
options_ . push_back ( ' ; ' ) ;
for ( auto & option : list_ )
{
if ( option . first = = list_ . begin ( ) - > first )
options_ + = std : : string ( " " ) + option . first ;
else
options_ + = std : : string ( " | " ) + option . first ;
}
}
return { id_ , options_ . c_str ( ) } ;
}
bool Update ( T * dest )
{
retro_variable var { id_ } ;
T val = list_ . front ( ) . second ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
for ( auto option : list_ )
{
if ( option . first = = var . value )
{
val = option . second ;
break ;
}
}
}
if ( * dest ! = val )
{
* dest = val ;
return true ;
}
return false ;
}
2022-05-13 16:48:06 +02:00
void Show ( bool show )
{
2022-05-13 16:59:21 +02:00
struct retro_core_option_display optionDisplay { id_ , show } ;
environ_cb ( RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY , & optionDisplay ) ;
2022-05-13 16:48:06 +02:00
}
2022-05-14 00:34:25 +02:00
void Set ( const char * val )
{
struct retro_variable var { id_ , val } ;
environ_cb ( RETRO_ENVIRONMENT_SET_VARIABLE , & var ) ;
}
2020-07-13 21:11:26 +02:00
private :
const char * id_ ;
const char * name_ ;
std : : string options_ ;
std : : vector < std : : pair < std : : string , T > > list_ ;
2018-03-24 12:44:53 +01:00
} ;
2022-05-14 00:34:25 +02:00
# define MAC_INITIALIZER_LIST \
{ \
{ " 0 " , " 0 " } , \
{ " 1 " , " 1 " } , \
{ " 2 " , " 2 " } , \
{ " 3 " , " 3 " } , \
{ " 4 " , " 4 " } , \
{ " 5 " , " 5 " } , \
{ " 6 " , " 6 " } , \
{ " 7 " , " 7 " } , \
{ " 8 " , " 8 " } , \
{ " 9 " , " 9 " } , \
{ " a " , " a " } , \
{ " b " , " b " } , \
{ " c " , " c " } , \
{ " d " , " d " } , \
{ " e " , " e " } , \
{ " f " , " f " } \
}
2021-09-06 20:13:07 +01:00
static RetroOption < CPUCore > ppsspp_cpu_core ( " ppsspp_cpu_core " , " CPU Core " , { { " JIT " , CPUCore : : JIT } , { " IR JIT " , CPUCore : : IR_JIT } , { " Interpreter " , CPUCore : : INTERPRETER } } ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < int > ppsspp_locked_cpu_speed ( " ppsspp_locked_cpu_speed " , " Locked CPU Speed " , { { " off " , 0 } , { " 222MHz " , 222 } , { " 266MHz " , 266 } , { " 333MHz " , 333 } } ) ;
2021-09-06 20:13:07 +01:00
static RetroOption < int > ppsspp_language ( " ppsspp_language " , " Language " , { { " Automatic " , - 1 } , { " English " , PSP_SYSTEMPARAM_LANGUAGE_ENGLISH } , { " Japanese " , PSP_SYSTEMPARAM_LANGUAGE_JAPANESE } , { " French " , PSP_SYSTEMPARAM_LANGUAGE_FRENCH } , { " Spanish " , PSP_SYSTEMPARAM_LANGUAGE_SPANISH } , { " German " , PSP_SYSTEMPARAM_LANGUAGE_GERMAN } , { " Italian " , PSP_SYSTEMPARAM_LANGUAGE_ITALIAN } , { " Dutch " , PSP_SYSTEMPARAM_LANGUAGE_DUTCH } , { " Portuguese " , PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE } , { " Russian " , PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN } , { " Korean " , PSP_SYSTEMPARAM_LANGUAGE_KOREAN } , { " Chinese Traditional " , PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL } , { " Chinese Simplified " , PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED } } ) ;
static RetroOption < int > ppsspp_rendering_mode ( " ppsspp_rendering_mode " , " Rendering Mode " , { { " Buffered " , FB_BUFFERED_MODE } , { " Skip Buffer Effects " , FB_NON_BUFFERED_MODE } } ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < bool > ppsspp_auto_frameskip ( " ppsspp_auto_frameskip " , " Auto Frameskip " , false ) ;
2021-09-06 20:13:07 +01:00
static RetroOption < int > ppsspp_frameskip ( " ppsspp_frameskip " , " Frameskip " , { " Off " , " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 6 " , " 7 " , " 8 " } ) ;
static RetroOption < int > ppsspp_frameskiptype ( " ppsspp_frameskiptype " , " Frameskip Type " , { { " Number of frames " , 0 } , { " Percent of FPS " , 1 } } ) ;
static RetroOption < int > ppsspp_internal_resolution ( " ppsspp_internal_resolution " , " Internal Resolution (Restart) " , 1 , { " 480x272 " , " 960x544 " , " 1440x816 " , " 1920x1088 " , " 2400x1360 " , " 2880x1632 " , " 3360x1904 " , " 3840x2176 " , " 4320x2448 " , " 4800x2720 " } ) ;
static RetroOption < int > ppsspp_button_preference ( " ppsspp_button_preference " , " Confirmation Button " , { { " Cross " , PSP_SYSTEMPARAM_BUTTON_CROSS } , { " Circle " , PSP_SYSTEMPARAM_BUTTON_CIRCLE } } ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < bool > ppsspp_fast_memory ( " ppsspp_fast_memory " , " Fast Memory (Speedhack) " , true ) ;
static RetroOption < bool > ppsspp_block_transfer_gpu ( " ppsspp_block_transfer_gpu " , " Block Transfer GPU " , true ) ;
2021-09-06 19:47:39 -07:00
static RetroOption < int > ppsspp_inflight_frames ( " ppsspp_inflight_frames " , " Buffered frames (Slower, less lag, restart) " , { { " Up to 2 " , 2 } , { " Up to 1 " , 1 } , { " No buffer " , 0 } , } ) ;
2021-10-05 19:26:56 -07:00
static RetroOption < int > ppsspp_texture_scaling_level ( " ppsspp_texture_scaling_level " , " Texture Scaling Level " , { { " Off " , 1 } , { " 2x " , 2 } , { " 3x " , 3 } , { " 4x " , 4 } , { " 5x " , 5 } } ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < int > ppsspp_texture_scaling_type ( " ppsspp_texture_scaling_type " , " Texture Scaling Type " , { { " xbrz " , TextureScalerCommon : : XBRZ } , { " hybrid " , TextureScalerCommon : : HYBRID } , { " bicubic " , TextureScalerCommon : : BICUBIC } , { " hybrid_bicubic " , TextureScalerCommon : : HYBRID_BICUBIC } } ) ;
2022-01-27 08:27:04 +00:00
static RetroOption < std : : string > ppsspp_texture_shader ( " ppsspp_texture_shader " , " Texture Shader (Vulkan only, overrides Texture Scaling Type) " , { { " Off " , " Off " } , { " 2xBRZ " , " Tex2xBRZ " } , { " 4xBRZ " , " Tex4xBRZ " } , { " MMPX " , " TexMMPX " } } ) ;
2021-09-08 09:27:15 +01:00
static RetroOption < int > ppsspp_texture_filtering ( " ppsspp_texture_filtering " , " Texture Filtering " , { { " Auto " , 1 } , { " Nearest " , 2 } , { " Linear " , 3 } , { " Auto max quality " , 4 } } ) ;
2021-08-30 16:38:37 +02:00
static RetroOption < int > ppsspp_texture_anisotropic_filtering ( " ppsspp_texture_anisotropic_filtering " , " Anisotropic Filtering " , { " off " , " 2x " , " 4x " , " 8x " , " 16x " } ) ;
2021-09-06 20:13:07 +01:00
static RetroOption < int > ppsspp_lower_resolution_for_effects ( " ppsspp_lower_resolution_for_effects " , " Lower resolution for effects " , { { " Off " , 0 } , { " Safe " , 1 } , { " Balanced " , 2 } , { " Aggressive " , 3 } } ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < bool > ppsspp_texture_deposterize ( " ppsspp_texture_deposterize " , " Texture Deposterize " , false ) ;
2018-10-27 20:52:54 -05:00
static RetroOption < bool > ppsspp_texture_replacement ( " ppsspp_texture_replacement " , " Texture Replacement " , false ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < bool > ppsspp_gpu_hardware_transform ( " ppsspp_gpu_hardware_transform " , " GPU Hardware T&L " , true ) ;
2021-04-15 13:22:59 +01:00
static RetroOption < bool > ppsspp_vertex_cache ( " ppsspp_vertex_cache " , " Vertex Cache (Speedhack) " , false ) ;
2018-03-24 12:44:53 +01:00
static RetroOption < bool > ppsspp_cheats ( " ppsspp_cheats " , " Internal Cheats Support " , false ) ;
2019-04-20 18:02:09 +09:00
static RetroOption < IOTimingMethods > ppsspp_io_timing_method ( " ppsspp_io_timing_method " , " IO Timing Method " , { { " Fast " , IOTimingMethods : : IOTIMING_FAST } , { " Host " , IOTimingMethods : : IOTIMING_HOST } , { " Simulate UMD delays " , IOTimingMethods : : IOTIMING_REALISTIC } } ) ;
2022-05-16 16:25:56 +01:00
static RetroOption < bool > ppsspp_frame_duplication ( " ppsspp_frame_duplication " , " Duplicate Frames in 30 Hz Games " , false ) ;
static RetroOption < bool > ppsspp_detect_vsync_swap_interval ( " ppsspp_detect_vsync_swap_interval " , " Detect Frame Rate Changes (Notify Frontend) " , false ) ;
2021-04-13 21:07:48 +01:00
static RetroOption < bool > ppsspp_software_skinning ( " ppsspp_software_skinning " , " Software Skinning " , true ) ;
static RetroOption < bool > ppsspp_ignore_bad_memory_access ( " ppsspp_ignore_bad_memory_access " , " Ignore bad memory accesses " , true ) ;
2021-09-06 20:13:07 +01:00
static RetroOption < bool > ppsspp_lazy_texture_caching ( " ppsspp_lazy_texture_caching " , " Lazy texture caching (Speedup) " , false ) ;
static RetroOption < bool > ppsspp_retain_changed_textures ( " ppsspp_retain_changed_textures " , " Retain changed textures (Speedup, mem hog) " , false ) ;
static RetroOption < bool > ppsspp_force_lag_sync ( " ppsspp_force_lag_sync " , " Force real clock sync (Slower, less lag) " , false ) ;
static RetroOption < int > ppsspp_spline_quality ( " ppsspp_spline_quality " , " Spline/Bezier curves quality " , { { " Low " , 0 } , { " Medium " , 1 } , { " High " , 2 } } ) ;
static RetroOption < bool > ppsspp_disable_slow_framebuffer_effects ( " ppsspp_disable_slow_framebuffer_effects " , " Disable slower effects (Speedup) " , false ) ;
2022-05-13 16:48:06 +02:00
static RetroOption < bool > ppsspp_enable_wlan ( " ppsspp_enable_wlan " , " Enable Networking/WLAN (beta, may break games) " , false ) ;
2022-05-14 00:34:25 +02:00
static RetroOption < std : : string > ppsspp_change_mac_address [ ] = {
{ " ppsspp_change_mac_address01 " , " MAC address Pt 1: X-:--:--:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address02 " , " MAC address Pt 2: -X:--:--:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address03 " , " MAC address Pt 3: --:X-:--:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address04 " , " MAC address Pt 4: --:-X:--:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address05 " , " MAC address Pt 5: --:--:X-:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address06 " , " MAC address Pt 6: --:--:-X:--:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address07 " , " MAC address Pt 7: --:--:--:X-:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address08 " , " MAC address Pt 8: --:--:--:-X:--:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address09 " , " MAC address Pt 9: --:--:--:--:X-:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address10 " , " MAC address Pt 10: --:--:--:--:-X:-- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address11 " , " MAC address Pt 11: --:--:--:--:--:X- " , MAC_INITIALIZER_LIST } ,
{ " ppsspp_change_mac_address12 " , " MAC address Pt 12: --:--:--:--:--:-X " , MAC_INITIALIZER_LIST }
} ;
2022-05-13 16:48:06 +02:00
static RetroOption < int > ppsspp_wlan_channel ( " ppsspp_wlan_channel " , " WLAN channel " , { { " Auto " , 0 } , { " 1 " , 1 } , { " 6 " , 6 } , { " 11 " , 11 } } ) ;
static RetroOption < bool > ppsspp_enable_builtin_pro_ad_hoc_server ( " ppsspp_enable_builtin_pro_ad_hoc_server " , " Enable built-in PRO ad hoc server " , false ) ;
2022-05-13 16:59:21 +02:00
static RetroOption < std : : string > ppsspp_change_pro_ad_hoc_server_address ( " ppsspp_change_pro_ad_hoc_server_address " , " Change PRO ad hoc server IP address (localhost = multiple instances) " , {
2022-05-13 16:48:06 +02:00
{ " socom.cc " , " socom.cc " } ,
2022-06-26 19:47:33 +07:00
{ " psp.gameplayer.club " , " psp.gameplayer.club " } ,
2022-05-13 16:48:06 +02:00
{ " myneighborsushicat.com " , " myneighborsushicat.com " } ,
{ " localhost " , " localhost " } ,
{ " IP address " , " IP address " }
} ) ;
static RetroOption < int > ppsspp_pro_ad_hoc_ipv4 [ ] = {
2022-05-13 16:59:21 +02:00
{ " ppsspp_pro_ad_hoc_server_address01 " , " PRO ad hoc server IP address Pt 1: x--.---.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address02 " , " PRO ad hoc server IP address Pt 2: -x-.---.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address03 " , " PRO ad hoc server IP address Pt 3: --x.---.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address04 " , " PRO ad hoc server IP address Pt 4: ---.x--.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address05 " , " PRO ad hoc server IP address Pt 5: ---.-x-.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address06 " , " PRO ad hoc server IP address Pt 6: ---.--x.---.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address07 " , " PRO ad hoc server IP address Pt 7: ---.---.x--.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address08 " , " PRO ad hoc server IP address Pt 8: ---.---.-x-.--- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address09 " , " PRO ad hoc server IP address Pt 9: ---.---.--x.--- " , 0 , 10 , 1 } ,
2022-05-13 16:48:06 +02:00
{ " ppsspp_pro_ad_hoc_server_address10 " , " PRO ad hoc server IP address Pt 10: ---.---.---.x-- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address11 " , " PRO ad hoc server IP address Pt 11: ---.---.---.-x- " , 0 , 10 , 1 } ,
{ " ppsspp_pro_ad_hoc_server_address12 " , " PRO ad hoc server IP address Pt 12: ---.---.---.--x " , 0 , 10 , 1 }
} ;
2022-05-13 20:21:20 +02:00
static RetroOption < bool > ppsspp_enable_upnp ( " ppsspp_enable_upnp " , " Enable UPnP (need a few seconds to detect) " , false ) ;
2022-05-13 16:48:06 +02:00
static RetroOption < bool > ppsspp_upnp_use_original_port ( " ppsspp_upnp_use_original_port " , " UPnP use original port (enabled = PSP compatibility) " , true ) ;
2022-05-14 19:44:59 +02:00
static RetroOption < int > ppsspp_port_offset ( " ppsspp_port_offset " , " Port offset (0 = PSP compatibility) " , 0 , 65001 , 1000 ) ;
2022-05-15 11:06:34 +02:00
static RetroOption < int > ppsspp_minimum_timeout ( " ppsspp_minimum timeout " , " Minimum timeout (override in ms, 0 = default)) " , 0 , 5001 , 100 ) ;
2022-05-13 16:48:06 +02:00
static RetroOption < bool > ppsspp_forced_first_connect ( " ppsspp_forced_first_connect " , " Forced first connect (faster connect) " , false ) ;
static bool set_variable_visibility ( void )
{
bool updated = false ;
if ( ppsspp_change_pro_ad_hoc_server_address . Update ( & changeProAdhocServer ) )
updated = true ;
if ( changeProAdhocServer = = " IP address " )
{
g_Config . proAdhocServer = " " ;
for ( int i = 0 ; ; )
{
int addressPt = 0 ;
ppsspp_pro_ad_hoc_ipv4 [ i ] . Show ( true ) ;
ppsspp_pro_ad_hoc_ipv4 [ i ] . Update ( & addressPt ) ;
g_Config . proAdhocServer + = static_cast < char > ( ' 0 ' + addressPt ) ;
if ( + + i = = 12 )
break ;
if ( i % 3 = = 0 )
g_Config . proAdhocServer + = ' . ' ;
}
}
else
{
g_Config . proAdhocServer = changeProAdhocServer ;
for ( int i = 0 ; i < 12 ; + + i )
ppsspp_pro_ad_hoc_ipv4 [ i ] . Show ( false ) ;
}
if ( ppsspp_enable_upnp . Update ( & g_Config . bEnableUPnP ) )
updated = true ;
2022-05-16 16:25:56 +01:00
ppsspp_upnp_use_original_port . Show ( g_Config . bEnableUPnP ) ;
bool detectVsyncSwapIntervalOptShownLast = detectVsyncSwapIntervalOptShown ;
bool autoFrameSkip = false ;
int frameSkip = 0 ;
bool renderDuplicateFrames = false ;
ppsspp_auto_frameskip . Update ( & autoFrameSkip ) ;
ppsspp_frameskip . Update ( & frameSkip ) ;
ppsspp_frame_duplication . Update ( & renderDuplicateFrames ) ;
detectVsyncSwapIntervalOptShown =
! autoFrameSkip & &
( frameSkip = = 0 ) & &
! renderDuplicateFrames ;
if ( detectVsyncSwapIntervalOptShown ! = detectVsyncSwapIntervalOptShownLast )
{
ppsspp_detect_vsync_swap_interval . Show ( detectVsyncSwapIntervalOptShown ) ;
updated = true ;
}
2022-05-13 16:48:06 +02:00
return updated ;
}
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
void retro_set_environment ( retro_environment_t cb )
{
2022-05-13 16:48:06 +02:00
environ_cb = cb ;
struct retro_core_options_update_display_callback update_display_cb ;
update_display_cb . callback = set_variable_visibility ;
2022-05-16 16:25:56 +01:00
environ_cb ( RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK , & update_display_cb ) ;
2022-05-13 16:48:06 +02:00
2020-07-13 21:11:26 +02:00
std : : vector < retro_variable > vars ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_internal_resolution . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_cpu_core . GetOptions ( ) ) ;
vars . push_back ( ppsspp_locked_cpu_speed . GetOptions ( ) ) ;
vars . push_back ( ppsspp_language . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_button_preference . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_rendering_mode . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_gpu_hardware_transform . GetOptions ( ) ) ;
vars . push_back ( ppsspp_texture_anisotropic_filtering . GetOptions ( ) ) ;
vars . push_back ( ppsspp_spline_quality . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_auto_frameskip . GetOptions ( ) ) ;
vars . push_back ( ppsspp_frameskip . GetOptions ( ) ) ;
vars . push_back ( ppsspp_frameskiptype . GetOptions ( ) ) ;
2022-05-16 16:25:56 +01:00
vars . push_back ( ppsspp_frame_duplication . GetOptions ( ) ) ;
vars . push_back ( ppsspp_detect_vsync_swap_interval . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_vertex_cache . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_fast_memory . GetOptions ( ) ) ;
vars . push_back ( ppsspp_block_transfer_gpu . GetOptions ( ) ) ;
2021-09-06 20:14:08 +01:00
vars . push_back ( ppsspp_inflight_frames . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_software_skinning . GetOptions ( ) ) ;
vars . push_back ( ppsspp_lazy_texture_caching . GetOptions ( ) ) ;
vars . push_back ( ppsspp_retain_changed_textures . GetOptions ( ) ) ;
2021-08-09 17:16:30 -04:00
vars . push_back ( ppsspp_force_lag_sync . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_disable_slow_framebuffer_effects . GetOptions ( ) ) ;
vars . push_back ( ppsspp_lower_resolution_for_effects . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_texture_scaling_level . GetOptions ( ) ) ;
vars . push_back ( ppsspp_texture_scaling_type . GetOptions ( ) ) ;
2021-09-08 16:42:11 +01:00
vars . push_back ( ppsspp_texture_shader . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( ppsspp_texture_filtering . GetOptions ( ) ) ;
vars . push_back ( ppsspp_texture_deposterize . GetOptions ( ) ) ;
vars . push_back ( ppsspp_texture_replacement . GetOptions ( ) ) ;
vars . push_back ( ppsspp_io_timing_method . GetOptions ( ) ) ;
2021-04-13 21:07:48 +01:00
vars . push_back ( ppsspp_ignore_bad_memory_access . GetOptions ( ) ) ;
2021-04-14 23:14:52 +01:00
vars . push_back ( ppsspp_cheats . GetOptions ( ) ) ;
2022-05-13 16:48:06 +02:00
vars . push_back ( ppsspp_enable_wlan . GetOptions ( ) ) ;
2022-05-14 00:34:25 +02:00
for ( int i = 0 ; i < 12 ; + + i )
vars . push_back ( ppsspp_change_mac_address [ i ] . GetOptions ( ) ) ;
2022-05-13 16:48:06 +02:00
vars . push_back ( ppsspp_wlan_channel . GetOptions ( ) ) ;
vars . push_back ( ppsspp_enable_builtin_pro_ad_hoc_server . GetOptions ( ) ) ;
vars . push_back ( ppsspp_change_pro_ad_hoc_server_address . GetOptions ( ) ) ;
for ( int i = 0 ; i < 12 ; + + i )
vars . push_back ( ppsspp_pro_ad_hoc_ipv4 [ i ] . GetOptions ( ) ) ;
vars . push_back ( ppsspp_enable_upnp . GetOptions ( ) ) ;
vars . push_back ( ppsspp_upnp_use_original_port . GetOptions ( ) ) ;
vars . push_back ( ppsspp_port_offset . GetOptions ( ) ) ;
vars . push_back ( ppsspp_minimum_timeout . GetOptions ( ) ) ;
vars . push_back ( ppsspp_forced_first_connect . GetOptions ( ) ) ;
2020-07-13 21:11:26 +02:00
vars . push_back ( { } ) ;
2022-05-16 16:25:56 +01:00
environ_cb ( RETRO_ENVIRONMENT_SET_VARIABLES , ( void * ) vars . data ( ) ) ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
static int get_language_auto ( void )
{
retro_language val = RETRO_LANGUAGE_ENGLISH ;
environ_cb ( RETRO_ENVIRONMENT_GET_LANGUAGE , & val ) ;
switch ( val )
{
default :
case RETRO_LANGUAGE_ENGLISH :
return PSP_SYSTEMPARAM_LANGUAGE_ENGLISH ;
case RETRO_LANGUAGE_JAPANESE :
return PSP_SYSTEMPARAM_LANGUAGE_JAPANESE ;
case RETRO_LANGUAGE_FRENCH :
return PSP_SYSTEMPARAM_LANGUAGE_FRENCH ;
case RETRO_LANGUAGE_GERMAN :
return PSP_SYSTEMPARAM_LANGUAGE_GERMAN ;
case RETRO_LANGUAGE_SPANISH :
return PSP_SYSTEMPARAM_LANGUAGE_SPANISH ;
case RETRO_LANGUAGE_ITALIAN :
return PSP_SYSTEMPARAM_LANGUAGE_ITALIAN ;
case RETRO_LANGUAGE_PORTUGUESE_BRAZIL :
case RETRO_LANGUAGE_PORTUGUESE_PORTUGAL :
return PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE ;
case RETRO_LANGUAGE_RUSSIAN :
return PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN ;
case RETRO_LANGUAGE_DUTCH :
return PSP_SYSTEMPARAM_LANGUAGE_DUTCH ;
case RETRO_LANGUAGE_KOREAN :
return PSP_SYSTEMPARAM_LANGUAGE_KOREAN ;
case RETRO_LANGUAGE_CHINESE_TRADITIONAL :
return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL ;
case RETRO_LANGUAGE_CHINESE_SIMPLIFIED :
return PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED ;
}
2018-03-24 12:44:53 +01:00
}
2021-07-24 18:59:58 +01:00
static std : : string map_psp_language_to_i18n_locale ( int val )
{
switch ( val )
{
default :
case PSP_SYSTEMPARAM_LANGUAGE_ENGLISH :
return " en_US " ;
case PSP_SYSTEMPARAM_LANGUAGE_JAPANESE :
return " ja_JP " ;
case PSP_SYSTEMPARAM_LANGUAGE_FRENCH :
return " fr_FR " ;
case PSP_SYSTEMPARAM_LANGUAGE_GERMAN :
return " de_DE " ;
case PSP_SYSTEMPARAM_LANGUAGE_SPANISH :
return " es_ES " ;
case PSP_SYSTEMPARAM_LANGUAGE_ITALIAN :
return " it_IT " ;
case PSP_SYSTEMPARAM_LANGUAGE_PORTUGUESE :
return " pt_PT " ;
case PSP_SYSTEMPARAM_LANGUAGE_RUSSIAN :
return " ru_RU " ;
case PSP_SYSTEMPARAM_LANGUAGE_DUTCH :
return " nl_NL " ;
case PSP_SYSTEMPARAM_LANGUAGE_KOREAN :
return " ko_KR " ;
case PSP_SYSTEMPARAM_LANGUAGE_CHINESE_TRADITIONAL :
return " zh_TW " ;
case PSP_SYSTEMPARAM_LANGUAGE_CHINESE_SIMPLIFIED :
return " zh_CN " ;
}
}
2020-07-13 21:11:26 +02:00
static void check_variables ( CoreParameter & coreParam )
{
bool updated = false ;
2021-09-06 20:10:13 +01:00
if ( coreState ! = CoreState : : CORE_POWERUP
2021-08-09 17:16:30 -04:00
& & environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE , & updated )
2020-07-13 21:11:26 +02:00
& & ! updated )
return ;
ppsspp_button_preference . Update ( & g_Config . iButtonPreference ) ;
ppsspp_fast_memory . Update ( & g_Config . bFastMemory ) ;
ppsspp_vertex_cache . Update ( & g_Config . bVertexCache ) ;
ppsspp_gpu_hardware_transform . Update ( & g_Config . bHardwareTransform ) ;
ppsspp_frameskip . Update ( & g_Config . iFrameSkip ) ;
ppsspp_frameskiptype . Update ( & g_Config . iFrameSkipType ) ;
ppsspp_auto_frameskip . Update ( & g_Config . bAutoFrameSkip ) ;
ppsspp_block_transfer_gpu . Update ( & g_Config . bBlockTransferGPU ) ;
ppsspp_texture_filtering . Update ( & g_Config . iTexFiltering ) ;
ppsspp_texture_anisotropic_filtering . Update ( & g_Config . iAnisotropyLevel ) ;
ppsspp_texture_deposterize . Update ( & g_Config . bTexDeposterize ) ;
ppsspp_texture_replacement . Update ( & g_Config . bReplaceTextures ) ;
ppsspp_cheats . Update ( & g_Config . bEnableCheats ) ;
ppsspp_locked_cpu_speed . Update ( & g_Config . iLockedCPUSpeed ) ;
ppsspp_rendering_mode . Update ( & g_Config . iRenderingMode ) ;
ppsspp_cpu_core . Update ( ( CPUCore * ) & g_Config . iCpuCore ) ;
ppsspp_io_timing_method . Update ( ( IOTimingMethods * ) & g_Config . iIOTimingMethod ) ;
2020-11-11 00:04:02 +01:00
ppsspp_lower_resolution_for_effects . Update ( & g_Config . iBloomHack ) ;
2022-05-16 16:25:56 +01:00
ppsspp_frame_duplication . Update ( & g_Config . bRenderDuplicateFrames ) ;
ppsspp_detect_vsync_swap_interval . Update ( & detectVsyncSwapInterval ) ;
2021-04-13 21:07:48 +01:00
ppsspp_software_skinning . Update ( & g_Config . bSoftwareSkinning ) ;
ppsspp_ignore_bad_memory_access . Update ( & g_Config . bIgnoreBadMemAccess ) ;
ppsspp_lazy_texture_caching . Update ( & g_Config . bTextureBackoffCache ) ;
ppsspp_retain_changed_textures . Update ( & g_Config . bTextureSecondaryCache ) ;
ppsspp_force_lag_sync . Update ( & g_Config . bForceLagSync ) ;
ppsspp_spline_quality . Update ( & g_Config . iSplineBezierQuality ) ;
2021-04-13 23:01:46 +01:00
ppsspp_disable_slow_framebuffer_effects . Update ( & g_Config . bDisableSlowFramebufEffects ) ;
2021-09-06 20:14:08 +01:00
ppsspp_inflight_frames . Update ( & g_Config . iInflightFrames ) ;
2021-09-08 16:42:11 +01:00
const bool do_scaling_type_update = ppsspp_texture_scaling_type . Update ( & g_Config . iTexScalingType ) ;
const bool do_scaling_level_update = ppsspp_texture_scaling_level . Update ( & g_Config . iTexScalingLevel ) ;
const bool do_texture_shader_update = ppsspp_texture_shader . Update ( & g_Config . sTextureShaderName ) ;
2022-05-13 16:48:06 +02:00
2021-09-08 16:42:11 +01:00
g_Config . bTexHardwareScaling = " Off " ! = g_Config . sTextureShaderName ;
if ( gpu & & ( do_scaling_type_update | | do_scaling_level_update | | do_texture_shader_update ) )
{
gpu - > ClearCacheNextFrame ( ) ;
gpu - > Resized ( ) ;
}
2020-07-13 21:11:26 +02:00
ppsspp_language . Update ( & g_Config . iLanguage ) ;
if ( g_Config . iLanguage < 0 )
g_Config . iLanguage = get_language_auto ( ) ;
2021-07-24 18:59:58 +01:00
g_Config . sLanguageIni = map_psp_language_to_i18n_locale ( g_Config . iLanguage ) ;
2021-07-18 14:59:21 +09:00
i18nrepo . LoadIni ( g_Config . sLanguageIni ) ;
2022-05-16 16:25:56 +01:00
// Cannot detect refresh rate changes if:
// > Frame skipping is enabled
// > Frame duplication is enabled
detectVsyncSwapInterval & =
! g_Config . bAutoFrameSkip & &
( g_Config . iFrameSkip = = 0 ) & &
! g_Config . bRenderDuplicateFrames ;
bool updateAvInfo = false ;
if ( ! detectVsyncSwapInterval & & ( vsyncSwapInterval ! = 1 ) )
{
vsyncSwapInterval = 1 ;
updateAvInfo = true ;
}
2021-09-08 16:42:11 +01:00
if ( ppsspp_internal_resolution . Update ( & g_Config . iInternalResolution ) & & ! PSP_IsInited ( ) )
2020-07-13 21:11:26 +02:00
{
2020-10-11 20:26:39 +02:00
coreParam . pixelWidth = coreParam . renderWidth = g_Config . iInternalResolution * 480 ;
coreParam . pixelHeight = coreParam . renderHeight = g_Config . iInternalResolution * 272 ;
2020-07-13 21:11:26 +02:00
if ( gpu )
{
2022-05-16 16:25:56 +01:00
retro_system_av_info avInfo ;
retro_get_system_av_info ( & avInfo ) ;
environ_cb ( RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO , & avInfo ) ;
updateAvInfo = false ;
2020-07-13 21:11:26 +02:00
gpu - > Resized ( ) ;
}
}
2022-05-16 16:25:56 +01:00
if ( updateAvInfo )
{
retro_system_av_info avInfo ;
retro_get_system_av_info ( & avInfo ) ;
environ_cb ( RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO , & avInfo ) ;
}
2021-09-06 20:03:57 +01:00
bool isFastForwarding = environ_cb ( RETRO_ENVIRONMENT_GET_FASTFORWARDING , & isFastForwarding ) ;
2021-09-06 21:01:17 +01:00
coreParam . fastForward = isFastForwarding ;
2022-05-13 16:48:06 +02:00
ppsspp_enable_wlan . Update ( & g_Config . bEnableWlan ) ;
ppsspp_wlan_channel . Update ( & g_Config . iWlanAdhocChannel ) ;
ppsspp_enable_builtin_pro_ad_hoc_server . Update ( & g_Config . bEnableAdhocServer ) ;
ppsspp_upnp_use_original_port . Update ( & g_Config . bUPnPUseOriginalPort ) ;
ppsspp_port_offset . Update ( & g_Config . iPortOffset ) ;
ppsspp_minimum_timeout . Update ( & g_Config . iMinTimeout ) ;
ppsspp_forced_first_connect . Update ( & g_Config . bForcedFirstConnect ) ;
2022-05-14 00:34:25 +02:00
g_Config . sMACAddress = " " ;
for ( int i = 0 ; i < 12 ; )
{
std : : string digit ;
ppsspp_change_mac_address [ i ] . Update ( & digit ) ;
g_Config . sMACAddress + = digit ;
if ( + + i = = 12 )
break ;
if ( i % 2 = = 0 )
g_Config . sMACAddress + = " : " ;
}
if ( g_Config . sMACAddress = = " 00:00:00:00:00:00 " )
{
g_Config . sMACAddress = CreateRandMAC ( ) ;
for ( int i = 0 ; i < 12 ; + + i )
{
std : : string digit = { g_Config . sMACAddress [ i + i / 2 ] } ;
ppsspp_change_mac_address [ i ] . Set ( digit . c_str ( ) ) ;
}
}
2022-05-13 16:48:06 +02:00
set_variable_visibility ( ) ;
2018-03-24 12:44:53 +01:00
}
void retro_set_audio_sample_batch ( retro_audio_sample_batch_t cb ) { audio_batch_cb = cb ; }
void retro_set_audio_sample ( retro_audio_sample_t cb ) { ( void ) cb ; }
void retro_set_input_poll ( retro_input_poll_t cb ) { input_poll_cb = cb ; }
void retro_set_input_state ( retro_input_state_t cb ) { input_state_cb = cb ; }
2020-07-13 19:13:18 +02:00
void retro_init ( void )
{
2022-05-16 16:25:56 +01:00
VsyncSwapIntervalReset ( ) ;
2021-12-05 17:31:36 +01:00
AudioBufferInit ( ) ;
2021-06-12 23:42:52 +02:00
g_threadManager . Init ( cpu_info . num_cores , cpu_info . logical_cpu_count ) ;
2021-09-06 20:10:13 +01:00
struct retro_input_descriptor desc [ ] = {
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_LEFT , " D-Pad Left " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_UP , " D-Pad Up " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_DOWN , " D-Pad Down " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_RIGHT , " D-Pad Right " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_B , " Cross " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_A , " Circle " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_X , " Triangle " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_Y , " Square " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_L , " L " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_R , " R " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_SELECT , " Select " } ,
{ 0 , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_START , " Start " } ,
{ 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_RIGHT , RETRO_DEVICE_ID_ANALOG_X , " Right Analog X " } ,
{ 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_RIGHT , RETRO_DEVICE_ID_ANALOG_Y , " Right Analog Y " } ,
{ 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_LEFT , RETRO_DEVICE_ID_ANALOG_X , " Left Analog X " } ,
{ 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_LEFT , RETRO_DEVICE_ID_ANALOG_Y , " Left Analog Y " } ,
{ 0 } ,
} ;
environ_cb ( RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS , desc ) ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_INPUT_BITMASKS , NULL ) )
libretro_supports_bitmasks = true ;
2020-07-13 21:11:26 +02:00
2021-09-06 20:10:13 +01:00
struct retro_log_callback log ;
2020-07-13 21:11:26 +02:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_LOG_INTERFACE , & log ) )
{
2021-09-06 20:10:13 +01:00
LogManager : : Init ( & g_Config . bEnableLogging ) ;
2020-07-13 21:11:26 +02:00
printfLogger = new PrintfLogger ( log ) ;
2021-09-06 20:10:13 +01:00
LogManager * logman = LogManager : : GetInstance ( ) ;
2020-07-13 21:11:26 +02:00
logman - > RemoveListener ( logman - > GetConsoleListener ( ) ) ;
logman - > RemoveListener ( logman - > GetDebuggerListener ( ) ) ;
logman - > ChangeFileLog ( nullptr ) ;
logman - > AddListener ( printfLogger ) ;
logman - > SetAllLogLevels ( LogTypes : : LINFO ) ;
}
2020-07-13 19:13:18 +02:00
2021-09-06 20:10:13 +01:00
g_Config . Load ( " " , " " ) ;
g_Config . iInternalResolution = 0 ;
const char * nickname = NULL ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_USERNAME , & nickname ) & & nickname )
g_Config . sNickName = std : : string ( nickname ) ;
Path retro_base_dir ;
Path retro_save_dir ;
const char * dir_ptr = NULL ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY , & dir_ptr ) & & dir_ptr )
retro_base_dir = Path ( dir_ptr ) ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY , & dir_ptr ) & & dir_ptr )
retro_save_dir = Path ( dir_ptr ) ;
retro_base_dir / = " PPSSPP " ;
g_Config . currentDirectory = retro_base_dir ;
g_Config . defaultCurrentDirectory = retro_base_dir ;
g_Config . memStickDirectory = retro_save_dir ;
g_Config . flash0Directory = retro_base_dir / " flash0 " ;
g_Config . internalDataDirectory = retro_base_dir ;
2022-05-14 11:17:28 +02:00
g_Config . bEnableNetworkChat = false ;
2022-05-14 21:01:37 +02:00
g_Config . bDiscordPresence = false ;
2021-09-06 20:10:13 +01:00
VFSRegister ( " " , new DirectoryAssetReader ( retro_base_dir ) ) ;
2021-09-06 21:01:17 +01:00
host = new LibretroHost ( ) ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void retro_deinit ( void )
{
2021-09-06 20:10:13 +01:00
g_threadManager . Teardown ( ) ;
2020-07-13 21:11:26 +02:00
LogManager : : Shutdown ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
delete printfLogger ;
printfLogger = nullptr ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
delete host ;
host = nullptr ;
2020-07-13 19:13:18 +02:00
libretro_supports_bitmasks = false ;
2021-12-05 17:31:36 +01:00
2022-05-16 16:25:56 +01:00
VsyncSwapIntervalReset ( ) ;
2021-12-05 17:31:36 +01:00
AudioBufferDeinit ( ) ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void retro_set_controller_port_device ( unsigned port , unsigned device )
{
2018-03-24 12:44:53 +01:00
( void ) port ;
( void ) device ;
}
2020-07-13 21:11:26 +02:00
void retro_get_system_info ( struct retro_system_info * info )
{
* info = { } ;
info - > library_name = " PPSSPP " ;
info - > library_version = PPSSPP_GIT_VERSION ;
info - > need_fullpath = true ;
info - > valid_extensions = " elf|iso|cso|prx|pbp " ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void retro_get_system_av_info ( struct retro_system_av_info * info )
{
* info = { } ;
2022-05-16 16:25:56 +01:00
info - > timing . fps = ( 60.0 / 1.001 ) / ( double ) vsyncSwapInterval ;
2020-07-13 21:11:26 +02:00
info - > timing . sample_rate = SAMPLERATE ;
2021-08-17 01:13:24 +02:00
info - > geometry . base_width = g_Config . iInternalResolution * 480 ;
info - > geometry . base_height = g_Config . iInternalResolution * 272 ;
2020-07-13 21:11:26 +02:00
info - > geometry . max_width = g_Config . iInternalResolution * 480 ;
info - > geometry . max_height = g_Config . iInternalResolution * 272 ;
2020-10-11 20:26:39 +02:00
info - > geometry . aspect_ratio = 480.0 / 272.0 ; // Not 16:9! But very, very close.
2018-03-24 12:44:53 +01:00
}
unsigned retro_api_version ( void ) { return RETRO_API_VERSION ; }
2020-07-13 21:11:26 +02:00
namespace Libretro
{
bool useEmuThread = false ;
std : : atomic < EmuThreadState > emuThreadState ( EmuThreadState : : DISABLED ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
static std : : thread emuThread ;
static void EmuFrame ( )
{
ctx - > SetRenderTarget ( ) ;
if ( ctx - > GetDrawContext ( ) )
ctx - > GetDrawContext ( ) - > BeginFrame ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
gpu - > BeginHostFrame ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
coreState = CORE_RUNNING ;
PSP_RunLoopUntil ( UINT64_MAX ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
gpu - > EndHostFrame ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( ctx - > GetDrawContext ( ) )
ctx - > GetDrawContext ( ) - > EndFrame ( ) ;
}
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
static void EmuThreadFunc ( )
{
2020-12-01 00:46:26 +01:00
SetCurrentThreadName ( " Emu " ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
for ( ; ; )
{
switch ( ( EmuThreadState ) emuThreadState )
{
case EmuThreadState : : START_REQUESTED :
emuThreadState = EmuThreadState : : RUNNING ;
/* fallthrough */
case EmuThreadState : : RUNNING :
EmuFrame ( ) ;
break ;
case EmuThreadState : : PAUSE_REQUESTED :
emuThreadState = EmuThreadState : : PAUSED ;
/* fallthrough */
case EmuThreadState : : PAUSED :
sleep_ms ( 1 ) ;
break ;
default :
case EmuThreadState : : QUIT_REQUESTED :
emuThreadState = EmuThreadState : : STOPPED ;
ctx - > StopThread ( ) ;
return ;
}
}
}
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
void EmuThreadStart ( )
{
bool wasPaused = emuThreadState = = EmuThreadState : : PAUSED ;
emuThreadState = EmuThreadState : : START_REQUESTED ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( ! wasPaused )
{
ctx - > ThreadStart ( ) ;
emuThread = std : : thread ( & EmuThreadFunc ) ;
}
}
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
void EmuThreadStop ( )
{
if ( emuThreadState ! = EmuThreadState : : RUNNING )
return ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
emuThreadState = EmuThreadState : : QUIT_REQUESTED ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
// Need to keep eating frames to allow the EmuThread to exit correctly.
while ( ctx - > ThreadFrame ( ) )
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
emuThread . join ( ) ;
emuThread = std : : thread ( ) ;
ctx - > ThreadEnd ( ) ;
}
void EmuThreadPause ( )
{
if ( emuThreadState ! = EmuThreadState : : RUNNING )
return ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
emuThreadState = EmuThreadState : : PAUSE_REQUESTED ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
ctx - > ThreadFrame ( ) ; // Eat 1 frame
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
while ( emuThreadState ! = EmuThreadState : : PAUSED )
sleep_ms ( 1 ) ;
}
2018-03-24 12:44:53 +01:00
2018-03-26 17:37:34 +01:00
} // namespace Libretro
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
bool retro_load_game ( const struct retro_game_info * game )
{
2021-09-06 20:10:13 +01:00
retro_pixel_format fmt = retro_pixel_format : : RETRO_PIXEL_FORMAT_XRGB8888 ;
2020-07-13 21:11:26 +02:00
if ( ! environ_cb ( RETRO_ENVIRONMENT_SET_PIXEL_FORMAT , & fmt ) )
{
ERROR_LOG ( SYSTEM , " XRGB8888 is not supported. \n " ) ;
return false ;
}
coreState = CORE_POWERUP ;
ctx = LibretroGraphicsContext : : CreateGraphicsContext ( ) ;
INFO_LOG ( SYSTEM , " Using %s backend " , ctx - > Ident ( ) ) ;
Core_SetGraphicsContext ( ctx ) ;
SetGPUBackend ( ( GPUBackend ) g_Config . iGPUBackend ) ;
useEmuThread = ctx - > GetGPUCore ( ) = = GPUCORE_GLES ;
CoreParameter coreParam = { } ;
coreParam . enableSound = true ;
2021-05-09 15:25:12 +02:00
coreParam . fileToStart = Path ( std : : string ( game - > path ) ) ;
2021-05-09 17:24:04 -07:00
coreParam . mountIso . clear ( ) ;
2020-07-13 21:11:26 +02:00
coreParam . startBreak = false ;
coreParam . printfEmuLog = true ;
coreParam . headLess = true ;
coreParam . graphicsContext = ctx ;
coreParam . gpuCore = ctx - > GetGPUCore ( ) ;
2021-09-06 20:10:13 +01:00
coreParam . cpuCore = ( CPUCore ) g_Config . iCpuCore ;
2020-07-13 21:11:26 +02:00
check_variables ( coreParam ) ;
2018-03-24 12:44:53 +01:00
2021-09-06 20:10:13 +01:00
std : : string error_string ;
2020-07-13 21:11:26 +02:00
if ( ! PSP_InitStart ( coreParam , & error_string ) )
{
ERROR_LOG ( BOOT , " %s " , error_string . c_str ( ) ) ;
return false ;
}
2018-03-24 12:44:53 +01:00
2022-05-13 16:48:06 +02:00
set_variable_visibility ( ) ;
2020-07-13 21:11:26 +02:00
return true ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void retro_unload_game ( void )
{
if ( Libretro : : useEmuThread )
2018-03-24 12:44:53 +01:00
Libretro : : EmuThreadStop ( ) ;
PSP_Shutdown ( ) ;
VFSShutdown ( ) ;
delete ctx ;
ctx = nullptr ;
PSP_CoreParameter ( ) . graphicsContext = nullptr ;
}
2020-07-13 21:11:26 +02:00
void retro_reset ( void )
{
std : : string error_string ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
PSP_Shutdown ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( ! PSP_Init ( PSP_CoreParameter ( ) , & error_string ) )
{
ERROR_LOG ( BOOT , " %s " , error_string . c_str ( ) ) ;
environ_cb ( RETRO_ENVIRONMENT_SHUTDOWN , nullptr ) ;
}
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
static void retro_input ( void )
{
2020-07-13 19:13:18 +02:00
unsigned i ;
int16_t ret = 0 ;
2020-07-13 21:11:26 +02:00
// clang-format off
static struct
2020-07-13 19:13:18 +02:00
{
2020-07-13 21:11:26 +02:00
u32 retro ;
u32 sceCtrl ;
} map [ ] = {
{ RETRO_DEVICE_ID_JOYPAD_UP , CTRL_UP } ,
{ RETRO_DEVICE_ID_JOYPAD_DOWN , CTRL_DOWN } ,
{ RETRO_DEVICE_ID_JOYPAD_LEFT , CTRL_LEFT } ,
{ RETRO_DEVICE_ID_JOYPAD_RIGHT , CTRL_RIGHT } ,
{ RETRO_DEVICE_ID_JOYPAD_X , CTRL_TRIANGLE } ,
{ RETRO_DEVICE_ID_JOYPAD_A , CTRL_CIRCLE } ,
{ RETRO_DEVICE_ID_JOYPAD_B , CTRL_CROSS } ,
{ RETRO_DEVICE_ID_JOYPAD_Y , CTRL_SQUARE } ,
{ RETRO_DEVICE_ID_JOYPAD_L , CTRL_LTRIGGER } ,
{ RETRO_DEVICE_ID_JOYPAD_R , CTRL_RTRIGGER } ,
{ RETRO_DEVICE_ID_JOYPAD_START , CTRL_START } ,
{ RETRO_DEVICE_ID_JOYPAD_SELECT , CTRL_SELECT } ,
} ;
// clang-format on
input_poll_cb ( ) ;
if ( libretro_supports_bitmasks )
ret = input_state_cb ( 0 , RETRO_DEVICE_JOYPAD ,
0 , RETRO_DEVICE_ID_JOYPAD_MASK ) ;
2020-07-13 19:13:18 +02:00
else
{
for ( i = RETRO_DEVICE_ID_JOYPAD_B ; i < = RETRO_DEVICE_ID_JOYPAD_R ; i + + )
if ( input_state_cb ( 0 , RETRO_DEVICE_JOYPAD , 0 , i ) )
ret | = ( 1 < < i ) ;
}
2020-07-13 21:11:26 +02:00
for ( i = 0 ; i < sizeof ( map ) / sizeof ( * map ) ; i + + )
2020-07-13 19:13:18 +02:00
{
2021-09-06 20:10:13 +01:00
bool pressed = ret & ( 1 < < map [ i ] . retro ) ;
2020-07-13 19:13:18 +02:00
2020-07-13 21:11:26 +02:00
if ( pressed )
2020-07-13 19:13:18 +02:00
{
2020-07-13 21:11:26 +02:00
__CtrlButtonDown ( map [ i ] . sceCtrl ) ;
}
2020-07-13 19:13:18 +02:00
else
{
2020-07-13 21:11:26 +02:00
__CtrlButtonUp ( map [ i ] . sceCtrl ) ;
}
}
2021-07-09 10:41:26 +02:00
float x_left = input_state_cb ( 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_LEFT , RETRO_DEVICE_ID_ANALOG_X ) / 32767.0f ;
float y_left = input_state_cb ( 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_LEFT , RETRO_DEVICE_ID_ANALOG_Y ) / - 32767.0f ;
float x_right = input_state_cb ( 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_RIGHT , RETRO_DEVICE_ID_ANALOG_X ) / 32767.0f ;
float y_right = input_state_cb ( 0 , RETRO_DEVICE_ANALOG , RETRO_DEVICE_INDEX_ANALOG_RIGHT , RETRO_DEVICE_ID_ANALOG_Y ) / - 32767.0f ;
__CtrlSetAnalogXY ( CTRL_STICK_LEFT , x_left , y_left ) ;
__CtrlSetAnalogXY ( CTRL_STICK_RIGHT , x_right , y_right ) ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void retro_run ( void )
{
if ( PSP_IsIniting ( ) )
{
std : : string error_string ;
while ( ! PSP_InitUpdate ( & error_string ) )
sleep_ms ( 4 ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( ! PSP_IsInited ( ) )
{
ERROR_LOG ( BOOT , " %s " , error_string . c_str ( ) ) ;
environ_cb ( RETRO_ENVIRONMENT_SHUTDOWN , nullptr ) ;
return ;
}
}
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
check_variables ( PSP_CoreParameter ( ) ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
retro_input ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( useEmuThread )
{
2021-08-09 17:16:30 -04:00
if ( emuThreadState = = EmuThreadState : : PAUSED | |
2020-07-13 21:11:26 +02:00
emuThreadState = = EmuThreadState : : PAUSE_REQUESTED )
{
2022-05-16 16:25:56 +01:00
VsyncSwapIntervalDetect ( ) ;
2021-12-05 17:31:36 +01:00
AudioUploadSamples ( ) ;
2020-07-13 21:11:26 +02:00
ctx - > SwapBuffers ( ) ;
return ;
}
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
if ( emuThreadState ! = EmuThreadState : : RUNNING )
EmuThreadStart ( ) ;
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
if ( ! ctx - > ThreadFrame ( ) )
2021-12-05 17:31:36 +01:00
{
2022-05-16 16:25:56 +01:00
VsyncSwapIntervalDetect ( ) ;
2021-12-05 17:31:36 +01:00
AudioUploadSamples ( ) ;
2020-07-13 21:11:26 +02:00
return ;
2021-12-05 17:31:36 +01:00
}
2020-07-13 21:11:26 +02:00
}
else
EmuFrame ( ) ;
2018-03-24 12:44:53 +01:00
2022-05-16 16:25:56 +01:00
VsyncSwapIntervalDetect ( ) ;
2021-12-05 17:31:36 +01:00
AudioUploadSamples ( ) ;
2020-07-13 21:11:26 +02:00
ctx - > SwapBuffers ( ) ;
2018-03-24 12:44:53 +01:00
}
unsigned retro_get_region ( void ) { return RETRO_REGION_NTSC ; }
2020-07-13 21:11:26 +02:00
bool retro_load_game_special ( unsigned type , const struct retro_game_info * info , size_t num ) { return false ; }
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
namespace SaveState
{
struct SaveStart
{
void DoState ( PointerWrap & p ) ;
} ;
2018-03-26 17:37:34 +01:00
} // namespace SaveState
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
size_t retro_serialize_size ( void )
{
2021-08-09 17:16:30 -04:00
if ( ! gpu ) { // The HW renderer isn't ready on first pass.
return 134217728 ; // 128MB ought to be enough for anybody.
}
2020-07-13 21:11:26 +02:00
SaveState : : SaveStart state ;
// TODO: Libretro API extension to use the savestate queue
if ( useEmuThread )
EmuThreadPause ( ) ;
2019-04-23 17:35:24 +02:00
2021-08-09 17:16:30 -04:00
return ( CChunkFileReader : : MeasurePtr ( state ) + 0x800000 )
2020-07-13 21:11:26 +02:00
& ~ 0x7FFFFF ; // We don't unpause intentionally
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
bool retro_serialize ( void * data , size_t size )
{
2021-08-09 17:16:30 -04:00
if ( ! gpu ) { // The HW renderer isn't ready on first pass.
return false ;
}
2020-07-13 21:11:26 +02:00
bool retVal ;
SaveState : : SaveStart state ;
// TODO: Libretro API extension to use the savestate queue
if ( useEmuThread )
EmuThreadPause ( ) ; // Does nothing if already paused
2020-01-06 01:04:07 +08:00
2021-08-07 13:55:29 -07:00
size_t measured = CChunkFileReader : : MeasurePtr ( state ) ;
assert ( measured < = size ) ;
auto err = CChunkFileReader : : SavePtr ( ( u8 * ) data , state , measured ) ;
retVal = err = = CChunkFileReader : : ERROR_NONE ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
if ( useEmuThread )
{
EmuThreadStart ( ) ;
sleep_ms ( 4 ) ;
}
2020-01-06 01:04:07 +08:00
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
2020-07-13 21:11:26 +02:00
return retVal ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
bool retro_unserialize ( const void * data , size_t size )
{
bool retVal ;
SaveState : : SaveStart state ;
// TODO: Libretro API extension to use the savestate queue
if ( useEmuThread )
EmuThreadPause ( ) ; // Does nothing if already paused
2019-04-23 17:35:24 +02:00
2020-08-02 17:54:03 +02:00
std : : string errorString ;
2021-08-09 17:16:30 -04:00
retVal = CChunkFileReader : : LoadPtr ( ( u8 * ) data , state , & errorString )
2020-07-13 21:11:26 +02:00
= = CChunkFileReader : : ERROR_NONE ;
2019-04-23 17:35:24 +02:00
2020-07-13 21:11:26 +02:00
if ( useEmuThread )
{
EmuThreadStart ( ) ;
sleep_ms ( 4 ) ;
}
2019-04-23 17:35:24 +02:00
2021-12-05 17:31:36 +01:00
AudioBufferFlush ( ) ;
2020-07-13 21:11:26 +02:00
return retVal ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
void * retro_get_memory_data ( unsigned id )
{
if ( id = = RETRO_MEMORY_SYSTEM_RAM )
return Memory : : GetPointerUnchecked ( PSP_GetKernelMemoryBase ( ) ) ;
return NULL ;
2018-03-24 12:44:53 +01:00
}
2020-07-13 21:11:26 +02:00
size_t retro_get_memory_size ( unsigned id )
{
if ( id = = RETRO_MEMORY_SYSTEM_RAM )
2018-07-31 23:57:10 -04:00
return Memory : : g_MemorySize ;
2018-03-24 12:44:53 +01:00
return 0 ;
}
void retro_cheat_reset ( void ) { }
2020-07-13 21:11:26 +02:00
void retro_cheat_set ( unsigned index , bool enabled , const char * code ) { }
2018-03-24 12:44:53 +01:00
2020-07-13 21:11:26 +02:00
int System_GetPropertyInt ( SystemProperty prop )
{
switch ( prop )
{
case SYSPROP_AUDIO_SAMPLE_RATE :
return SAMPLERATE ;
2020-08-03 19:04:40 +02:00
# if PPSSPP_PLATFORM(ANDROID)
case SYSPROP_SYSTEMVERSION : {
char sdk [ PROP_VALUE_MAX ] = { 0 } ;
if ( __system_property_get ( " ro.build.version.sdk " , sdk ) ! = 0 ) {
return atoi ( sdk ) ;
}
return - 1 ;
}
# endif
2020-07-13 21:11:26 +02:00
default :
break ;
}
return - 1 ;
2020-01-06 01:04:07 +08:00
}
2020-07-13 21:11:26 +02:00
float System_GetPropertyFloat ( SystemProperty prop )
{
switch ( prop )
{
case SYSPROP_DISPLAY_REFRESH_RATE :
2022-05-16 16:25:56 +01:00
// Have to lie here and report 60 Hz instead
// of (60.0 / 1.001), otherwise the internal
// stereo resampler will output at the wrong
// frequency...
return 60.0f ;
2020-10-14 23:34:01 +01:00
case SYSPROP_DISPLAY_SAFE_INSET_LEFT :
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT :
case SYSPROP_DISPLAY_SAFE_INSET_TOP :
case SYSPROP_DISPLAY_SAFE_INSET_BOTTOM :
return 0.0f ;
2020-07-13 21:11:26 +02:00
default :
break ;
}
return - 1 ;
2018-03-24 12:44:53 +01:00
}
2021-04-26 23:45:03 -07:00
bool System_GetPropertyBool ( SystemProperty prop )
{
switch ( prop )
{
case SYSPROP_CAN_JIT :
return true ;
default :
return false ;
}
}
2018-03-24 12:44:53 +01:00
std : : string System_GetProperty ( SystemProperty prop ) { return " " ; }
2021-01-06 16:37:04 +01:00
std : : vector < std : : string > System_GetPropertyStringVec ( SystemProperty prop ) { return std : : vector < std : : string > ( ) ; }
2018-03-24 12:44:53 +01:00
void System_SendMessage ( const char * command , const char * parameter ) { }
void NativeUpdate ( ) { }
void NativeRender ( GraphicsContext * graphicsContext ) { }
void NativeResized ( ) { }
2020-02-05 11:51:47 -06:00
# if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
std : : vector < std : : string > __cameraGetDeviceList ( ) { return std : : vector < std : : string > ( ) ; }
2020-10-24 13:36:24 +03:00
bool audioRecording_Available ( ) { return false ; }
bool audioRecording_State ( ) { return false ; }
2020-04-03 09:57:54 -05:00
2020-07-13 21:11:26 +02:00
void System_InputBoxGetString ( const std : : string & title , const std : : string & defaultValue , std : : function < void ( bool , const std : : string & ) > cb ) { cb ( false , " " ) ; }
2020-02-05 11:51:47 -06:00
# endif