video_driver: extract cached-frame state to file-scope statics

Follow-up to the cached-frame redesign series (934dcf5..2d9af0d).
After the API migration landed, no TU outside gfx/video_driver.c
referenced frame_cache_data / frame_cache_width /
frame_cache_height / frame_cache_pitch -- the privacy was
enforced by convention.  This commit makes it structural: the
four fields move out of video_driver_state_t and become
file-scope statics in video_driver.c.

Effect:
  - The fields cannot be referenced from another TU even by
    accident, since they're not in the struct anymore and they're
    static.  Future code can't reintroduce the pre-redesign UAF
    pattern by typo.
  - sizeof(video_driver_state_t) shrinks by 24 bytes on 64-bit
    (one pointer + one size_t + two unsigned).  Only one instance
    exists, so the size win is symbolic; the readability win is
    the point.
  - All internal video_driver.c sites that previously did
    video_st->frame_cache_* now do bare frame_cache_*.  Identical
    semantics; the lock-and-callback contract on cached_frame_read
    / publish / invalidate is unchanged.

Stale comments in command.c (the reinit snapshot block) updated
to reference the publish API instead of the no-longer-existing
field.  A residual mention of 'frame_cache_data' in runloop.c
and gfx/drivers/d3d12.c is comment-only and accurate as a
description of the cached frame's role.

Compile-checked: gfx/video_driver.c plus every consumer file
that touched the old fields (runloop.c, retroarch.c, command.c,
tasks/task_*.c, cheevos/cheevos.c) all build clean against the
extracted statics.
This commit is contained in:
libretroadmin authored and U-DESKTOP-SPFP6AQ\twistedtechre committed 2026-05-20 05:51:58 +02:00
1 parent 2d9af0dcc8
commit a7ccc0438a
3 files changed
+63 -54

No files matched your search

