This patch adds support for OML_sync_control compliant pageflip completion timestamping while triple-buffering is enabled and the ddx is running on Xorg server 1.12 or later. It makes use of the DRI2SwapLimit api to allow up to two pending flips without throttling of the client, then defers invocation of DRI2SwapComplete() until the corresponding pageflips actually complete, just as in the double-buffering case, allowing for proper timestamping and glXWaitForSbcOML() behaviour. This should not impact triple-buffering performance. On server versions <= 1.11 without swaplimit api, triple-buffering is achieved by sacrificing OML_sync_control compliance, as in the old implementation. Tested against server without swaplimit api and 1.13 with swaplimit api, both with and without triplebuffering enabled. Signed-off-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de> --- src/intel_dri.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/src/intel_dri.c b/src/intel_dri.c index 64cb567..126acb2 100644 --- a/src/intel_dri.c +++ b/src/intel_dri.c @@ -310,6 +310,15 @@ I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, drawable = &(get_drawable_pixmap(drawable)->drawable); is_glamor_pixmap = TRUE; } + +#if DRI2INFOREC_VERSION >= 6 + /* If swaplimit api supported, use it to tell server we are + * triple-buffering capable. This allows triple-buffering + * without need for hacks which compromise time-stamping. + */ + if (drawable->type == DRAWABLE_WINDOW) + DRI2SwapLimit(drawable, intel->use_triple_buffer ? 2 : 1); +#endif } if (pixmap == NULL) { @@ -815,6 +824,20 @@ static drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) return bo; } +#if DRI2INFOREC_VERSION >= 6 +static Bool +I830DRI2SwapLimitValidate(DrawablePtr draw, int swap_limit) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(draw->pScreen); + struct intel_screen_private *intel = intel_get_screen_private(pScrn); + + if ((swap_limit < 1 ) || (swap_limit > (intel->use_triple_buffer ? 2 : 1))) + return FALSE; + + return TRUE; +} +#endif + /* * Our internal swap routine takes care of actually exchanging, blitting, or * flipping buffers as necessary. @@ -914,10 +937,17 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel, /* Then flip DRI2 pointers and update the screen pixmap */ I830DRI2ExchangeBuffers(intel, info->front, info->back); + +#if DRI2INFOREC_VERSION < 6 + /* Only needed on Xorg <= 1.11 server, which doesn't have swaplimit + * api to do this cleanly. Breaks OML_sync_control timestamping. + */ DRI2SwapComplete(info->client, draw, 0, 0, 0, DRI2_EXCHANGE_COMPLETE, info->event_complete, info->event_data); +#endif + return TRUE; } @@ -1041,14 +1071,22 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, M_ANY, DixWriteAccess); - - /* We assume our flips arrive in order, so we don't check the frame */ - switch (flip_info->type) { - case DRI2_SWAP: - if (!drawable) - break; - - /* Check for too small vblank count of pageflip completion, taking wraparound + /* Perform consistency check, final timestamping and swap completion here iff: + * - This is a pageflip completion for a classic double-buffered swap. + * - This is a pageflip completion for a triple-buffered swap and the XOrg 1.12+ + * server supports the swap limit api, so we were able to defer swap completion + * until this point without negative impact on performance. + * + * -> This allows OML_sync_control spec compliant timestamping. + * + * On older servers we already mark the swap as completed ahead of its completion in + * I830DRI2ScheduleFlip to allow triple-buffering at the cost of broken timestamping. + */ + if (drawable && ((flip_info->type == DRI2_SWAP) || + ((DRI2INFOREC_VERSION >= 6) && (flip_info->type == DRI2_SWAP_CHAIN)))) { + /* We assume our flips arrive in order, so we don't check the frame. + * + * Check for too small vblank count of pageflip completion, taking wraparound * into account. This usually means some defective kms pageflip completion, * causing wrong (msc, ust) return values and possible visual corruption. */ @@ -1072,6 +1110,11 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, flip_info->event_data); + } + + switch (flip_info->type) { + case DRI2_SWAP: + /* All completion work for double-buffered swaps already done above. */ break; case DRI2_SWAP_CHAIN: @@ -1596,6 +1639,14 @@ Bool I830DRI2ScreenInit(ScreenPtr screen) driverNames[0] = info.driverName; #endif +#if DRI2INFOREC_VERSION >= 6 + info.version = 6; + info.SwapLimitValidate = I830DRI2SwapLimitValidate; + /* Server has fallbacks for these undefined ones for v5 and v6: */ + info.AuthMagic = NULL; + info.ReuseBufferNotify = NULL; +#endif + return DRI2ScreenInit(screen, &info); } -- 1.7.10.4