[Scummvm-git-logs] scummvm master -> e43f6b69530b7ebee999577585d3d1027c0b4d4c

spleen1981 noreply at scummvm.org
Wed Mar 15 09:26:22 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
e43f6b6953 LIBRETRO: add frameskip options


Commit: e43f6b69530b7ebee999577585d3d1027c0b4d4c
    https://github.com/scummvm/scummvm/commit/e43f6b69530b7ebee999577585d3d1027c0b4d4c
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2023-03-15T10:06:48+01:00

Commit Message:
LIBRETRO: add frameskip options

Changed paths:
    backends/platform/libretro/include/libretro-core-options-intl.h
    backends/platform/libretro/include/libretro-core-options.h
    backends/platform/libretro/include/os.h
    backends/platform/libretro/src/libretro.cpp


diff --git a/backends/platform/libretro/include/libretro-core-options-intl.h b/backends/platform/libretro/include/libretro-core-options-intl.h
index 8c0e86dfbea..17eb258c04f 100644
--- a/backends/platform/libretro/include/libretro-core-options-intl.h
+++ b/backends/platform/libretro/include/libretro-core-options-intl.h
@@ -75,6 +75,11 @@ struct retro_core_option_v2_category option_cats_it[] = {
 		"Movimento del cursore",
 		"Impostazioni relative al movimento del cursore"
 	},
+	{
+		"frameskip",
+		"Salto dei fotogrammi",
+		"Impostazioni per il salto dei fotogrammi"
+	},
 	{ NULL, NULL, NULL },
 };
 
@@ -141,6 +146,52 @@ struct retro_core_option_v2_definition option_defs_it[] = {
 		},
 		NULL
 	},
+	{
+		"scummvm_frameskip_type",
+		"Salto dei fotogrammi",
+		NULL,
+		"Salto dei fotogrammi per evitare buffer under-run audio (crackling). Migliora le prestazioni a discapito della fluidità video. 'Auto' salta i fotogrammi su indicazione del frontend, 'Manuale' usa l'impostazione di 'Soglia minima buffer audio (%)', 'Fisso' usa l'impostazione 'Salto dei fotogrammi fisso'.",
+		NULL,
+		"frameskip",
+		{
+			{ "disabled", NULL },
+			{ "fixed", "Fisso" },
+			{ "auto", "Auto" },
+			{ "manual", "Manuale" },
+			{ NULL, NULL },
+		},
+		NULL
+	},
+	{
+		"scummvm_frameskip_threshold",
+		"Soglia minima buffer audio (%)",
+		NULL,
+		"Quando 'Salto dei fotogrammi' è impostato su 'Manuale', specifica la soglia minima del buffer audio al di sotto della quale il fotogramma viene saltato. Valori più alti riducono il rischio di crackling al costo di un salto di fotogrammi più frequente.",
+		NULL,
+		"frameskip",
+		{
+			{ NULL, NULL },
+		},
+		NULL
+	},
+	{
+		"scummvm_frameskip_no",
+		"Salto dei fotogrammi fisso",
+		NULL,
+		"Quando la modalità di 'Salto dei fotogrammi' è 'Fisso', o il frontend non supporta una delle altre modalità selezionate, salta costantemente X fotogrammi ogni X+1.",
+		NULL,
+		"frameskip",
+		{
+			{ "0", "Nessun fotogramma saltato" },
+			{ "1", "Salto di 1 fotogramma su 2" },
+			{ "2", "Salto di 2 fotogrammi su 3" },
+			{ "3", "Salto di 3 fotogrammi su 4" },
+			{ "4", "Salto di 4 fotogrammi su 5" },
+			{ "5", "Salto di 5 fotogrammi su 6" },
+			{ NULL, NULL },
+		},
+		NULL
+	},
 	{
 		"scummvm_speed_hack",
 		"Speed Hack (riavvio necessario)",
diff --git a/backends/platform/libretro/include/libretro-core-options.h b/backends/platform/libretro/include/libretro-core-options.h
index aebd1bdf11b..eb7ed09d181 100644
--- a/backends/platform/libretro/include/libretro-core-options.h
+++ b/backends/platform/libretro/include/libretro-core-options.h
@@ -77,6 +77,11 @@ struct retro_core_option_v2_category option_cats_us[] = {
 		"Cursor Movement",
 		"Configure cursor movement settings"
 	},
+	{
+		"frameskip",
+		"Frameskip",
+		"Configure frameskip settings"
+	},
 	{ NULL, NULL, NULL },
 };
 
