diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index 01d1d5ffc5b..5a1eb93be46 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -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 diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index 385791fcd6d..60b0c1c400f 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -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"); diff --git a/src/glx/glx_pbuffer.c b/src/glx/glx_pbuffer.c index ffc4f6c4648..8208c977c34 100644 --- a/src/glx/glx_pbuffer.c +++ b/src/glx/glx_pbuffer.c @@ -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 diff --git a/src/glx/glxcmds.c b/src/glx/glxcmds.c index 0a6324400c3..a8c51cbfec3 100644 --- a/src/glx/glxcmds.c +++ b/src/glx/glxcmds.c @@ -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; } diff --git a/src/glx/glxextensions.c b/src/glx/glxextensions.c index 1d65e680b81..f4d3807a810 100644 --- a/src/glx/glxextensions.c +++ b/src/glx/glxextensions.c @@ -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 }, diff --git a/src/glx/glxextensions.h b/src/glx/glxextensions.h index 446079e2c5f..29eb81ef177 100644 --- a/src/glx/glxextensions.h +++ b/src/glx/glxextensions.h @@ -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, diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index cba3dfe2695..1984c20c909 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -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 is set to a value of 0, buffer swaps are not * synchronized to a video frame." * + * From GLX_EXT_swap_control_tear: + * + * "If is negative, the minimum number of video frames + * between buffer swaps is the absolute value of . In this + * case, if abs() 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