From 09dc0fb2eed65074306c51e3475ebc36f42a2cdb Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 8 Sep 2021 20:08:57 +0200 Subject: [PATCH] loader/dri3: avoid reusing the same back buffer with DRI_PRIME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For DRI_PRIME setup where the dGPU -> iGPU copy can happen asynchronously, we need to ensure that we're not continuously reusing the same back buffer. The existing code relies on XCB_PRESENT_EVENT_IDLE_NOTIFY to decide if a buffer is busy or idle. If this event is received before the hardware is done using the buffer, then it will reuse the same buffer and introduce a dependency between the copy and the next frame. This commit mitigates this by trying to allocate a different back buffer when called from dri3_get_buffer (not from dri3_find_back_alloc, because it seems that it expects dri3_get_buffer - see 0cc4c7e33ed). An alternative would be to query the busy-ness using is_resource_busy but this complicates the code to achieve the same result. One affected app is Unigine Superposition, and this change improves the score by 0% - 5% depending on the settings. This behavior is enabled if PIPE_CAP_PREFER_BACK_BUFFER_REUSE is 0. Reviewed-by: Marek Olšák Acked-by: Michel Dänzer Part-of: --- src/loader/loader_dri3_helper.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 16cb1faf7b3..e808bcf9741 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -679,7 +679,7 @@ loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw, * wait for a present idle notify event from the X server */ static int -dri3_find_back(struct loader_dri3_drawable *draw) +dri3_find_back(struct loader_dri3_drawable *draw, bool prefer_a_different) { int b; int num_to_consider; @@ -701,12 +701,23 @@ dri3_find_back(struct loader_dri3_drawable *draw) max_num = draw->max_num_back; } + /* In a DRI_PRIME situation, if prefer_a_different is true, we first try + * to find an idle buffer that is not the last used one. + * This is useful if we receive a XCB_PRESENT_EVENT_IDLE_NOTIFY event + * for a pixmap but it's not actually idle (eg: the DRI_PRIME blit is + * still in progress). + * Unigine Superposition hits this and this allows to use 2 back buffers + * instead of reusing the same one all the time, causing the next frame + * to wait for the copy to finish. + */ + int current_back_id = draw->cur_back; for (;;) { for (b = 0; b < num_to_consider; b++) { int id = LOADER_DRI3_BACK_ID((b + draw->cur_back) % draw->cur_num_back); struct loader_dri3_buffer *buffer = draw->buffers[id]; - if (!buffer || !buffer->busy) { + if (!buffer || (!buffer->busy && + (!prefer_a_different || id != current_back_id))) { draw->cur_back = id; mtx_unlock(&draw->mtx); return id; @@ -715,6 +726,8 @@ dri3_find_back(struct loader_dri3_drawable *draw) if (num_to_consider < max_num) { num_to_consider = ++draw->cur_num_back; + } else if (prefer_a_different) { + prefer_a_different = false; } else if (!dri3_wait_for_event_locked(draw, NULL)) { mtx_unlock(&draw->mtx); return -1; @@ -1921,7 +1934,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable, if (buffer_type == loader_dri3_buffer_back) { draw->back_format = format; - buf_id = dri3_find_back(draw); + buf_id = dri3_find_back(draw, !draw->prefer_back_buffer_reuse); if (buf_id < 0) return NULL; @@ -2246,7 +2259,7 @@ dri3_find_back_alloc(struct loader_dri3_drawable *draw) struct loader_dri3_buffer *back; int id; - id = dri3_find_back(draw); + id = dri3_find_back(draw, false); if (id < 0) return NULL;