Treats vblank event scheduling for the non-pageflip swap
case correctly. Allows vblank controlled swaps for redirected
windows. Fixes some corner-cases in OML_sync_control scheduling
when divisor and remainder parameters are used.

Signed-off-by: Mario Kleiner <[email protected]>
---
 src/nouveau_dri2.c |   71 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 9f0ee97..f14dea4 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -196,10 +196,8 @@ can_sync_to_vblank(DrawablePtr draw)
 {
        ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
        NVPtr pNv = NVPTR(scrn);
-       PixmapPtr pix = NVGetDrawablePixmap(draw);
 
        return pNv->glx_vblank &&
-               nouveau_exa_pixmap_is_onscreen(pix) &&
                nv_window_belongs_to_crtc(scrn, draw->x, draw->y,
                                          draw->width, draw->height);
 }
@@ -344,9 +342,40 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr 
draw,
                           CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
                           DRI2SwapEventPtr func, void *data)
 {
+       PixmapPtr dst_pix;
+       PixmapPtr src_pix = nouveau_dri2_buffer(src)->ppix;
        struct nouveau_dri2_vblank_state *s;
        CARD64 current_msc, expect_msc;
-       int ret;
+       int ret, flip = 0;
+       Bool front_updated;
+
+       /* Truncate to match kernel interfaces; means occasional overflow
+        * misses, but that's generally not a big deal.
+        */
+       *target_msc &= 0xffffffff;
+       divisor &= 0xffffffff;
+       remainder &= 0xffffffff;
+
+       /* Update frontbuffer pixmap and name: Could have changed due to
+        * window (un)redirection as part of compositing.
+        */
+       front_updated = update_front(draw, dst);
+
+       /* Assign frontbuffer pixmap, after update in update_front() */
+       dst_pix = nouveau_dri2_buffer(dst)->ppix;
+
+       /* Flips need to be submitted one frame before */
+       if (DRI2CanFlip(draw) && front_updated &&
+           can_exchange(draw, dst_pix, src_pix)) {
+               flip = 1;
+       }
+
+       /* Correct target_msc by 'flip' if this is a page-flipped swap.
+        * Do it early, so handling of different timing constraints
+        * for divisor, remainder and msc vs. target_msc works.
+        */
+       if (*target_msc > 0)
+               *target_msc -= (CARD64) flip;
 
        /* Initialize a swap structure */
        s = malloc(sizeof(*s));
@@ -363,19 +392,34 @@ nouveau_dri2_schedule_swap(ClientPtr client, DrawablePtr 
draw,
                if (ret)
                        goto fail;
 
-               /* Calculate a swap target if we don't have one */
-               if (current_msc >= *target_msc && divisor)
+               /* Calculate a swap target if we don't have one or if
+                * divisor/remainder relationship must be satisfied.
+                */
+               if (current_msc >= *target_msc && divisor) {
                        *target_msc = current_msc + divisor
                                - (current_msc - remainder) % divisor;
 
-               /* Request a vblank event one frame before the target */
+                       /* Account for extra pageflip delay if flip > 0 */
+                       *target_msc -= (CARD64) flip;
+               }
+
+               /* Request a vblank event one frame before the target, unless
+                * this is a copy-swap, in which case we need to make sure
+                * it is only dispatched at the target frame or later.
+                */
                ret = nouveau_wait_vblank(draw, DRM_VBLANK_ABSOLUTE |
-                                         DRM_VBLANK_EVENT,
-                                         max(current_msc, *target_msc - 1),
+                                         DRM_VBLANK_EVENT |
+                                         ((flip) ? 0 : DRM_VBLANK_NEXTONMISS),
+                                         max(current_msc, *target_msc),
                                          &expect_msc, NULL, s);
                if (ret)
                        goto fail;
-               s->frame = (unsigned int) expect_msc & 0xffffffff;
+
+               /* Store expected target_msc for later consistency check and
+                * return it to server for proper swap_interval implementation.
+                */
+               s->frame = ((unsigned int) (expect_msc & 0xffffffff)) + flip ;
+               *target_msc = s->frame;
        } else {
                /* We can't/don't want to sync to vblank, just swap. */
                nouveau_dri2_finish_swap(draw, 0, 0, 0, s);
@@ -396,6 +440,13 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr 
draw,
        CARD64 current_msc;
        int ret;
 
+       /* Truncate to match kernel interfaces; means occasional overflow
+        * misses, but that's generally not a big deal.
+        */
+       target_msc &= 0xffffffff;
+       divisor &= 0xffffffff;
+       remainder &= 0xffffffff;
+
        if (!can_sync_to_vblank(draw)) {
                DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
                return TRUE;
@@ -415,7 +466,7 @@ nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr 
draw,
                goto fail;
 
        /* Calculate a wait target if we don't have one */
-       if (current_msc > target_msc && divisor)
+       if (current_msc >= target_msc && divisor)
                target_msc = current_msc + divisor
                        - (current_msc - remainder) % divisor;
 
-- 
1.7.1

_______________________________________________
Nouveau mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to