+20 -18
View File
@@ -2578,27 +2578,29 @@ void command_event_reinit(const int flags)
*sec_joypad = NULL;
#endif
/* Snapshot the last cached core frame before tearing the video
* driver down. video_driver_free() nulls frame_cache_data as part
* of the reinit cycle (the pointer was borrowed from the core's
* own framebuffer and isn't guaranteed to stay live across the
* driver swap), so without a snapshot the new driver would come
* up with no core image to replay. Restored + replayed below so
* the paused-core background remains visible when reinit is
* triggered from inside the menu (e.g. HDR mode toggle).
* driver down. video_driver_free() invalidates the cache as
* part of the reinit cycle (the pointer was borrowed from the
* core's own framebuffer and isn't guaranteed to stay live
* across the driver swap), so without a snapshot the new
* driver would come up with no core image to replay. Restored
* + replayed below so the paused-core background remains
* visible when reinit is triggered from inside the menu (e.g.
* HDR mode toggle).
*
* The snapshot buffer is static and reused across reinits — we
* need it to outlive command_event_reinit because we hand the
* pointer to video_st->frame_cache_data for the new driver to
* read via video_driver_cached_frame(), and the core's next real
* frame will replace the pointer at its leisure. Resizing in
* place on each call keeps it bounded at one buffer's worth.
* need it to outlive command_event_reinit because we publish
* the pointer back through video_driver_cached_frame_publish
* for the new driver to read via video_driver_cached_frame(),
* and the core's next real frame will replace the pointer at
* its leisure. Resizing in place on each call keeps it
* bounded at one buffer's worth.
*
* The actual copy happens inside the cached_frame_read callback
* (which is what this function was hand-rolling before the
* unified read API existed -- exactly the same pattern,
* lifted into one place). HW-render frames are skipped: the
* callback receives data == NULL for those, so we don't even
* allocate. */
* The actual copy happens inside the cached_frame_read
* callback (which is what this function was hand-rolling
* before the unified read API existed -- exactly the same
* pattern, lifted into one place). HW-render frames are
* skipped: the callback receives data == NULL for those, so
* we don't even allocate. */
static void *cached_snapshot = NULL;
static size_t cached_snapshot_cap = 0;
unsigned cached_snapshot_w = 0;
+43 -31
View File
@@ -492,6 +492,18 @@ static video_driver_state_t video_driver_st = { 0 };
static const video_display_server_t *current_display_server =
&dispserv_null;
/* Cached-frame state. Private to this TU; all access goes through
* video_driver_cached_frame_{info,read,is_hw_render,publish,
* invalidate} (any-thread, locked) or the same-thread
* video_driver_cached_frame() replay path. Extracted from
* video_driver_state_t after the API migration landed so the
* privacy is structural (file-scope static) rather than
* convention (struct field accessed only through helpers). */
static const void *frame_cache_data = NULL;
static unsigned frame_cache_width = 0;
static unsigned frame_cache_height = 0;
static size_t frame_cache_pitch = 0;
struct retro_hw_render_callback *video_driver_get_hw_context(void)
{
video_driver_state_t *video_st = &video_driver_st;
@@ -2462,8 +2474,8 @@ static void video_viewport_get_scaled_integer(
int padding_y = 0;
float vp_bias_x = settings->floats.video_vp_bias_x;
float vp_bias_y = settings->floats.video_vp_bias_y;
unsigned content_width = video_st->frame_cache_width;
unsigned content_height = video_st->frame_cache_height;
unsigned content_width = frame_cache_width;
unsigned content_height = frame_cache_height;
#if defined(RARCH_MOBILE)
if (width < height)
{
@@ -2611,8 +2623,8 @@ static void video_viewport_get_scaled_integer(
/* Reset width to exact width */
content_width = (rotation % 2)
? ((video_st->frame_cache_height <= 4) ? video_st->av_info.geometry.base_height : video_st->frame_cache_height)
: ((video_st->frame_cache_width <= 4) ? video_st->av_info.geometry.base_width : video_st->frame_cache_width);
? ((frame_cache_height <= 4) ? video_st->av_info.geometry.base_height : frame_cache_height)
: ((frame_cache_width <= 4) ? video_st->av_info.geometry.base_width : frame_cache_width);
overscale_w = (width / content_width) + !!(width % content_width);
@@ -3206,12 +3218,12 @@ void video_driver_cached_frame(void)
if (runloop_st->current_core.flags & RETRO_CORE_FLAG_INITED)
cbs->frame_cb(
(video_st->frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID)
? video_st->frame_cache_data
(frame_cache_data != RETRO_HW_FRAME_BUFFER_VALID)
? frame_cache_data
: NULL,
video_st->frame_cache_width,
video_st->frame_cache_height,
video_st->frame_cache_pitch);
frame_cache_width,
frame_cache_height,
frame_cache_pitch);
recording_st->data = recording;
}
@@ -3266,14 +3278,14 @@ bool video_driver_cached_frame_info(
bool has_frame;
cached_frame_lock_acquire();
data = video_st->frame_cache_data;
data = frame_cache_data;
has_frame = (data != NULL);
if (has_frame)
{
if (width) *width = video_st->frame_cache_width;
if (height) *height = video_st->frame_cache_height;
if (pitch) *pitch = video_st->frame_cache_pitch;
if (width) *width = frame_cache_width;
if (height) *height = frame_cache_height;
if (pitch) *pitch = frame_cache_pitch;
if (has_cpu_pixels) *has_cpu_pixels =
(data != RETRO_HW_FRAME_BUFFER_VALID);
}
@@ -3315,13 +3327,13 @@ void video_driver_cached_frame_read(
* guarantee the redesign introduces: the pointer handed to the
* callback cannot be freed out from under it. */
cached_frame_lock_acquire();
data = video_st->frame_cache_data;
data = frame_cache_data;
hw_or_empty = (!data || data == RETRO_HW_FRAME_BUFFER_VALID);
if (!hw_or_empty)
{
width = video_st->frame_cache_width;
height = video_st->frame_cache_height;
pitch = video_st->frame_cache_pitch;
width = frame_cache_width;
height = frame_cache_height;
pitch = frame_cache_pitch;
}
/* Hand the callback NULL when no CPU pixels are available, so
@@ -3337,8 +3349,8 @@ bool video_driver_cached_frame_is_hw_render(void)
video_driver_state_t *video_st = &video_driver_st;
bool is_hw;
cached_frame_lock_acquire();
is_hw = video_st->frame_cache_data
&& video_st->frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID;
is_hw = frame_cache_data
&& frame_cache_data == RETRO_HW_FRAME_BUFFER_VALID;
cached_frame_lock_release();
return is_hw;
}
@@ -3355,10 +3367,10 @@ void video_driver_cached_frame_publish(
video_driver_state_t *video_st = &video_driver_st;
cached_frame_lock_acquire();
if (data)
video_st->frame_cache_data = data;
video_st->frame_cache_width = width;
video_st->frame_cache_height = height;
video_st->frame_cache_pitch = pitch;
frame_cache_data = data;
frame_cache_width = width;
frame_cache_height = height;
frame_cache_pitch = pitch;
cached_frame_lock_release();
}
@@ -3373,10 +3385,10 @@ void video_driver_cached_frame_invalidate(void)
{
video_driver_state_t *video_st = &video_driver_st;
cached_frame_lock_acquire();
video_st->frame_cache_data = NULL;
video_st->frame_cache_width = 0;
video_st->frame_cache_height = 0;
video_st->frame_cache_pitch = 0;
frame_cache_data = NULL;
frame_cache_width = 0;
frame_cache_height = 0;
frame_cache_pitch = 0;
cached_frame_lock_release();
}
@@ -4892,8 +4904,8 @@ void video_driver_frame(const void *data, unsigned width,
" Blocking: %6.2f %%\n"
" Samples: %8d\n"
,
video_st->frame_cache_width,
video_st->frame_cache_height,
frame_cache_width,
frame_cache_height,
av_info->geometry.base_width,
av_info->geometry.base_height,
av_info->geometry.max_width,
@@ -4907,9 +4919,9 @@ void video_driver_frame(const void *data, unsigned width,
video_info.scale_width,
video_info.scale_height,
(float)video_info.scale_width / ((rotation % 2)
? (float)video_st->frame_cache_height : (float)video_st->frame_cache_width),
? (float)frame_cache_height : (float)frame_cache_width),
(float)video_info.scale_height / ((rotation % 2)
? (float)video_st->frame_cache_width : (float)video_st->frame_cache_height),
? (float)frame_cache_width : (float)frame_cache_height),
video_info.refresh_rate,
last_fps,
frame_time / 1000.0f,
-5
View File
@@ -829,8 +829,6 @@ typedef struct
void *current_display_server_data;
const void *frame_cache_data;
const struct
retro_hw_render_context_negotiation_interface *
hw_render_context_negotiation;
@@ -849,7 +847,6 @@ typedef struct
uintptr_t display;
uintptr_t window;
size_t frame_cache_pitch;
size_t window_title_len;
uint32_t flags;
@@ -858,8 +855,6 @@ typedef struct
unsigned state_scale;
unsigned state_out_bpp;
#endif
unsigned frame_cache_width;
unsigned frame_cache_height;
unsigned width;
unsigned height;
unsigned scale_width;