egl/wayland: break double/tripple buffering feedback loops
Currently we dispose any unneeded color buffers immediately if we detect that there are more unlocked buffers than we need. This can lead to feedback loops between the compositor and the application causing rapid toggling between double and tripple buffering. Scenario: 2 buffers already queued to the compositor, egl/wayland allocates a new back buffer to avoid throttling, slowing down the frame. This allows the compositor to catch up and unlock both buffers. EGL detects that there are more buffers than currently needed, freeing the buffer, restarting the loop shortly after. To avoid wasting CPU time on rapidly freeing and reallocating color buffers break those feedback loops by letting the unneeded buffers sit around for a short while before disposing them. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Simon Ser <contact@emersion.fr> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14451>
This commit is contained in:
parent
d77bfc117c
commit
22d796feb8
|
@ -1096,6 +1096,12 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
|
|||
buffer->flags = 0;
|
||||
}
|
||||
|
||||
/* Value chosen empirically as a compromise between avoiding frequent
|
||||
* reallocations and extended time of increased memory consumption due to
|
||||
* unused buffers being kept.
|
||||
*/
|
||||
#define BUFFER_TRIM_AGE_HYSTERESIS 20
|
||||
|
||||
static int
|
||||
update_buffers(struct dri2_egl_surface *dri2_surf)
|
||||
{
|
||||
|
@ -1125,10 +1131,13 @@ update_buffers(struct dri2_egl_surface *dri2_surf)
|
|||
|
||||
/* If we have an extra unlocked buffer at this point, we had to do triple
|
||||
* buffering for a while, but now can go back to just double buffering.
|
||||
* That means we can free any unlocked buffer now. */
|
||||
* That means we can free any unlocked buffer now. To avoid toggling between
|
||||
* going back to double buffering and needing to allocate another buffer too
|
||||
* fast we let the unneeded buffer sit around for a short while. */
|
||||
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
||||
if (!dri2_surf->color_buffers[i].locked &&
|
||||
dri2_surf->color_buffers[i].wl_buffer) {
|
||||
dri2_surf->color_buffers[i].wl_buffer &&
|
||||
dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) {
|
||||
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
||||
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
||||
if (dri2_dpy->is_different_gpu)
|
||||
|
@ -2321,10 +2330,13 @@ swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
|
|||
|
||||
/* If we have an extra unlocked buffer at this point, we had to do triple
|
||||
* buffering for a while, but now can go back to just double buffering.
|
||||
* That means we can free any unlocked buffer now. */
|
||||
* That means we can free any unlocked buffer now. To avoid toggling between
|
||||
* going back to double buffering and needing to allocate another buffer too
|
||||
* fast we let the unneeded buffer sit around for a short while. */
|
||||
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
||||
if (!dri2_surf->color_buffers[i].locked &&
|
||||
dri2_surf->color_buffers[i].wl_buffer) {
|
||||
dri2_surf->color_buffers[i].wl_buffer &&
|
||||
dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) {
|
||||
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
||||
munmap(dri2_surf->color_buffers[i].data,
|
||||
dri2_surf->color_buffers[i].data_size);
|
||||
|
|
Loading…
Reference in New Issue