mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
Overlays: the pixels go after the driver has the textures, not before
With threaded video off, enabling an input overlay showed one oversized blob across the screen or took RetroArch down (reported by sonninnos, bisected to86fbf34e01).86fbf34e01freed the pack's decoded pixels inside input_overlay_upload_textures(), as soon as every image had a handle. The very next loop builds each page's handle list by matching the page's pixel pointers against the unique images' - which had just been set to NULL. No entry matched, the upload released everything and returned false, and input_overlay_load_page() fell back to load() with the pages' own copies of those pointers: freed memory, handed to the driver as images. With threaded video the handles are not there at the poll, the function returns before the free, and the page goes through load() with live pixels, which is why only the unthreaded case showed. There was a second way in. The wrapper's overlay table answers load_textures for any driver, and the one beneath it may have no such path (d3d9, d3d10, gl1, ...): load_textures() returns false after the upload succeeded, and the fallback is load() again - so freeing at the upload leaves that route nothing to read either. The pixels are now released by input_overlay_load_page(), and only once load_textures() has answered true. The pages' copies of the pointers are cleared with them, so nothing is left that looks like an image and is not one. The sizes are kept, as86fbf34e01meant them to be: image_texture_free() zeroes them. A pack left with neither textures nor pixels shows nothing instead of reaching load(), and the cache check in input_overlay_init() becomes input_overlay_has_source(), which also stops a pack with no images at all from being reloaded from its path on every toggle.
This commit is contained in:
1 parent
d5e7337b48
commit
e9468dedf8
3 files changed
+62
-27
No files matched your search
@@ -3609,8 +3609,9 @@ void input_overlay_set_scale_factor(
|
||||
}
|
||||
|
||||
/* The video driver is about to go: every pack's textures, active or
|
||||
* cached, are unloaded while it can still do so. The packs keep their
|
||||
* decoded pixels and upload them again on the next enable. */
|
||||
* cached, are unloaded while it can still do so. A pack whose pixels
|
||||
* went to the driver it is losing has nothing to upload again and is
|
||||
* reloaded from its path (input_overlay_has_source). */
|
||||
void input_overlay_video_teardown(void)
|
||||
{
|
||||
input_overlay_release_textures(input_driver_st.overlay_ptr);
|
||||
@@ -6980,9 +6981,7 @@ void input_overlay_init(void)
|
||||
bool overlay_cached = ol_cache
|
||||
&& (ol_cache->flags & INPUT_OVERLAY_ALIVE)
|
||||
&& string_is_equal(path_overlay, ol_cache->path)
|
||||
&& (ol_cache->page_textures
|
||||
|| (ol_cache->num_images && ol_cache->images
|
||||
&& ol_cache->images[0]->pixels));
|
||||
&& input_overlay_has_source(ol_cache);
|
||||
bool overlay_hidden = !ol && overlay_cached;
|
||||
|
||||
#if defined(GEKKO)
|
||||
|
||||
@@ -534,6 +534,10 @@ void input_overlay_release_textures(input_overlay_t *ol);
|
||||
* call; false when it cannot be uploaded this way. */
|
||||
bool input_overlay_upload_textures(input_overlay_t *ol);
|
||||
|
||||
/* Whether the pack can still be shown: it has its textures, or the
|
||||
* pixels to make them from. */
|
||||
bool input_overlay_has_source(const input_overlay_t *ol);
|
||||
|
||||
/* Hand the active page to the driver: as textures when the driver
|
||||
* takes them, as pixels through load() otherwise. True when it went
|
||||
* as textures. */
|
||||
|
||||
@@ -79,10 +79,8 @@ bool input_overlay_upload_textures(input_overlay_t *ol)
|
||||
|
||||
if (ol->page_textures || !ol->images || !ol->num_images)
|
||||
return ol->page_textures != NULL;
|
||||
/* Nothing to upload from: the pixels went when the textures were
|
||||
* made and the textures went with the driver. The caller declines
|
||||
* the pack, and the next input_overlay_init() reloads it from its
|
||||
* path. */
|
||||
/* Nothing to upload from: the pixels went once the driver had the
|
||||
* textures, and the textures went with the driver. */
|
||||
if (!ol->images[0]->pixels)
|
||||
return false;
|
||||
|
||||
@@ -165,24 +163,6 @@ bool input_overlay_upload_textures(input_overlay_t *ol)
|
||||
tex[i] = s->handle;
|
||||
}
|
||||
|
||||
/* The pixels have reached the GPU and nothing reads them again: a
|
||||
* pack is anything from a megabyte of button sprites to forty of
|
||||
* 4K border, held for the whole session against the one event that
|
||||
* would want them - a video reinit, which reloads the overlay from
|
||||
* its path anyway (video_driver_init_internal) and stalls far
|
||||
* longer than the decode does. The width and height stay, because
|
||||
* the layout and the reload check read them. */
|
||||
for (i = 0; i < ol->num_images; i++)
|
||||
{
|
||||
if (!ol->images[i]->pixels)
|
||||
continue;
|
||||
GFX_INSTR_ADD(GFX_INSTR_OVERLAY_PIXEL_KIB,
|
||||
-(int)(((size_t)ol->images[i]->width * ol->images[i]->height
|
||||
* sizeof(uint32_t)) >> 10));
|
||||
image_texture_free(ol->images[i]);
|
||||
ol->images[i]->pixels = NULL;
|
||||
}
|
||||
|
||||
/* The loader deduplicated by path, so a page's entry shares its
|
||||
* pixels with exactly one unique image. */
|
||||
k = ol->num_images;
|
||||
@@ -211,6 +191,52 @@ bool input_overlay_upload_textures(input_overlay_t *ol)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool input_overlay_has_source(const input_overlay_t *ol)
|
||||
{
|
||||
/* A pack of hitboxes alone has nothing to lose. */
|
||||
if (!ol->num_images || !ol->images)
|
||||
return true;
|
||||
return ol->page_textures || ol->images[0]->pixels;
|
||||
}
|
||||
|
||||
/* The driver has the pack's textures and nothing reads the pixels
|
||||
* again: a pack is anything from a megabyte of button sprites to forty
|
||||
* of 4K border, held for the whole session against the one event that
|
||||
* would want them - a video reinit, which reloads the overlay from
|
||||
* its path anyway (video_driver_init_internal).
|
||||
*
|
||||
* Only here, after load_textures() has answered true. The page lists
|
||||
* are built by matching each page's pixels to a unique image's, so
|
||||
* the pixels must outlive input_overlay_upload_textures(); and a
|
||||
* driver that declines the textures is shown the pages through
|
||||
* load(), which reads them.
|
||||
*
|
||||
* The sizes stay (image_texture_free() clears them), and the pages'
|
||||
* copies of the pointers are cleared with the pixels they pointed at:
|
||||
* nothing is left that looks like an image and is not one. The copies
|
||||
* in overlay::image and overlay_desc::image are only ever tested, as
|
||||
* "this has an image", and are left to say so. */
|
||||
static void input_overlay_drop_pixels(input_overlay_t *ol)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < ol->num_images; i++)
|
||||
{
|
||||
unsigned width = ol->images[i]->width;
|
||||
unsigned height = ol->images[i]->height;
|
||||
if (!ol->images[i]->pixels)
|
||||
continue;
|
||||
GFX_INSTR_ADD(GFX_INSTR_OVERLAY_PIXEL_KIB,
|
||||
-(int)(((size_t)width * height * sizeof(uint32_t)) >> 10));
|
||||
image_texture_free(ol->images[i]);
|
||||
ol->images[i]->width = width;
|
||||
ol->images[i]->height = height;
|
||||
}
|
||||
for (i = 0; i < ol->size; i++)
|
||||
for (j = 0; j < ol->overlays[i].load_images_size; j++)
|
||||
ol->overlays[i].load_images[j].pixels = NULL;
|
||||
}
|
||||
|
||||
bool input_overlay_load_page(input_overlay_t *ol)
|
||||
{
|
||||
if ( ol->iface->load_textures
|
||||
@@ -221,6 +247,7 @@ bool input_overlay_load_page(input_overlay_t *ol)
|
||||
ol->active->textures, ol->active->load_images_size))
|
||||
{
|
||||
GFX_INSTR_INC(GFX_INSTR_OVERLAY_PAGE);
|
||||
input_overlay_drop_pixels(ol);
|
||||
return true;
|
||||
}
|
||||
/* The wrapper's table answers for any driver; the one beneath
|
||||
@@ -228,6 +255,11 @@ bool input_overlay_load_page(input_overlay_t *ol)
|
||||
input_overlay_release_textures(ol);
|
||||
ol->flags |= INPUT_OVERLAY_TEXTURES_DECLINED;
|
||||
}
|
||||
/* A pack with neither textures nor pixels has nothing to show and
|
||||
* must not show what its pages used to point at; it is on its way
|
||||
* to being reloaded (input_overlay_init). */
|
||||
if (!input_overlay_has_source(ol))
|
||||
return false;
|
||||
GFX_INSTR_INC(GFX_INSTR_OVERLAY_PAGE);
|
||||
GFX_INSTR_INC(GFX_INSTR_OVERLAY_PAGE_LOAD);
|
||||
if (ol->iface->load)
|
||||
|
||||
Reference in new issue
Block a user