[PATCH 10/10] dri2: Testpatch: Fix corner case crash but not the problem.
Mario Kleiner
mario.kleiner at tuebingen.mpg.de
Thu Mar 1 10:11:15 PST 2012
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 <mario.kleiner at tuebingen.mpg.de>
---
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
More information about the xorg-devel
mailing list