egl/gbm: Destroy excess BOs

Calculate the minimum available buffer age in addition to the maximum,
and if they differ for 1000 frames in a row, destroy the BO for the
highest-age unused buffer.

Without this, Wayland compositors using dynamic triple buffering always
get buffer age 3 once a third BO has been allocated.

v2:
* Rename function to destroy_oldest_unused_bo. (Marek Olšák)
* Move function call into if block.
* Use == instead of > as the condition for the function call.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37511>
This commit is contained in:
Michel Dänzer 2025-09-22 15:12:36 +02:00 committed by Marge Bot
parent 15b8d3ca43
commit dd7ae41091
2 changed files with 43 additions and 5 deletions

View file

@ -338,6 +338,7 @@ struct dri2_egl_surface {
#ifdef HAVE_DRM_PLATFORM
struct gbm_dri_surface *gbm_surf;
unsigned excess_bo_frames;
#endif
#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)

View file

@ -216,22 +216,59 @@ dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
return EGL_TRUE;
}
static void
destroy_oldest_unused_bo(struct dri2_egl_surface *dri2_surf)
{
int max_age = 0;
struct dri2_egl_buffer *oldest_buffer = NULL;
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (dri2_surf->color_buffers[i].locked ||
dri2_surf->back == &dri2_surf->color_buffers[i])
continue;
if (!max_age || dri2_surf->color_buffers[i].age > max_age) {
oldest_buffer = &dri2_surf->color_buffers[i];
max_age = dri2_surf->color_buffers[i].age;
}
}
gbm_bo_destroy(oldest_buffer->bo);
oldest_buffer->bo = NULL;
oldest_buffer->age = 0;
dri2_surf->excess_bo_frames = 0;
}
static int
get_back_bo(struct dri2_egl_surface *dri2_surf)
{
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
int age = 0;
int min_age = 0, max_age = 0;
if (dri2_surf->back == NULL) {
for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
if (!dri2_surf->color_buffers[i].locked &&
dri2_surf->color_buffers[i].age >= age) {
dri2_surf->back = &dri2_surf->color_buffers[i];
age = dri2_surf->color_buffers[i].age;
if (!dri2_surf->color_buffers[i].locked) {
int age = dri2_surf->color_buffers[i].age;
if (!min_age || age < min_age)
min_age = age;
if (!max_age || age > max_age) {
dri2_surf->back = &dri2_surf->color_buffers[i];
max_age = age;
}
}
}
if (min_age && min_age < max_age) {
if (++dri2_surf->excess_bo_frames == 1000)
destroy_oldest_unused_bo(dri2_surf);
} else {
dri2_surf->excess_bo_frames = 0;
}
}
if (dri2_surf->back == NULL)