@@ -190,6 +195,68 @@ struct retro_core_option_v2_definition option_defs_us[] = {
 		},
 		"1.0"
 	},
+	{
+		"scummvm_frameskip_type",
+		"Frameskip Mode",
+		NULL,
+		"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' uses the 'Frameskip Threshold (%)' setting. 'Fixed' uses the 'Fixed Frameskip' setting.",
+		NULL,
+		"frameskip",
+		{
+			{ "disabled", NULL },
+			{ "fixed", "Fixed" },
+			{ "auto", "Auto" },
+			{ "manual", "Manual" },
+			{ NULL, NULL },
+		},
+		"auto"
+	},
+	{
+		"scummvm_frameskip_threshold",
+		"Frameskip Threshold (%)",
+		NULL,
+		"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.",
+		NULL,
+		"frameskip",
+		{
+			{ "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"
+	},
+	{
+		"scummvm_frameskip_no",
+		"Fixed Frameskip",
+		NULL,
+		"When 'Frameskip' is set to 'Fixed', or if the frontend doesn't support the alternative 'Frameskip' mode, skip rendering at a fixed rate of X frames out of X+1",
+		NULL,
+		"frameskip",
+		{
+			{ "0", "No skipping" },
+			{ "1", "Skip rendering of 1 frames out of 2" },
+			{ "2", "Skip rendering of 2 frames out of 3" },
+			{ "3", "Skip rendering of 3 frames out of 4" },
+			{ "4", "Skip rendering of 4 frames out of 5" },
+			{ "5", "Skip rendering of 5 frames out of 6" },
+			{ NULL, NULL },
+		},
+		"0"
+	},
 	{
 		"scummvm_speed_hack",
 		"Speed Hack (Restart)",
diff --git a/backends/platform/libretro/include/os.h b/backends/platform/libretro/include/os.h
index 4712f3f5579..df245d1447c 100644
--- a/backends/platform/libretro/include/os.h
+++ b/backends/platform/libretro/include/os.h
@@ -24,6 +24,14 @@
 
 #define SAMPLE_RATE     48000
 #define REFRESH_RATE    60
+#define FRAMESKIP_MAX   30
+
+// Audio status
+#define AUDIO_STATUS_MUTE               (1 << 0)
+#define AUDIO_STATUS_BUFFER_SUPPORT     (1 << 1)
+#define AUDIO_STATUS_BUFFER_ACTIVE      (1 << 2)
+#define AUDIO_STATUS_BUFFER_UNDERRUN    (1 << 3)
+#define AUDIO_STATUS_UPDATE_LATENCY     (1 << 4)
 
 // Preliminary scan results
 #define TEST_GAME_OK_TARGET_FOUND        0
diff --git a/backends/platform/libretro/src/libretro.cpp b/backends/platform/libretro/src/libretro.cpp
index 7fd4b42b589..01bd09a3f6f 100644
--- a/backends/platform/libretro/src/libretro.cpp
+++ b/backends/platform/libretro/src/libretro.cpp
@@ -80,13 +80,16 @@ char cmd_params_num;
 int adjusted_RES_W = 0;
 int adjusted_RES_H = 0;
 
-static uint32 audio_latency = 0;
-static bool audio_buffer_status_support = false;
-static bool mute=true;
+static uint32 current_frame = 0;
+static uint8 frameskip_no;
+static uint8 frameskip_type;
+static uint8 frameskip_threshold;
+static uint32 frameskip_counter = 0;
+
+static bool can_dupe = false;
+static uint8 audio_status = 0;
 
-static bool retro_audio_buff_active = false;
 static unsigned retro_audio_buff_occupancy = 0;
-static bool retro_audio_buff_underrun = false;
 
 static uint16 fps = 0;
 static uint16 sound_len = 0;                // length in samples per frame
@@ -106,6 +109,32 @@ static void audio_buffer_init(uint16 sample_rate, uint16 frame_rate) {
 		memset(sound_buffer, 0, sound_size);
 	else
 		log_cb(RETRO_LOG_ERROR, "audio_buffer_init error.\n");
+
+	audio_status |= AUDIO_STATUS_UPDATE_LATENCY;
+}
+
+static void retro_audio_buff_status_cb(bool active, unsigned occupancy, bool underrun_likely) {
+	if (active)
+		audio_status |= AUDIO_STATUS_BUFFER_ACTIVE;
+	else
+		audio_status &= ~AUDIO_STATUS_BUFFER_ACTIVE;
+
+	if (underrun_likely)
+		audio_status |= AUDIO_STATUS_BUFFER_UNDERRUN;
+	else
+		audio_status &= ~AUDIO_STATUS_BUFFER_UNDERRUN;
+
+	retro_audio_buff_occupancy = occupancy;
+}
+
+static void set_audio_buffer_status(){
+	if (frameskip_type > 1) {
+		struct retro_audio_buffer_status_callback buf_status_cb;
+		buf_status_cb.callback = retro_audio_buff_status_cb;
+		audio_status = environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, &buf_status_cb) ? (audio_status | AUDIO_STATUS_BUFFER_SUPPORT) : (audio_status & ~AUDIO_STATUS_BUFFER_SUPPORT);
+	} else {
+		audio_status = environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL) ? (audio_status | AUDIO_STATUS_BUFFER_SUPPORT) : (audio_status & ~AUDIO_STATUS_BUFFER_SUPPORT);
+	}
 }
 
 static void update_variables(void) {
@@ -154,6 +183,36 @@ static void update_variables(void) {
 		if (strcmp(var.value, "enabled") == 0)
 			speed_hack_is_enabled = true;
 	}
+
+	var.key = "scummvm_frameskip_threshold";
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+		frameskip_threshold = (uint8)strtol(var.value, NULL, 10);
+
+	var.key = "scummvm_frameskip_no";
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+	{
+		frameskip_no = (uint8)strtol(var.value, NULL, 10) + 1;
+	}
+
+	uint8 old_frameskip_type = frameskip_type;
+	var.key = "scummvm_frameskip_type";
+	var.value = NULL;
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+	{
+		if (strcmp(var.value, "disabled") == 0)
+			frameskip_type = 0;
+		else if (strcmp(var.value, "fixed") == 0)
+			frameskip_type = 1;
+		else if (strcmp(var.value, "auto") == 0)
+			frameskip_type = 2;
+		else if (strcmp(var.value, "manual") == 0)
+			frameskip_type = 3;
+	}
+
+	if (old_frameskip_type != frameskip_type){
+		set_audio_buffer_status();
+		audio_status |= AUDIO_STATUS_UPDATE_LATENCY;
+	}
 }
 
 void parse_command_params(char *cmdline) {
@@ -309,8 +368,11 @@ void retro_init(void) {
 	else
 		log_cb = NULL;
 
+	audio_buffer_init(SAMPLE_RATE, REFRESH_RATE);
 	update_variables();
 
+	environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
+
 	cmd_params_num = 1;
 	strcpy(cmd_params[0], "scummvm\0");
 
@@ -377,11 +439,6 @@ void retro_init(void) {
 		retroSetSaveDir(".");
 	}
 
-	// Check RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK support
-	audio_buffer_status_support = environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL);
-
-	audio_buffer_init(SAMPLE_RATE, REFRESH_RATE);
-
 	g_system = retroBuildOS(speed_hack_is_enabled);
 }
 
@@ -517,6 +574,7 @@ bool retro_load_game_special(unsigned game_type, const struct retro_game_info *i
 }
 
 void retro_run(void) {
+
 	if (retro_emu_thread_exited())
 		retro_deinit_emu_thread();
 
@@ -525,51 +583,92 @@ void retro_run(void) {
 		return;
 	}
 
-	// Setting RA's video or audio driver to null will disable video/audio bits,
+	/* Setting RA's video or audio driver to null will disable video/audio bits */
 	int audio_video_enable = 0;
 	environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &audio_video_enable);
 
+	bool skip_frame = false;
 	retro_switch_to_emu_thread();
-	/* Mouse */
+
 	if (g_system) {
 		poll_cb();
 		retroProcessMouse(input_cb, retro_device, gampad_cursor_speed, gamepad_acceleration_time, analog_response_is_quadratic, analog_deadzone, mouse_speed);
 
+		if (frameskip_type && can_dupe) {
+			if (audio_status & (AUDIO_STATUS_BUFFER_SUPPORT | AUDIO_STATUS_BUFFER_ACTIVE)){
+				switch (frameskip_type) {
+				case 1:
+					skip_frame = !(current_frame % frameskip_no == 0);
+					break;
+				case 2:
+					skip_frame = (audio_status & AUDIO_STATUS_BUFFER_UNDERRUN);
+					break;
+				case 3:
+					skip_frame = (retro_audio_buff_occupancy < frameskip_threshold);
+					break;
+				}
+			} else
+				skip_frame = !(current_frame % frameskip_no == 0);
+		}
+		/* Upload audio */
+		size_t count = 0;
+		if (audio_video_enable & 2) {
+			count = ((Audio::MixerImpl *)g_system->getMixer())->mixCallback((byte *)sound_buffer, sound_size);
+		}
+		audio_status = count ? (audio_status & ~AUDIO_STATUS_MUTE) : (audio_status | AUDIO_STATUS_MUTE);
+
+		/* No frame skipping if there is no incoming audio (e.g. GUI) */
+		skip_frame = skip_frame && ! (audio_status & AUDIO_STATUS_MUTE);
 
+		if ((!skip_frame && frameskip_counter) || frameskip_counter >= FRAMESKIP_MAX) {
+			if (frameskip_counter)
+				log_cb(RETRO_LOG_WARN, "%d frame(s) skipped\n",frameskip_counter);
+			skip_frame        = false;
+			frameskip_counter = 0;
+		} else if (skip_frame)
+			frameskip_counter++;
 
-		/* Upload video: TODO: Check the CANDUPE env value */
-		if (audio_video_enable & 1) {
+		if ((audio_video_enable & 1) && !skip_frame) {
 			const Graphics::Surface &screen = getScreen();
 			video_cb(screen.getPixels(), screen.w, screen.h, screen.pitch);
 		} else {
-			//check if it's the same avoiding the call to video_cb at all
 			video_cb(NULL, 0, 0, 0); // Set to NULL to skip frame rendering
 		}
 
-		/* Upload audio */
-		size_t count = 0;
-		if (audio_video_enable & 2) {
-			count = ((Audio::MixerImpl *)g_system->getMixer())->mixCallback((byte *)sound_buffer, sound_size);
-		}
-		mute = count ? false : true;
 #if defined(_3DS)
 		/* Hack: 3DS will produce static noise
 		 * unless we manually send a zeroed
 		 * audio buffer when no samples are
 		 * available (i.e. when the overlay
 		 * is shown) */
-		if (mute) {
+		if (audio_status & AUDIO_STATUS_MUTE) {
 			audio_buffer_init(SAMPLE_RATE, REFRESH_RATE);
 		}
 #endif
-		audio_batch_cb(mute ? NULL : sound_buffer, count); // Set to NULL to skip sound rendering
+		audio_batch_cb((audio_status & AUDIO_STATUS_MUTE) ? NULL : sound_buffer, count); // Set to NULL to skip sound rendering
 
+		current_frame++;
 	}
 
 	bool updated = false;
-	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) {
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated){
 		update_variables();
 	}
+
+	if (audio_status & AUDIO_STATUS_UPDATE_LATENCY){
+		uint32 audio_latency;
+		if (frameskip_type > 1) {
+			float frame_time_msec = 100000.0f / fps;
+
+			audio_latency = (uint32)((8.0f * frame_time_msec) + 0.5f);
+			audio_latency = (audio_latency + 0x1F) & ~0x1F;
+		} else {
+			audio_latency = 0;
+		}
+		/* This can only be called from within retro_run() */
+		environ_cb(RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY, &audio_latency);
+		audio_status &= ~AUDIO_STATUS_UPDATE_LATENCY;
+	}
 }
 
 void retro_unload_game(void) {




More information about the Scummvm-git-logs mailing list