X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Floader%2Floader_dri3_helper.c;h=30ea133f7e57b508cd7e429e06c1b3b98be7931f;hb=f386776ea55f86d0288c955cf4cf877a1b4a027d;hp=55e14718bc3d5f4cc617db8d28cf2cd68bf850c6;hpb=7c3e3c0faf7dfff61762fb7bc3299f5d7528b91e;p=mesa.git diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 55e14718bc3..30ea133f7e5 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -32,7 +32,6 @@ #include -#include #include "loader_dri3_helper.h" /* From xmlpool/options.h, user exposed so should be stable */ @@ -59,6 +58,9 @@ static struct loader_dri3_blit_context blit_context = { static void dri3_flush_present_events(struct loader_dri3_drawable *draw); +static struct loader_dri3_buffer * +dri3_find_back_alloc(struct loader_dri3_drawable *draw); + /** * Do we have blit functionality in the image blit extension? * @@ -178,10 +180,16 @@ dri3_fence_trigger(xcb_connection_t *c, struct loader_dri3_buffer *buffer) } static inline void -dri3_fence_await(xcb_connection_t *c, struct loader_dri3_buffer *buffer) +dri3_fence_await(xcb_connection_t *c, struct loader_dri3_drawable *draw, + struct loader_dri3_buffer *buffer) { xcb_flush(c); xshmfence_await(buffer->shm_fence); + if (draw) { + mtx_lock(&draw->mtx); + dri3_flush_present_events(draw); + mtx_unlock(&draw->mtx); + } } static void @@ -197,7 +205,6 @@ void loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) { draw->swap_interval = interval; - dri3_update_num_back(draw); } /** dri3_free_render_buffer @@ -239,6 +246,9 @@ loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) xcb_discard_reply(draw->conn, cookie.sequence); xcb_unregister_for_special_event(draw->conn, draw->special_event); } + + cnd_destroy(&draw->event_cnd); + mtx_destroy(&draw->mtx); } int @@ -269,6 +279,9 @@ loader_dri3_drawable_init(xcb_connection_t *conn, draw->first_init = true; draw->cur_blit_source = -1; + draw->back_format = __DRI_IMAGE_FORMAT_NONE; + mtx_init(&draw->mtx, mtx_plain); + cnd_init(&draw->event_cnd); if (draw->ext->config) draw->ext->config->configQueryi(draw->dri_screen, @@ -341,6 +354,7 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, draw->width = ce->width; draw->height = ce->height; draw->vtable->set_drawable_size(draw, draw->width, draw->height); + draw->ext->flush->invalidate(draw->dri_drawable); break; } case XCB_PRESENT_COMPLETE_NOTIFY: { @@ -362,15 +376,13 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, draw->flipping = false; break; } - dri3_update_num_back(draw); if (draw->vtable->show_fps) draw->vtable->show_fps(draw, ce->ust); draw->ust = ce->ust; draw->msc = ce->msc; - } else { - draw->recv_msc_serial = ce->serial; + } else if (ce->serial == draw->eid) { draw->notify_ust = ce->ust; draw->notify_msc = ce->msc; } @@ -383,13 +395,14 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, for (b = 0; b < sizeof(draw->buffers) / sizeof(draw->buffers[0]); b++) { struct loader_dri3_buffer *buf = draw->buffers[b]; - if (buf && buf->pixmap == ie->pixmap) { + if (buf && buf->pixmap == ie->pixmap) buf->busy = 0; - if (draw->num_back <= b && b < LOADER_DRI3_MAX_BACK) { - dri3_free_render_buffer(draw, buf); - draw->buffers[b] = NULL; - } - break; + + if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK && + draw->cur_blit_source != b && + !buf->busy) { + dri3_free_render_buffer(draw, buf); + draw->buffers[b] = NULL; } } break; @@ -399,13 +412,27 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, } static bool -dri3_wait_for_event(struct loader_dri3_drawable *draw) +dri3_wait_for_event_locked(struct loader_dri3_drawable *draw) { xcb_generic_event_t *ev; xcb_present_generic_event_t *ge; xcb_flush(draw->conn); - ev = xcb_wait_for_special_event(draw->conn, draw->special_event); + + /* Only have one thread waiting for events at a time */ + if (draw->has_event_waiter) { + cnd_wait(&draw->event_cnd, &draw->mtx); + /* Another thread has updated the protected info, so retest. */ + return true; + } else { + draw->has_event_waiter = true; + /* Allow other threads access to the drawable while we're waiting. */ + mtx_unlock(&draw->mtx); + ev = xcb_wait_for_special_event(draw->conn, draw->special_event); + mtx_lock(&draw->mtx); + draw->has_event_waiter = false; + cnd_broadcast(&draw->event_cnd); + } if (!ev) return false; ge = (void *) ev; @@ -424,29 +451,34 @@ loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) { - uint32_t msc_serial; - - msc_serial = ++draw->send_msc_serial; - xcb_present_notify_msc(draw->conn, - draw->drawable, - msc_serial, - target_msc, - divisor, - remainder); + xcb_void_cookie_t cookie = xcb_present_notify_msc(draw->conn, + draw->drawable, + draw->eid, + target_msc, + divisor, + remainder); + xcb_generic_event_t *ev; + unsigned full_sequence; + mtx_lock(&draw->mtx); xcb_flush(draw->conn); /* Wait for the event */ - if (draw->special_event) { - while ((int32_t) (msc_serial - draw->recv_msc_serial) > 0) { - if (!dri3_wait_for_event(draw)) - return false; + do { + ev = xcb_wait_for_special_event(draw->conn, draw->special_event); + if (!ev) { + mtx_unlock(&draw->mtx); + return false; } - } + + full_sequence = ev->full_sequence; + dri3_handle_present_event(draw, (void *) ev); + } while (full_sequence != cookie.sequence || draw->notify_msc < target_msc); *ust = draw->notify_ust; *msc = draw->notify_msc; *sbc = draw->recv_sbc; + mtx_unlock(&draw->mtx); return true; } @@ -468,17 +500,21 @@ loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw, * swaps requested with glXSwapBuffersMscOML for that window have * completed." */ + mtx_lock(&draw->mtx); if (!target_sbc) target_sbc = draw->send_sbc; while (draw->recv_sbc < target_sbc) { - if (!dri3_wait_for_event(draw)) + if (!dri3_wait_for_event_locked(draw)) { + mtx_unlock(&draw->mtx); return 0; + } } *ust = draw->ust; *msc = draw->msc; *sbc = draw->recv_sbc; + mtx_unlock(&draw->mtx); return 1; } @@ -491,16 +527,17 @@ static int dri3_find_back(struct loader_dri3_drawable *draw) { int b; - xcb_generic_event_t *ev; - xcb_present_generic_event_t *ge; - int num_to_consider = draw->num_back; + int num_to_consider; + mtx_lock(&draw->mtx); /* Increase the likelyhood of reusing current buffer */ dri3_flush_present_events(draw); /* Check whether we need to reuse the current back buffer as new back. * In that case, wait until it's not busy anymore. */ + dri3_update_num_back(draw); + num_to_consider = draw->num_back; if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) { num_to_consider = 1; draw->cur_blit_source = -1; @@ -513,15 +550,14 @@ dri3_find_back(struct loader_dri3_drawable *draw) if (!buffer || !buffer->busy) { draw->cur_back = id; + mtx_unlock(&draw->mtx); return id; } } - xcb_flush(draw->conn); - ev = xcb_wait_for_special_event(draw->conn, draw->special_event); - if (!ev) + if (!dri3_wait_for_event_locked(draw)) { + mtx_unlock(&draw->mtx); return -1; - ge = (void *) ev; - dri3_handle_present_event(draw, ge); + } } } @@ -616,7 +652,10 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, flags |= __DRI2_FLUSH_CONTEXT; loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER); - back = dri3_back_buffer(draw); + back = dri3_find_back_alloc(draw); + if (!back) + return; + y = draw->height - y - height; if (draw->is_different_gpu) { @@ -628,20 +667,12 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, back->image, 0, 0, back->width, back->height, 0, 0, __BLIT_FLAG_FLUSH); - /* We use blit_image to update our fake front, - */ - if (draw->have_fake_front) - (void) loader_dri3_blit_image(draw, - dri3_fake_front_buffer(draw)->image, - back->image, - x, y, width, height, - x, y, __BLIT_FLAG_FLUSH); } loader_dri3_swapbuffer_barrier(draw); dri3_fence_reset(draw->conn, back); dri3_copy_area(draw->conn, - dri3_back_buffer(draw)->pixmap, + back->pixmap, draw->drawable, dri3_drawable_gc(draw), x, y, x, y, width, height); @@ -649,17 +680,23 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, /* Refresh the fake front (if present) after we just damaged the real * front. */ - if (draw->have_fake_front && !draw->is_different_gpu) { + if (draw->have_fake_front && + !loader_dri3_blit_image(draw, + dri3_fake_front_buffer(draw)->image, + back->image, + x, y, width, height, + x, y, __BLIT_FLAG_FLUSH) && + !draw->is_different_gpu) { dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); dri3_copy_area(draw->conn, - dri3_back_buffer(draw)->pixmap, + back->pixmap, dri3_fake_front_buffer(draw)->pixmap, dri3_drawable_gc(draw), x, y, x, y, width, height); dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); - dri3_fence_await(draw->conn, dri3_fake_front_buffer(draw)); + dri3_fence_await(draw->conn, NULL, dri3_fake_front_buffer(draw)); } - dri3_fence_await(draw->conn, back); + dri3_fence_await(draw->conn, draw, back); } void @@ -675,7 +712,7 @@ loader_dri3_copy_drawable(struct loader_dri3_drawable *draw, dri3_drawable_gc(draw), 0, 0, 0, 0, draw->width, draw->height); dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); - dri3_fence_await(draw->conn, dri3_fake_front_buffer(draw)); + dri3_fence_await(draw->conn, draw, dri3_fake_front_buffer(draw)); } void @@ -736,6 +773,9 @@ dri3_flush_present_events(struct loader_dri3_drawable *draw) /* Check to see if any configuration changes have occurred * since we were last invoked */ + if (draw->has_event_waiter) + return; + if (draw->special_event) { xcb_generic_event_t *ev; @@ -763,7 +803,9 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, draw->vtable->flush_drawable(draw, flush_flags); - back = draw->buffers[dri3_find_back(draw)]; + back = dri3_find_back_alloc(draw); + + mtx_lock(&draw->mtx); if (draw->is_different_gpu && back) { /* Update the linear buffer before presenting the pixmap */ (void) loader_dri3_blit_image(draw, @@ -883,6 +925,7 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, if (draw->stamp) ++(*draw->stamp); } + mtx_unlock(&draw->mtx); draw->ext->flush->invalidate(draw->dri_drawable); @@ -892,15 +935,15 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw) { - int back_id = LOADER_DRI3_BACK_ID(dri3_find_back(draw)); + struct loader_dri3_buffer *back = dri3_find_back_alloc(draw); + int ret; - if (back_id < 0 || !draw->buffers[back_id]) - return 0; + mtx_lock(&draw->mtx); + ret = (!back || back->last_swap == 0) ? 0 : + draw->send_sbc - back->last_swap + 1; + mtx_unlock(&draw->mtx); - if (draw->buffers[back_id]->last_swap != 0) - return draw->send_sbc - draw->buffers[back_id]->last_swap + 1; - else - return 0; + return ret; } /** loader_dri3_open @@ -950,6 +993,8 @@ dri3_cpp_for_format(uint32_t format) { case __DRI_IMAGE_FORMAT_XBGR8888: case __DRI_IMAGE_FORMAT_XRGB2101010: case __DRI_IMAGE_FORMAT_ARGB2101010: + case __DRI_IMAGE_FORMAT_XBGR2101010: + case __DRI_IMAGE_FORMAT_ABGR2101010: case __DRI_IMAGE_FORMAT_SARGB8: return 4; case __DRI_IMAGE_FORMAT_NONE: @@ -958,6 +1003,31 @@ dri3_cpp_for_format(uint32_t format) { } } +/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while + * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid + * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and + * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds + */ +static int +image_format_to_fourcc(int format) +{ + + /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ + switch (format) { + case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; + case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; + case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; + case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; + case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; + case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; + case __DRI_IMAGE_FORMAT_XRGB2101010: return __DRI_IMAGE_FOURCC_XRGB2101010; + case __DRI_IMAGE_FORMAT_ARGB2101010: return __DRI_IMAGE_FOURCC_ARGB2101010; + case __DRI_IMAGE_FORMAT_XBGR2101010: return __DRI_IMAGE_FOURCC_XBGR2101010; + case __DRI_IMAGE_FORMAT_ABGR2101010: return __DRI_IMAGE_FOURCC_ABGR2101010; + } + return 0; +} + /** loader_dri3_alloc_render_buffer * * Use the driver createImage function to construct a __DRIimage, then @@ -1097,6 +1167,7 @@ static int dri3_update_drawable(__DRIdrawable *driDrawable, struct loader_dri3_drawable *draw) { + mtx_lock(&draw->mtx); if (draw->first_init) { xcb_get_geometry_cookie_t geom_cookie; xcb_get_geometry_reply_t *geom_reply; @@ -1137,8 +1208,10 @@ dri3_update_drawable(__DRIdrawable *driDrawable, geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); - if (!geom_reply) + if (!geom_reply) { + mtx_unlock(&draw->mtx); return false; + } draw->width = geom_reply->width; draw->height = geom_reply->height; @@ -1170,6 +1243,7 @@ dri3_update_drawable(__DRIdrawable *driDrawable, if (error) { if (error->error_code != BadWindow) { free(error); + mtx_unlock(&draw->mtx); return false; } draw->is_pixmap = true; @@ -1178,30 +1252,10 @@ dri3_update_drawable(__DRIdrawable *driDrawable, } } dri3_flush_present_events(draw); + mtx_unlock(&draw->mtx); return true; } -/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while - * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid - * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and - * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds - */ -static int -image_format_to_fourcc(int format) -{ - - /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ - switch (format) { - case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; - case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; - case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; - case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; - case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; - case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; - } - return 0; -} - __DRIimage * loader_dri3_create_image(xcb_connection_t *c, xcb_dri3_buffer_from_pixmap_reply_t *bp_reply, @@ -1238,7 +1292,10 @@ loader_dri3_create_image(xcb_connection_t *c, ret = image->fromPlanar(image_planar, 0, loaderPrivate); - image->destroyImage(image_planar); + if (!ret) + ret = image_planar; + else + image->destroyImage(image_planar); return ret; } @@ -1261,6 +1318,7 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, xcb_sync_fence_t sync_fence; struct xshmfence *shm_fence; int fence_fd; + __DRIscreen *cur_screen; if (buffer) return buffer; @@ -1291,8 +1349,17 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, if (!bp_reply) goto no_image; + /* Get the currently-bound screen or revert to using the drawable's screen if + * no contexts are currently bound. The latter case is at least necessary for + * obs-studio, when using Window Capture (Xcomposite) as a Source. + */ + cur_screen = draw->vtable->get_dri_screen(); + if (!cur_screen) { + cur_screen = draw->dri_screen; + } + buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format, - draw->dri_screen, draw->ext->image, + cur_screen, draw->ext->image, buffer); if (!buffer->image) goto no_image; @@ -1334,6 +1401,8 @@ dri3_get_buffer(__DRIdrawable *driDrawable, int buf_id; if (buffer_type == loader_dri3_buffer_back) { + draw->back_format = format; + buf_id = dri3_find_back(draw); if (buf_id < 0) @@ -1364,30 +1433,30 @@ dri3_get_buffer(__DRIdrawable *driDrawable, /* When resizing, copy the contents of the old buffer, waiting for that * copy to complete using our fences before proceeding */ - switch (buffer_type) { - case loader_dri3_buffer_back: - if (buffer) { - if (!buffer->linear_buffer) { - dri3_fence_reset(draw->conn, new_buffer); - dri3_fence_await(draw->conn, buffer); - dri3_copy_area(draw->conn, - buffer->pixmap, - new_buffer->pixmap, - dri3_drawable_gc(draw), - 0, 0, 0, 0, - draw->width, draw->height); - dri3_fence_trigger(draw->conn, new_buffer); - } else if (draw->vtable->in_current_context(draw)) { - (void) loader_dri3_blit_image(draw, - new_buffer->image, - buffer->image, - 0, 0, draw->width, draw->height, - 0, 0, 0); - } - dri3_free_render_buffer(draw, buffer); + if ((buffer_type == loader_dri3_buffer_back || + (buffer_type == loader_dri3_buffer_front && draw->have_fake_front)) + && buffer) { + + /* Fill the new buffer with data from an old buffer */ + dri3_fence_await(draw->conn, draw, buffer); + if (!loader_dri3_blit_image(draw, + new_buffer->image, + buffer->image, + 0, 0, draw->width, draw->height, + 0, 0, 0) && + !buffer->linear_buffer) { + dri3_fence_reset(draw->conn, new_buffer); + dri3_copy_area(draw->conn, + buffer->pixmap, + new_buffer->pixmap, + dri3_drawable_gc(draw), + 0, 0, 0, 0, + draw->width, draw->height); + dri3_fence_trigger(draw->conn, new_buffer); } - break; - case loader_dri3_buffer_front: + dri3_free_render_buffer(draw, buffer); + } else if (buffer_type == loader_dri3_buffer_front) { + /* Fill the new fake front with data from a real front */ loader_dri3_swapbuffer_barrier(draw); dri3_fence_reset(draw->conn, new_buffer); dri3_copy_area(draw->conn, @@ -1398,21 +1467,19 @@ dri3_get_buffer(__DRIdrawable *driDrawable, draw->width, draw->height); dri3_fence_trigger(draw->conn, new_buffer); - if (new_buffer->linear_buffer && - draw->vtable->in_current_context(draw)) { - dri3_fence_await(draw->conn, new_buffer); + if (new_buffer->linear_buffer) { + dri3_fence_await(draw->conn, draw, new_buffer); (void) loader_dri3_blit_image(draw, new_buffer->image, new_buffer->linear_buffer, 0, 0, draw->width, draw->height, 0, 0, 0); } - break; } buffer = new_buffer; draw->buffers[buf_id] = buffer; } - dri3_fence_await(draw->conn, buffer); + dri3_fence_await(draw->conn, draw, buffer); /* * Do we need to preserve the content of a previous buffer? @@ -1462,10 +1529,12 @@ dri3_free_buffers(__DRIdrawable *driDrawable, case loader_dri3_buffer_back: first_id = LOADER_DRI3_BACK_ID(0); n_id = LOADER_DRI3_MAX_BACK; + draw->cur_blit_source = -1; break; case loader_dri3_buffer_front: first_id = LOADER_DRI3_FRONT_ID; - n_id = 1; + /* Don't free a fake front holding new backbuffer content. */ + n_id = (draw->cur_blit_source == LOADER_DRI3_FRONT_ID) ? 0 : 1; } for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { @@ -1584,6 +1653,7 @@ loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw) draw->width = geom_reply->width; draw->height = geom_reply->height; draw->vtable->set_drawable_size(draw, draw->width, draw->height); + draw->ext->flush->invalidate(draw->dri_drawable); free(geom_reply); } @@ -1620,3 +1690,56 @@ loader_dri3_close_screen(__DRIscreen *dri_screen) } mtx_unlock(&blit_context.mtx); } + +/** + * Find a backbuffer slot - potentially allocating a back buffer + * + * \param draw[in,out] Pointer to the drawable for which to find back. + * \return Pointer to a new back buffer or NULL if allocation failed or was + * not mandated. + * + * Find a potentially new back buffer, and if it's not been allocated yet and + * in addition needs initializing, then try to allocate and initialize it. + */ +#include +static struct loader_dri3_buffer * +dri3_find_back_alloc(struct loader_dri3_drawable *draw) +{ + struct loader_dri3_buffer *back; + int id; + + id = dri3_find_back(draw); + if (id < 0) + return NULL; + + back = draw->buffers[id]; + /* Allocate a new back if we haven't got one */ + if (!back && draw->back_format != __DRI_IMAGE_FORMAT_NONE && + dri3_update_drawable(draw->dri_drawable, draw)) + back = dri3_alloc_render_buffer(draw, draw->back_format, + draw->width, draw->height, draw->depth); + + if (!back) + return NULL; + + draw->buffers[id] = back; + + /* If necessary, prefill the back with data according to swap_method mode. */ + if (draw->cur_blit_source != -1 && + draw->buffers[draw->cur_blit_source] && + back != draw->buffers[draw->cur_blit_source]) { + struct loader_dri3_buffer *source = draw->buffers[draw->cur_blit_source]; + + dri3_fence_await(draw->conn, draw, source); + dri3_fence_await(draw->conn, draw, back); + (void) loader_dri3_blit_image(draw, + back->image, + source->image, + 0, 0, draw->width, draw->height, + 0, 0, 0); + back->last_swap = source->last_swap; + draw->cur_blit_source = -1; + } + + return back; +}