mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
(Video) Key the OSD font on the driver instance that owns it
font_driver_init_osd() decided whether to build a font by presence
alone:
if (!video_font_driver && video_info)
which is only correct if every init is preceded by a matching free.
It is not: a reinit can abandon the old driver without its free()
running, and the font then survives holding GPU objects from a device
that is gone, whose handle values the new device recycles. The
converse fails too - a teardown arriving after the next driver is up
takes the live font with it, leaving no OSD text at all.
Record the video driver instance a font was built against, and decide
on ownership rather than presence:
- init_osd() drops a font owned by a different instance before
building the new one, so a skipped teardown cannot strand it
- font_driver_free_osd_for(video_data) frees only if that instance
still owns it, so an out-of-order teardown is a no-op
Both hooks added in the previous commit use the keyed free. The
unconditional font_driver_free_osd() stays for drivers that still
manage their own font, where init and free are adjacent by
construction.
Verified against a harness modelling the real call graph - the init
and free hooks, the wrapper's CMD_INIT/CMD_FREE, and init_osd()'s
guard - over startup, content load, SET_SYSTEM_AV_INFO reinit, a
second reinit, driver switch between a migrated and an unmigrated
driver, threading toggled across a reinit, a reinit that never reaches
free(), and adversarial orderings (init before free, double free,
double init), threaded and unthreaded. The invariant checked after
every step is that a live driver has exactly one live font built
against that same instance, that no font outlives its instance, and
that creations and frees balance. Presence-keyed fails the
skipped-teardown and out-of-order-teardown cases; ownership-keyed
passes all of them.
This commit is contained in:
1 parent
e652f95214
commit
a725f60ce4
4 files changed
+37
-6
No files matched your search
+26
-1
@@ -34,6 +34,11 @@
|
||||
|
||||
/* TODO/FIXME - global */
|
||||
static void *video_font_driver = NULL;
|
||||
/* The video driver instance video_font_driver was built against. A
|
||||
* font holds GPU objects created through that instance and is not
|
||||
* reusable by any other, so ownership - not mere presence - is what
|
||||
* decides whether it can be kept or must be freed. */
|
||||
static void *video_font_driver_owner = NULL;
|
||||
|
||||
/* Monotonic counter incremented whenever any font instance is
|
||||
* freed. Consumers that cache per-font derived data (e.g. the
|
||||
@@ -1120,10 +1125,29 @@ void font_driver_init_osd(
|
||||
bool is_threaded,
|
||||
enum font_driver_render_api api)
|
||||
{
|
||||
/* A font left over from a different instance cannot be adopted:
|
||||
* its images belong to a device that is gone, whose handles the
|
||||
* new one will recycle. Drop it rather than keep it. Guarding on
|
||||
* presence alone is what let a stale font survive a reinit. */
|
||||
if (video_font_driver && video_font_driver_owner != video_data)
|
||||
font_driver_free_osd();
|
||||
|
||||
if (!video_font_driver && video_info)
|
||||
video_font_driver = font_driver_init_first(video_data,
|
||||
*video_info->path_font ? video_info->path_font : NULL,
|
||||
video_info->font_size, threading_hint, is_threaded, api);
|
||||
|
||||
if (video_font_driver)
|
||||
video_font_driver_owner = video_data;
|
||||
}
|
||||
|
||||
void font_driver_free_osd_for(void *video_data)
|
||||
{
|
||||
/* Only the owner may free it. Teardown of an instance that no
|
||||
* longer owns the font - a stale or deferred free - must leave the
|
||||
* live one alone. */
|
||||
if (video_font_driver && video_font_driver_owner == video_data)
|
||||
font_driver_free_osd();
|
||||
}
|
||||
|
||||
void font_driver_free_osd(void)
|
||||
@@ -1131,5 +1155,6 @@ void font_driver_free_osd(void)
|
||||
if (video_font_driver)
|
||||
font_driver_free((font_data_t*)video_font_driver);
|
||||
|
||||
video_font_driver = NULL;
|
||||
video_font_driver = NULL;
|
||||
video_font_driver_owner = NULL;
|
||||
}
|
||||
@@ -149,6 +149,11 @@ void font_driver_init_osd(
|
||||
|
||||
void font_driver_free_osd(void);
|
||||
|
||||
/* Frees the OSD font only if it was built against @video_data. Use
|
||||
* this from any teardown that may run out of order with respect to the
|
||||
* next init. */
|
||||
void font_driver_free_osd_for(void *video_data);
|
||||
|
||||
int font_driver_get_line_height(font_data_t *font, float scale);
|
||||
int font_driver_get_line_ascender(font_data_t *font, float scale);
|
||||
int font_driver_get_line_descender(font_data_t *font, float scale);
|
||||
|
||||
+5
-4
@@ -1978,15 +1978,16 @@ void video_driver_free_internal(void)
|
||||
|
||||
/* Drop the OSD font before the driver that owns its GPU objects
|
||||
* goes away. Only for drivers that have handed the lifecycle up;
|
||||
* the rest still free it inside their own free(). Under threaded
|
||||
* video the wrapper does this from CMD_FREE, on the video thread,
|
||||
* so it must not also happen here. */
|
||||
* the rest still free it inside their own free(). Keyed on
|
||||
* ownership so that a teardown arriving after the next driver is
|
||||
* already up cannot take the live font with it. Under threaded
|
||||
* video the wrapper does this from CMD_FREE, on the video thread. */
|
||||
#ifdef HAVE_THREADS
|
||||
if (!is_threaded)
|
||||
#endif
|
||||
{
|
||||
if (vid && vid->font_api != FONT_DRIVER_RENDER_DONT_CARE)
|
||||
font_driver_free_osd();
|
||||
font_driver_free_osd_for(video_st->data);
|
||||
}
|
||||
|
||||
if (video_st->data && vid && vid->free)
|
||||
|
||||
@@ -222,7 +222,7 @@ static bool video_thread_handle_packet(
|
||||
* against it, and this is the thread they belong to. */
|
||||
if ( thr->driver
|
||||
&& thr->driver->font_api != FONT_DRIVER_RENDER_DONT_CARE)
|
||||
font_driver_free_osd();
|
||||
font_driver_free_osd_for(thr->driver_data);
|
||||
if (thr->driver_data && thr->driver && thr->driver->free)
|
||||
thr->driver->free(thr->driver_data);
|
||||
thr->driver_data = NULL;
|
||||
|
||||
Reference in new issue
Block a user