Unverified Commit bf71b55b authored by Libretro-Admin's avatar Libretro-Admin Committed by GitHub
Browse files

Merge pull request #25 from jdgleaver/frameskip

Add optional frameskipping
parents 09800e41 b83c03b8
Pipeline #42746 passed with stages
in 8 minutes and 50 seconds
......@@ -1314,8 +1314,7 @@ void myGraphicsBlitLine(unsigned char render) /* NOTA */
{
/* start VBlank period */
tlcsMemWriteB(0x00008010,tlcsMemReadB(0x00008010) | 0x40);
if (render)
graphics_paint();
graphics_paint(render);
}
*scanlineY+= 1;
}
......
......@@ -60,7 +60,7 @@ extern unsigned short *oowTable;
extern unsigned char *color_switch;
BOOL graphics_init(void);
void graphics_paint(void);
void graphics_paint(unsigned char render);
void graphicsSetDarkFilterLevel(unsigned filterLevel);
/* new renderer (NeoGeo Pocket (Color)) */
void myGraphicsBlitLine(unsigned char render);
......
......@@ -36,13 +36,79 @@ static retro_input_state_t input_state_cb;
#define FB_WIDTH 160
#define FB_HEIGHT 152
/* Frameskipping Support */
static unsigned frameskip_type = 0;
static unsigned frameskip_threshold = 0;
static uint16_t frameskip_counter = 0;
static bool retro_audio_buff_active = false;
static unsigned retro_audio_buff_occupancy = 0;
static bool retro_audio_buff_underrun = false;
/* Maximum number of consecutive frames that
* can be skipped */
#define FRAMESKIP_MAX 60
static unsigned audio_latency = 0;
static bool update_audio_latency = false;
static void retro_audio_buff_status_cb(
bool active, unsigned occupancy, bool underrun_likely)
{
retro_audio_buff_active = active;
retro_audio_buff_occupancy = occupancy;
retro_audio_buff_underrun = underrun_likely;
}
static void init_frameskip(void)
{
if (frameskip_type > 0)
{
struct retro_audio_buffer_status_callback buf_status_cb;
buf_status_cb.callback = retro_audio_buff_status_cb;
if (!environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK,
&buf_status_cb))
{
if (log_cb)
log_cb(RETRO_LOG_WARN, "Frameskip disabled - frontend does not support audio buffer status monitoring.\n");
retro_audio_buff_active = false;
retro_audio_buff_occupancy = 0;
retro_audio_buff_underrun = false;
audio_latency = 0;
}
else
{
/* Frameskip is enabled - increase frontend
* audio latency to minimise potential
* buffer underruns */
float frame_time_msec = 1000.0f / (float)RACE_TIMING_FPS;
/* Set latency to 6x current frame time... */
audio_latency = (unsigned)((6.0f * frame_time_msec) + 0.5f);
/* ...then round up to nearest multiple of 32 */
audio_latency = (audio_latency + 0x1F) & ~0x1F;
}
}
else
{
environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL);
audio_latency = 0;
}
update_audio_latency = true;
}
/* core options */
static int RETRO_SAMPLE_RATE = 44100;
struct ngp_screen* screen;
int setting_ngp_language; /* 0x6F87 - language */
int gfx_hacks;
int tipo_consola; /* 0x6F91 - OS version */
int gfx_hacks = 0;
int tipo_consola = 0; /* 0x6F91 - OS version */
static bool libretro_supports_input_bitmasks;
char retro_save_directory[2048];
......@@ -68,29 +134,34 @@ unsigned retro_api_version(void)
return RETRO_API_VERSION;
}
void graphics_paint(void)
void graphics_paint(unsigned char render)
{
video_cb(screen->pixels, screen->w, screen->h, FB_WIDTH << 1);
video_cb((bool)render ? screen->pixels : NULL,
screen->w, screen->h, FB_WIDTH << 1);
}
static void check_variables(void)
static void check_variables(bool first_run)
{
struct retro_variable var = {0};
unsigned dark_filter_level = 0;
unsigned old_frameskip_type;
var.key = "race_language";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
if (first_run)
{
/* user must manually restart core for change to happen
* > 0: English
* > 1: Japanese
*/
if (!strcmp(var.value, "japanese"))
setting_ngp_language = 1;
else if (!strcmp(var.value, "english"))
setting_ngp_language = 0;
var.key = "race_language";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
/* user must manually restart core for change to happen
* > 0: English
* > 1: Japanese
*/
if (!strcmp(var.value, "japanese"))
setting_ngp_language = 1;
else if (!strcmp(var.value, "english"))
setting_ngp_language = 0;
}
}
var.key = "race_dark_filter_level";
......@@ -99,12 +170,46 @@ static void check_variables(void)
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
dark_filter_level = (unsigned)(atoi(var.value));
graphicsSetDarkFilterLevel(dark_filter_level);
old_frameskip_type = frameskip_type;
frameskip_type = 0;
var.key = "race_frameskip";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (!strcmp(var.value, "auto"))
frameskip_type = 1;
else if (!strcmp(var.value, "manual"))
frameskip_type = 2;
}
frameskip_threshold = 33;
var.key = "race_frameskip_threshold";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
frameskip_threshold = strtol(var.value, NULL, 10);
/* Reinitialise frameskipping, if required */
if ((frameskip_type != old_frameskip_type) && !first_run)
init_frameskip();
}
void retro_init(void)
{
char *dir = NULL;
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
frameskip_type = 0;
frameskip_threshold = 0;
frameskip_counter = 0;
retro_audio_buff_active = false;
retro_audio_buff_occupancy = 0;
retro_audio_buff_underrun = false;
audio_latency = 0;
update_audio_latency = false;
/* set up some logging */
init_log(environ_cb);
......@@ -114,8 +219,6 @@ void retro_init(void)
if (log_cb)
log_cb(RETRO_LOG_INFO, "[RACE]: Save directory: %s.\n", retro_save_directory);
check_variables();
if(!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt) && log_cb)
log_cb(RETRO_LOG_ERROR, "[could not set RGB565]\n");
......@@ -268,10 +371,48 @@ void retro_run(void)
static int16_t stereoBuffer[2048];
int16_t *p = NULL;
uint16_t samplesPerFrame;
int skipFrame = 0;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
check_variables(false);
race_input();
tlcs_execute(CPU_FREQ / HOST_FPS);
/* Check whether current frame should be skipped */
if ((frameskip_type > 0) && retro_audio_buff_active)
{
switch (frameskip_type)
{
case 1: /* auto */
skipFrame = retro_audio_buff_underrun ? 1 : 0;
break;
case 2: /* manual */
skipFrame = (retro_audio_buff_occupancy < frameskip_threshold) ? 1 : 0;
break;
default:
skipFrame = 0;
break;
}
if (!skipFrame || (frameskip_counter >= FRAMESKIP_MAX))
{
skipFrame = 0;
frameskip_counter = 0;
}
else
frameskip_counter++;
}
/* If frameskip settings have changed, update
* frontend audio latency */
if (update_audio_latency)
{
environ_cb(RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY,
&audio_latency);
update_audio_latency = false;
}
tlcs_execute(CPU_FREQ / HOST_FPS, skipFrame);
/* Get the number of samples in a frame */
samplesPerFrame = RETRO_SAMPLE_RATE / HOST_FPS;
......@@ -291,10 +432,6 @@ void retro_run(void)
}
audio_batch_cb(stereoBuffer, samplesPerFrame);
/* TODO/FIXME - shouldn't we check this at the top of this function? */
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
check_variables();
}
size_t retro_serialize_size(void)
......@@ -386,6 +523,9 @@ bool retro_load_game(const struct retro_game_info *info)
return false;
}
check_variables(true);
init_frameskip();
if (!race_initialize_system(content_path,
content_data, content_size))
return false;
......@@ -393,8 +533,6 @@ bool retro_load_game(const struct retro_game_info *info)
if (!race_initialize_sound())
return false;
check_variables();
{
/* TODO: Mappings might need updating
* Size is based on what is exposed in Mednafen NGP */
......
......@@ -51,7 +51,7 @@ extern "C" {
struct retro_core_option_definition option_defs_us[] = {
{
"race_language",
"Language",
"Language (Restart)",
"Specify which language to display when running content with dual language support.",
{
{ "japanese", "Japanese" },
......@@ -80,6 +80,43 @@ struct retro_core_option_definition option_defs_us[] = {
},
"0"
},
{
"race_frameskip",
"Frameskip",
"Skip frames to avoid audio buffer under-run (crackling). Improves performance at the expense of visual smoothness. 'Auto' skips frames when advised by the frontend. 'Manual' utilises the 'Frameskip Threshold (%)' setting.",
{
{ "disabled", NULL },
{ "auto", "Auto" },
{ "manual", "Manual" },
{ NULL, NULL },
},
"disabled"
},
{
"race_frameskip_threshold",
"Frameskip Threshold (%)",
"When 'Frameskip' is set to 'Manual', specifies the audio buffer occupancy threshold (percentage) below which frames will be skipped. Higher values reduce the risk of crackling by causing frames to be dropped more frequently.",
{
{ "15", NULL },
{ "18", NULL },
{ "21", NULL },
{ "24", NULL },
{ "27", NULL },
{ "30", NULL },
{ "33", NULL },
{ "36", NULL },
{ "39", NULL },
{ "42", NULL },
{ "45", NULL },
{ "48", NULL },
{ "51", NULL },
{ "54", NULL },
{ "57", NULL },
{ "60", NULL },
{ NULL, NULL },
},
"33"
},
{ NULL, NULL, NULL, {{0}}, NULL },
};
......
......@@ -8410,21 +8410,7 @@ static int tlcs_step(void)
extern unsigned char *ngpScY;
int ngOverflow = 0;
#define FRAME_RATE_LIMIT //should we limit the framerate or let it run wild?
#define FRAMESKIP //undef this to do no FRAME skipping
#ifdef FRAMESKIP
//#define AUTO_FRAMESKIP
//#define FIXED_FRAMESKIP 1
//#define MAX_SKIPFRAMES 2
#endif
#ifdef __LIBRETRO__
#define FIXED_FRAMESKIP 0
int frame=FIXED_FRAMESKIP;
#endif
#ifdef AUTO_FRAMESKIP
void tlcs_execute(int cycles, int skipFrames)// skipFrames=how many frames to skip for each frame rendered
#else
void tlcs_execute(int cycles)
......@@ -8434,12 +8420,7 @@ void tlcs_execute(int cycles)
int hCounter = ngOverflow;
#ifdef FRAMESKIP
#ifdef FIXED_FRAMESKIP
// static int frame=FIXED_FRAMESKIP;
#else
static int frame=1;
#endif
int frame = skipFrames;
#endif
while(cycles > 0)
......@@ -8499,19 +8480,12 @@ void tlcs_execute(int cycles)
if (tlcsMemReadB(0x8000)&0x80)
tlcs_interrupt(2);
#ifdef FRAMESKIP
#ifdef FIXED_FRAMESKIP
if(frame == 0)
frame = FIXED_FRAMESKIP;
#else
if(frame == 0)
{
frame = skipFrames;
SDL_Rect numRect = drawNumber(skipFrames, 10, 24);
//SDL_Rect numRect = drawNumber(skipFrames, 10, 24);
//SDL_UpdateRect(screen, numRect.x, numRect.y, numRect.w, numRect.h);
}
#endif
else
frame--;
#endif
......@@ -8533,13 +8507,13 @@ void tlcs_execute(int cycles)
//Flavor, this auto-frameskip code is messed up
void ngpc_run(void)
{
#ifdef AUTO_FRAMESKIP
#ifdef FRAMESKIP
unsigned int skipFrames=0;
#endif /* AUTO_FRAMESKIP */
#endif /* FRAMESKIP */
while(m_bIsActive) //should be some way to exit
{
#ifdef AUTO_FRAMESKIP
#ifdef FRAMESKIP
tlcs_execute((6*1024*1024) / HOST_FPS, skipFrames);
#else
tlcs_execute((6*1024*1024) / HOST_FPS);
......
......@@ -16,6 +16,8 @@
extern "C" {
#endif
#define FRAMESKIP //undef this to do no FRAME skipping
extern unsigned char *rasterY;
extern unsigned int gen_regsPC, gen_regsSR;
extern unsigned char F2;
......@@ -60,7 +62,7 @@ void tlcs_reinit(void);
/* execute interrupt */
void tlcs_interrupt_wrapper(int irq);
void ngpc_run(void);
#ifdef AUTO_FRAMESKIP
#ifdef FRAMESKIP
void tlcs_execute(int cycles, int skipFrames); /* skipFrames=how many frames to skip for each frame rendered */
#else
void tlcs_execute(int cycles);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment