summaryrefslogtreecommitdiff
path: root/src/nouveau_dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nouveau_dri2.c')
-rw-r--r--src/nouveau_dri2.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index f0c7fec..7878a5a 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -445,6 +445,26 @@ 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.
+ */
+ if (current_msc < *target_msc - 1)
+ DRI2SwapLimit(draw, 1);
+#endif
+
/* Request a vblank event one frame before the target */
ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
DRM_VBLANK_EVENT,
@@ -557,6 +577,12 @@ 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
+
break;
case WAIT: