(Widgets) Recompute the derived metrics when a font is rebuilt

7eddfc2 gave the menu drivers this through font_flush(), and noted
that widgets were not covered: they keep their own font struct and
call renderer->flush directly, so they never reach that hook. Same
problem, so the same treatment.

gfx_widget_font_data_t carries the generation the metrics were worked
out at, and gfx_widgets_font_sync() redoes them when it has moved.
The computation is not duplicated to get there - the block that
gfx_widgets_font_init() already ran is what became the sync, so init
and refresh cannot drift apart.

The sync runs before the usage_count check rather than after, so a
widget that drew nothing this frame still lays out correctly on the
next one. Cheap either way: an integer compare when nothing changed.

xmb is still not covered, and its exposure is narrower than it looked
- it caches wideglyph_width and nothing else derived from the face, so
a rebuild leaves word wrapping stale rather than the whole layout. It
holds raw font_data_t pointers and has no impl struct to hang a
generation off, which is why it is left for its own change.

Also fixes samples/gfx/gfx_widgets_sanitize, which this broke:
gfx_widgets.c now calls font_driver_get_generation() and the sample
stubs the font driver out. Stubbed to a constant, since the fonts
there never change underneath. Sample passes again - 392 pushes, 310
frames, clean.
This commit is contained in:
W authored and libretroadmin committed 2026-08-08 18:59:42 +02:00
1 parent 8bc46ff400
commit 41bcd2aa7b
3 files changed
+42 -3

No files matched your search

+31 -3
View File
@@ -843,7 +843,16 @@ void gfx_widgets_flush_text(
{
/* Flushing is slow - only do it if font
* has actually been used */
if (!font_data || (font_data->usage_count == 0))
if (!font_data)
return;
/* A rebuilt font has different metrics; pick them up before
* anything is drawn with the old ones. Done here rather than only
* when there is something to flush, so a widget that drew nothing
* this frame still lays out correctly on the next. */
gfx_widgets_font_sync(font_data);
if (font_data->usage_count == 0)
return;
if (font_data->font && font_data->font->renderer && font_data->font->renderer->flush)
@@ -950,6 +959,27 @@ static void gfx_widgets_font_init(
* no implicit font to fall back on any more, so the approximate
* glyph width set above has to stand on its own. */
if (font_data->font)
gfx_widgets_font_sync(font_data);
font_data->usage_count = 0;
}
/* Recompute the derived metrics if the font has been rebuilt since
* they were last worked out. Cheap when nothing has changed. The menu
* drivers get this from font_flush() via font_driver_sync_impl(), but
* widgets keep their own font struct and flush directly. */
void gfx_widgets_font_sync(gfx_widget_font_data_t *font_data)
{
int glyph_width;
uint32_t gen = font_driver_get_generation();
if (!font_data || !font_data->font)
return;
if (font_data->metrics_generation == gen)
return;
font_data->metrics_generation = gen;
{
glyph_width = font_driver_get_message_width(
font_data->font, "a", 1, 1.0f);
@@ -962,8 +992,6 @@ static void gfx_widgets_font_init(
font_data->line_centre_offset = roundf((font_data->font->metrics.ascender
- font_data->font->metrics.descender) * 0.5f);
}
font_data->usage_count = 0;
}
static void gfx_widgets_layout(
+6
View File
@@ -152,8 +152,14 @@ typedef struct
float line_ascender;
float line_descender;
float line_centre_offset;
/* font_driver generation the values above were computed at. A font
* rebuilt underneath - a language switch picks a different face -
* moves the generation and they are worked out again. */
uint32_t metrics_generation;
} gfx_widget_font_data_t;
void gfx_widgets_font_sync(gfx_widget_font_data_t *font_data);
/* Font data */
typedef struct
{
@@ -97,6 +97,11 @@ int font_driver_get_message_width(void *font_data, const char *msg,
return (int)(len * 10 * (scale > 0.0f ? scale : 1.0f));
}
/* Bumped by the real font_driver when a font is freed or rebuilt;
* gfx_widgets_font_sync() watches it. Constant here: the stub fonts
* never change underneath. */
uint32_t font_driver_get_generation(void) { return 1; }
void font_driver_bind_block(void *font_data, void *block)
{ (void)font_data; (void)block; }
void font_driver_free(font_data_t *font) { (void)font; }