By design, framebuffer can be marked as obsoleted by GL calls (such as eglDestroySurface) at any time, but gets released only when it's no longer used (by calls such as eglMakeCurrent). st_manager uses two structs to achieve this, one is hash table stfbi_ht, which tracks st_framebuffer_iface of every active (non-obsolete) st_framebuffers, another one is linked list winsys_buffer, which keeps all currently used st_framebuffers. Consider following call sequence (assuming we are using dri backend): EGLSurface surf1 = eglCreateWindowSurface(...); eglMakeCurrent(..., surf1, surf1, ...); // do rendering.... eglDestroySurface(..., surf1); EGLSurface surf2 = eglCreateWindowSurface(...); eglMakeCurrent(..., surf2, surf2, ...); When first eglMakeCurrent is called, st_api_make_current is called, st_framebuffer is created, its iface is pointed to the actual dri_drawable of surf1. st_framebuffer is added into winsys_buffer and iface is added into stfbi_ht. then st_framebuffers_purge is called, it traverses winsys_buffer, searches iface in stfbi_ht, found all framebuffers are active. When eglDestroySurface is called, st_api_destroy_drawable is called, only st_framebuffer_iface (which is actually dri_drawable of surf1) is removed from stfbi_ht. When second eglMakeCurrent is called, st_api_make_current is called, st_framebuffer is created, its iface is pointed to the actual dri_drawable of surf2, st_framebuffer is added into winsys_buffer and iface is added into stfbi_ht. then st_framebuffers_purge is called, it traverses winsys_buffers, found st_framebuffer->iface of surf1 is not in stfbi_ht, which means surf1 is obsolete, at last st_framebuffer is released and removed from winsys_buffers. This mechanism depends on an assumption: iface (which are dri_drawable of surf1 and surf2) are allocated on different locations on memory, so their address can be used as hash key. The assumption works for most cases, but on Android x86, due to different malloc implementation, dri_drawable of surf1 and surf2 are very likely to be allocated on the same address, which breaks st_framebuffers_purge, causes stale st_framebuffer never gets freed. Test environment: Android x86 7.1.2-r36, AMD Radeon RX560 How to reproduce: keep switching any app between foreground and background. Observe /sys/kernel/debug/dri/0/amdgpu_gem_info will find gem usage increase.
Proposed solution: do not use st_framebuffer_iface address as hash key, use st_framebuffer_iface->ID instead. According to st_api.h, ID is "Identifier that uniquely identifies the framebuffer interface object.", which is guaranteed to be unique. Please refer to attached patch.
Created attachment 142041 [details] [review] proposed patch
From a quick skim at the report - it does sound similar to the issue described here [1]. Feel free to try the patch. If it doesn't help please submit any patches as described here [2] [1] https://patchwork.freedesktop.org/patch/218289/ [2] https://www.mesa3d.org/submittingpatches.html
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/mesa/mesa/issues/1031.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.