From 326b3f730b0a665fe84b1d0cb750fc0c2e3db965 Mon Sep 17 00:00:00 2001 From: Maximus32 Date: Fri, 23 Jan 2026 16:25:33 +0100 Subject: [PATCH] Add fps rate limiter --- CMakeLists.txt | 1 + ee/gs/include/gsCore.h | 8 ++++++++ ee/gs/include/gsHires.h | 3 +++ ee/gs/src/gsHires.c | 27 +++++++++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78f566c..57ed2b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,7 @@ add_object_library_macros(GS_HIRES_OBJS ee/gs/src/gsHires.c _gsKit_create_passes gsKit_hires_sync gsKit_hires_flip + gsKit_hires_flip_ext gsKit_hires_prepare_bg gsKit_hires_set_bg gsKit_hires_init_screen diff --git a/ee/gs/include/gsCore.h b/ee/gs/include/gsCore.h index 4a9b0e9..05c9d1f 100644 --- a/ee/gs/include/gsCore.h +++ b/ee/gs/include/gsCore.h @@ -82,6 +82,14 @@ struct gsVertex }; typedef struct gsVertex GSVERTEX; +/// Flip mode for gsKit_hires_flip_ext +typedef enum { + GSFLIP_DIRECT = 0, ///< Flip immediately, no vsync wait + GSFLIP_VSYNC = 1, ///< Wait for vsync before flipping + GSFLIP_RATE_LIMIT_1 = 2, ///< Limit to 60fps (1 vsync per frame) + GSFLIP_RATE_LIMIT_2 = 3 ///< Limit to 30fps (2 vsyncs per frame) +} GSFLIP_MODE; + #ifdef __cplusplus extern "C" { #endif diff --git a/ee/gs/include/gsHires.h b/ee/gs/include/gsHires.h index 9b37b65..507d15b 100644 --- a/ee/gs/include/gsHires.h +++ b/ee/gs/include/gsHires.h @@ -28,6 +28,9 @@ void gsKit_hires_sync(GSGLOBAL *gsGlobal); /// Flips Draw Queue void gsKit_hires_flip(GSGLOBAL *gsGlobal); +/// Flips Draw Queue with specified flip mode +void gsKit_hires_flip_ext(GSGLOBAL *gsGlobal, GSFLIP_MODE mode); + /// Converts PSM and interlacing for use as background image void gsKit_hires_prepare_bg(GSGLOBAL *gsGlobal, GSTEXTURE * tex); diff --git a/ee/gs/src/gsHires.c b/ee/gs/src/gsHires.c index 08e05fb..7256f9c 100644 --- a/ee/gs/src/gsHires.c +++ b/ee/gs/src/gsHires.c @@ -260,8 +260,35 @@ void gsKit_hires_sync(GSGLOBAL *gsGlobal) #if F_gsKit_hires_flip void gsKit_hires_flip(GSGLOBAL *gsGlobal) +{ + gsKit_hires_flip_ext(gsGlobal, GSFLIP_DIRECT); +} +#endif + +#if F_gsKit_hires_flip_ext +// State tracking for rate limiting +static u32 __last_flip_vsync_count = 0; + +void gsKit_hires_flip_ext(GSGLOBAL *gsGlobal, GSFLIP_MODE mode) { u32 iY; + u32 vsync_end; + + // Handle vsync waiting based on mode + switch (mode) { + case GSFLIP_DIRECT: vsync_end = __vsync_count; break; + case GSFLIP_VSYNC: vsync_end = __vsync_count + 1; break; + case GSFLIP_RATE_LIMIT_1: vsync_end = __last_flip_vsync_count + 1; break; + case GSFLIP_RATE_LIMIT_2: vsync_end = __last_flip_vsync_count + 2; break; + } + + // Wait for required vsyncs + while (__vsync_count < vsync_end) { + WaitSema(__sema_vsync_id); + } + + // Update last flip vsync count + __last_flip_vsync_count = __vsync_count; // HACK: The start of the first displayed line // this is needed by the hsync interrupt but must be