Skip to content

Commit 0f6a3e2

Browse files
committed
gfx/gl1: reuse menu frame and POT buffers across set_texture_frame calls
gl1_set_texture_frame unconditionally free'd menu_frame and set it to NULL before a subsequent size-comparison check, making the "only reallocate if size changed" branch dead. Every menu frame triggered a full free+malloc+memcpy round-trip on menu_frame. Because GL1_FLAG_MENU_SIZE_CHANGED was also set unconditionally on every successful call, the downstream frame path in gl1_frame additionally reallocated the POT-sized menu_video_buf every single frame — so the bug was compounded: two per-frame allocations, not one. The inner 'if (gl1->menu_frame) free(gl1->menu_frame);' at the top of the allocation branch was also unreachable dead code (menu_frame had just been set to NULL directly above it). Replace with a cached-capacity realloc pattern for menu_frame, and gate GL1_FLAG_MENU_SIZE_CHANGED on actual dimension changes rather than setting it on every call. menu_video_buf is now correctly reused between frames when the menu dimensions don't change. On realloc failure the previous frame is kept intact (the original free+malloc sequence would have lost it). A transient NULL window that existed between the free and malloc is also closed. Thread-safety: set_texture_frame and the frame read-site both run on the video thread (threaded video) or main thread (non-threaded), sequentially within the same loop iteration. No synchronization required, none added. gl1_t is calloc'd at init and the entire struct is freed on teardown, so the new menu_frame_cap field starts at zero on every re-init — no explicit reset needed in gl1_free. With this commit the full cluster of drivers sharing the broken set_texture_frame pattern (caca, fpga, sixel, network, gdi, vga, gl1) is fixed.
1 parent e7bb95f commit 0f6a3e2

1 file changed

Lines changed: 29 additions & 32 deletions

File tree

gfx/drivers/gl1.c

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ typedef struct gl1
131131
unsigned char *menu_frame;
132132
unsigned char *video_buf;
133133
unsigned char *menu_video_buf;
134+
size_t menu_frame_cap;
134135

135136
int version_major;
136137
int version_minor;
@@ -2011,51 +2012,47 @@ static void gl1_set_texture_frame(void *data,
20112012
{
20122013
settings_t *settings = config_get_ptr();
20132014
bool menu_linear_filter = settings->bools.menu_linear_filter;
2014-
unsigned pitch = width * 2;
2015+
unsigned pitch = width * (rgb32 ? 4 : 2);
20152016
gl1_t *gl1 = (gl1_t*)data;
2017+
size_t required;
20162018

2017-
if (!gl1)
2019+
if (!gl1 || !frame || !width || !height || !pitch)
20182020
return;
20192021

20202022
if (menu_linear_filter)
20212023
gl1->flags |= GL1_FLAG_MENU_SMOOTH;
20222024
else
20232025
gl1->flags &= ~GL1_FLAG_MENU_SMOOTH;
20242026

2025-
if (rgb32)
2026-
pitch = width * 4;
2027-
2028-
if (gl1->menu_frame)
2029-
free(gl1->menu_frame);
2030-
gl1->menu_frame = NULL;
2027+
required = (size_t)pitch * (size_t)height;
20312028

2032-
if ( (!gl1->menu_frame)
2033-
|| (gl1->menu_width != width)
2034-
|| (gl1->menu_height != height)
2035-
|| (gl1->menu_pitch != pitch))
2029+
if (required > gl1->menu_frame_cap)
20362030
{
2037-
if (pitch && height)
2038-
{
2039-
if (gl1->menu_frame)
2040-
free(gl1->menu_frame);
2041-
2042-
/* FIXME? We have to assume the pitch has no
2043-
* extra padding in it because that will
2044-
* mess up the POT calculation when we don't
2045-
* know how many bpp there are. */
2046-
gl1->menu_frame = (unsigned char*)malloc(pitch * height);
2047-
}
2031+
/* FIXME? We have to assume the pitch has no
2032+
* extra padding in it because that will
2033+
* mess up the POT calculation when we don't
2034+
* know how many bpp there are. */
2035+
unsigned char *tmp = (unsigned char*)realloc(
2036+
gl1->menu_frame, required);
2037+
if (!tmp)
2038+
return; /* keep previous frame intact */
2039+
gl1->menu_frame = tmp;
2040+
gl1->menu_frame_cap = required;
20482041
}
20492042

2050-
if (gl1->menu_frame && frame && pitch && height)
2051-
{
2052-
memcpy(gl1->menu_frame, frame, pitch * height);
2053-
gl1->menu_width = width;
2054-
gl1->menu_height = height;
2055-
gl1->menu_pitch = pitch;
2056-
gl1->menu_bits = rgb32 ? 32 : 16;
2057-
gl1->flags |= GL1_FLAG_MENU_SIZE_CHANGED;
2058-
}
2043+
/* Only set MENU_SIZE_CHANGED when the dimensions the downstream
2044+
* frame path cares about actually change; otherwise the POT-sized
2045+
* menu_video_buf would get reallocated on every single frame. */
2046+
if ( gl1->menu_width != width
2047+
|| gl1->menu_height != height
2048+
|| gl1->menu_pitch != pitch)
2049+
gl1->flags |= GL1_FLAG_MENU_SIZE_CHANGED;
2050+
2051+
memcpy(gl1->menu_frame, frame, required);
2052+
gl1->menu_width = width;
2053+
gl1->menu_height = height;
2054+
gl1->menu_pitch = pitch;
2055+
gl1->menu_bits = rgb32 ? 32 : 16;
20592056
}
20602057

20612058
static void gl1_set_video_mode(void *data, unsigned width, unsigned height,

0 commit comments

Comments
 (0)