glx/dri3: Implement GLX_EXT_swap_control_tear
authorAdam Jackson <ajax@redhat.com>
Wed, 9 Sep 2020 19:14:30 +0000 (15:14 -0400)
committerAdam Jackson <ajax@redhat.com>
Thu, 10 Sep 2020 18:48:19 +0000 (14:48 -0400)
Not wired up for DRI2 because it would require server-side support,
which I'm not especially interested in writing.

Fixes: mesa/mesa#96
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6671>

docs/relnotes/new_features.txt
src/glx/dri3_glx.c
src/glx/glx_pbuffer.c
src/glx/glxcmds.c
src/glx/glxextensions.c
src/glx/glxextensions.h
src/loader/loader_dri3_helper.c

index 01d1d5f..5a1eb93 100644 (file)
@@ -4,3 +4,4 @@ GL_NV_half_float
 EGL_KHR_swap_buffers_with_damage on X11 (DRI3)
 VK_PRESENT_MODE_FIFO_RELAXED on X11
 GLX_EXT_swap_control for DRI2 and DRI3
+GLX_EXT_swap_control_tear for DRI3
index 385791f..60b0c1c 100644 (file)
@@ -742,6 +742,7 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
    extensions = psc->core->getExtensions(psc->driScreen);
 
    __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control");
+   __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control_tear");
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
index ffc4f6c..8208c97 100644 (file)
@@ -352,6 +352,10 @@ __glXGetDrawableAttribute(Display * dpy, GLXDrawable drawable,
       } else if (attribute == GLX_MAX_SWAP_INTERVAL_EXT) {
          *value = INT_MAX;
          return 0;
+      } else if (attribute == GLX_LATE_SWAPS_TEAR_EXT) {
+         *value = __glXExtensionBitIsEnabled(pdraw->psc,
+                                             EXT_swap_control_tear_bit);
+         return 0;
       }
    }
 #endif
index 0a63244..a8c51cb 100644 (file)
@@ -1863,7 +1863,8 @@ glXSwapIntervalEXT(Display *dpy, GLXDrawable drawable, int interval)
       return;
    }
 
-   if (interval < 0) {
+   if (interval < 0 &&
+       !__glXExtensionBitIsEnabled(pdraw->psc, EXT_swap_control_tear_bit)) {
       __glXSendError(dpy, BadValue, interval, 0, True);
       return;
    }
index 1d65e68..f4d3807 100644 (file)
@@ -148,6 +148,7 @@ static const struct extension_info known_glx_extensions[] = {
    { GLX(EXT_framebuffer_sRGB),        VER(0,0), Y, Y, N, N },
    { GLX(EXT_import_context),          VER(0,0), Y, Y, N, N },
    { GLX(EXT_swap_control),            VER(0,0), Y, N, N, Y },
+   { GLX(EXT_swap_control_tear),       VER(0,0), Y, N, N, Y },
    { GLX(EXT_texture_from_pixmap),     VER(0,0), Y, N, N, N },
    { GLX(EXT_visual_info),             VER(0,0), Y, Y, N, N },
    { GLX(EXT_visual_rating),           VER(0,0), Y, Y, N, N },
index 446079e..29eb81e 100644 (file)
@@ -52,6 +52,7 @@ enum
    EXT_framebuffer_sRGB_bit,
    EXT_import_context_bit,
    EXT_swap_control_bit,
+   EXT_swap_control_tear_bit,
    EXT_texture_from_pixmap_bit,
    EXT_visual_info_bit,
    EXT_visual_rating_bit,
index cba3dfe..1984c20 100644 (file)
@@ -969,7 +969,7 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
        */
       ++draw->send_sbc;
       if (target_msc == 0 && divisor == 0 && remainder == 0)
-         target_msc = draw->msc + draw->swap_interval *
+         target_msc = draw->msc + abs(draw->swap_interval) *
                       (draw->send_sbc - draw->recv_sbc);
       else if (divisor == 0 && remainder > 0) {
          /* From the GLX_OML_sync_control spec:
@@ -989,11 +989,19 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
        *     "If <interval> is set to a value of 0, buffer swaps are not
        *      synchronized to a video frame."
        *
+       * From GLX_EXT_swap_control_tear:
+       *
+       *     "If <interval> is negative, the minimum number of video frames
+       *      between buffer swaps is the absolute value of <interval>. In this
+       *      case, if abs(<interval>) video frames have already passed from
+       *      the previous swap when the swap is ready to be performed, the
+       *      swap will occur without synchronization to a video frame."
+       *
        * Implementation note: It is possible to enable triple buffering
        * behaviour by not using XCB_PRESENT_OPTION_ASYNC, but this should not be
        * the default.
        */
-      if (draw->swap_interval == 0)
+      if (draw->swap_interval <= 0)
           options |= XCB_PRESENT_OPTION_ASYNC;
 
       /* If we need to populate the new back, but need to reuse the back