loader/dri3: avoid reusing the same back buffer with DRI_PRIME
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 0cc4c7e33e
).
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 <marek.olsak@amd.com>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12788>
This commit is contained in:
parent
e67083caf4
commit
09dc0fb2ee
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue