Do not apply - Just for illustration: Introduce reference counting for nouveau_dri2_buffers and temporarily increase refcount on nouveau_dri2_buffer frontbuffer to protect it against premature deletion by x-server as part of the DRI2GetBuffers[WithFormat]() path while the vblank event for a scheduled swap is still pending and nouveau_dri2_finish_swap() hasn't completed for this swap.
This prevents server/ddx crash on deferred swaps with swaplimit > 1 but doesn't fix the problem: We try to treat a setup which is only double-buffered as if it is truly triple-buffered. This causes flickering, so not useful in practice. Signed-off-by: Mario Kleiner <[email protected]> --- src/nouveau_dri2.c | 57 +++++++++++++++++++++++++++++++--------------------- 1 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c index 7878a5a..eb008c9 100644 --- a/src/nouveau_dri2.c +++ b/src/nouveau_dri2.c @@ -14,6 +14,7 @@ struct nouveau_dri2_buffer { DRI2BufferRec base; PixmapPtr ppix; + unsigned int refcnt; }; static inline struct nouveau_dri2_buffer * @@ -79,6 +80,7 @@ nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, nvbuf->base.format = format; nvbuf->base.flags = 0; nvbuf->ppix = ppix; + nvbuf->refcnt++; nvpix = nouveau_pixmap(ppix); if (!nvpix || !nvpix->bo || @@ -100,6 +102,10 @@ nouveau_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf) if (!nvbuf) return; + nvbuf->refcnt--; + if (nvbuf->refcnt) + return; + pDraw->pScreen->DestroyPixmap(nvbuf->ppix); free(nvbuf); } @@ -178,6 +184,17 @@ update_front(DrawablePtr draw, DRI2BufferPtr front) return TRUE; } +static void +ref_front(DrawablePtr draw, DRI2BufferPtr front, Bool doref) +{ + struct nouveau_dri2_buffer *nvbuf = nouveau_dri2_buffer(front); + + if (doref) + nvbuf->refcnt++; + else + nouveau_dri2_destroy_buffer(draw, front); +} + static Bool can_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix) { @@ -445,25 +462,21 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (*target_msc == 0) *target_msc = 1; -#if DRI2INFOREC_VERSION >= 6 - /* Is this a swap in the future, ie. the vblank event will - * not be immediately dispatched, but only at a future vblank? - * If so, we need to temporarily lower the swaplimit to 1, so - * that DRI2GetBuffersWithFormat() requests from the client get - * deferred in the x-server until the vblank event has been - * dispatched to us and nouveau_dri2_finish_swap() is done. If - * we wouldn't do this, DRI2GetBuffersWithFormat() would operate - * on wrong (pre-swap) buffers, and cause a segfault later on in - * nouveau_dri2_finish_swap(). Our vblank event handler restores - * the old swaplimit immediately after nouveau_dri2_finish_swap() - * is done, so we still get 1 video refresh cycle worth of - * triple-buffering. For a swap at next vblank, dispatch of the - * vblank event happens immediately, so there isn't any need - * for this lowered swaplimit. + /* Increase refcount on frontbuffer to protect it against + * premature deletion by x-server as part of the + * DRI2GetBuffersWithFormat() path while the vblank event + * is still pending and nouveau_dri2_finish_swap() hasn't + * completed for this swap. + * + * XXX: This prevents server/ddx crash on deferred swaps, + * but doesn't fix the problem: We try to treat a setup + * which is only double-buffered as if it is truly triple- + * buffered. This causes flickering, so not useful in practice. + * + * Tinkering with the DRI2SwapLimit() is ugly but provides + * proper behaviour. */ - if (current_msc < *target_msc - 1) - DRI2SwapLimit(draw, 1); -#endif + ref_front(draw, s->dst, true); /* Request a vblank event one frame before the target */ ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE | @@ -577,12 +590,10 @@ nouveau_dri2_vblank_handler(int fd, unsigned int frame, switch (s->action) { case SWAP: nouveau_dri2_finish_swap(draw, frame, tv_sec, tv_usec, s); -#if DRI2INFOREC_VERSION >= 6 - /* Restore real swap limit on drawable, now that it is safe. */ - ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum]; - DRI2SwapLimit(draw, NVPTR(scrn)->swap_limit); -#endif + /* Drop our reference on frontbuffer, now that the swap + * has been programmed. */ + ref_front(draw, s->dst, false); break; case WAIT: -- 1.7.5.4 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
