diff --git a/dynamic.c b/dynamic.c index 729a2f45b5..e3cfb19f31 100644 --- a/dynamic.c +++ b/dynamic.c @@ -927,6 +927,32 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_SET_GEOMETRY: + { + RARCH_LOG("Environ SET_GEOMETRY.\n"); + const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data; + struct retro_game_geometry *geom = &g_extern.system.av_info.geometry; + + // Can potentially be called every frame, don't do anything unless required. + if (geom->base_width != in_geom->base_width || + geom->base_height != in_geom->base_height || + geom->aspect_ratio != in_geom->aspect_ratio) + { + geom->base_width = in_geom->base_width; + geom->base_height = in_geom->base_height; + geom->aspect_ratio = in_geom->aspect_ratio; + RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", + geom->base_width, geom->base_height, geom->aspect_ratio); + + // Forces recomputation of aspect ratios if using core-dependent aspect ratios. + if (driver.video_poke && driver.video_poke->set_aspect_ratio && driver.video_data) + driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx); + + // TODO: Figure out what to do, if anything, with recording. + } + break; + } + // Private extensions for internal use, not part of libretro API. case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH: RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n"); diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index 040374884a..d2db96d1a7 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -310,6 +310,7 @@ static void check_variables(void) float last_rate = last_sample_rate; struct retro_system_av_info info; retro_get_system_av_info(&info); + if ((last != last_aspect && last != 0.0f) || (last_rate != last_sample_rate && last_rate != 0.0f)) { // SET_SYSTEM_AV_INFO can only be called within retro_run(). @@ -317,8 +318,12 @@ static void check_variables(void) // on last and last_rate ensures this path is never hit that early. // last_aspect and last_sample_rate are not updated until retro_get_system_av_info(), // which must come after retro_load_game(). - bool ret = environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info); - logging.log(RETRO_LOG_INFO, "SET_SYSTEM_AV_INFO = %u.\n", ret); + bool ret; + if (last_rate != last_sample_rate && last_rate != 0.0f) // If audio rate changes, go through SET_SYSTEM_AV_INFO. + ret = environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &info); + else // If only aspect changed, take the simpler path. + ret = environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry); + logging.log(RETRO_LOG_INFO, "SET_SYSTEM_AV_INFO/SET_GEOMETRY = %u.\n", ret); } } diff --git a/libretro.h b/libretro.h index 59a0e1df3c..d132fb101a 100755 --- a/libretro.h +++ b/libretro.h @@ -591,8 +591,8 @@ enum retro_mod // avoid setting the "worst case" in max_width/max_height. // // ***HIGHLY RECOMMENDED*** Do not call this callback every time resolution changes in an emulator core if it's - // expected to be a temporary change, for the reasons of possible driver reinit. - // This call is not a free pass for not trying to provide correct values in retro_get_system_av_info(). + // expected to be a temporary change, for the reasons of possible driver reinitialization. + // This call is not a free pass for not trying to provide correct values in retro_get_system_av_info(). If you need to change things like aspect ratio or nominal width/height, use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant of SET_SYSTEM_AV_INFO. // // If this returns false, the frontend does not acknowledge a changed av_info struct. #define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 @@ -645,6 +645,23 @@ enum retro_mod // // Can be called from retro_init and retro_load_game. // +#define RETRO_ENVIRONMENT_SET_GEOMETRY 37 + // const struct retro_game_geometry * -- + // This environment call is similar to SET_SYSTEM_AV_INFO for changing video parameters, + // but provides a guarantee that drivers will not be reinitialized. + // This can only be called from within retro_run(). + // + // The purpose of this call is to allow a core to alter nominal width/heights as well as aspect ratios on-the-fly, + // which can be useful for some emulators to change in run-time. + // + // max_width/max_height arguments are ignored and cannot be changed + // with this call as this could potentially require a reinitialization or a non-constant time operation. + // If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. + // + // A frontend must guarantee that this environment call completes in constant time. + + + #define RETRO_MEMDESC_CONST (1 << 0) // The frontend will never change this memory area once retro_load_game has returned. #define RETRO_MEMDESC_BIGENDIAN (1 << 1) // The memory area contains big endian data. Default is little endian.