diff options
author | Mario Kleiner <mario.kleiner@tuebingen.mpg.de> | 2010-03-05 12:32:18 -0800 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-03-05 12:52:47 -0800 |
commit | 1cd556420277f103c47ade422f3ec8f8efb2d282 (patch) | |
tree | eb1f384070f3073a20c847f4f0348489f76866a3 /src/i830_dri.c | |
parent | 13119ffc034a3e9d6c76339d4fedc62bb3b41257 (diff) |
DRI2: handle target_msc, divisor and remainder properly in DRI2ScheduleSwap
The current code in I830DRI2ScheduleSwap() only schedules the correct
vblank events for the case divisor == 0, i.e., the simple
glXSwapBuffers() case.
In a glXSwapBuffersMscOML() request, divisor can be > 0, which would go
wrong.
This modified code should handle target_msc, divisor, remainder and the
different cases defined in the OML_sync_control extension correctly for
the divisor > 0 case.
It also tries to make sure that the effective framecount of swap
satisfies all constraints, taking the 1 frame delay in pageflipping mode
and possible delays in blitting/exchange mode due to
DRM_VBLANK_NEXTONMISS into account.
The swap_interval logic in the X-Servers DRI2SwapBuffers() call expects
the returned swap_target from the DDX to be reasonably accurate,
otherwise implementation of swap_interval for the glXSwapBuffers() as
defined in the SGI_swap_interval extension may become unreliable.
For non-pageflipped mode, the returned swap_target is always correct due
to the adjustments done by drmWaitVBlank(), as DRM_VBLANK_NEXTONMISS is
set.
In pageflipped mode, DRM_VBLANK_NEXTONMISS can't be used without severe
impact on performance, so the code in I830DRI2ScheduleSwap() must make
manual adjustments to the returned vbl.reply.sequence number.
This patch adds the needed adjustments.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Diffstat (limited to 'src/i830_dri.c')
-rw-r--r-- | src/i830_dri.c | 87 |
1 files changed, 53 insertions, 34 deletions
diff --git a/src/i830_dri.c b/src/i830_dri.c index 002f119b..96d41e71 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -641,6 +641,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0; DRI2FrameEventPtr swap_info; enum DRI2FrameEventType swap_type = DRI2_SWAP; + CARD64 current_msc; BoxRec box; RegionRec region; @@ -670,6 +671,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, goto blit_fallback; } + current_msc = vbl.reply.sequence; + /* Flips need to be submitted one frame before */ if (DRI2CanFlip(draw) && !intel->shadow_present && intel->use_pageflipping) { @@ -679,6 +682,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, swap_info->type = swap_type; + /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. + * Do it early, so handling of different timing constraints + * for divisor, remainder and msc vs. target_msc works. + */ + if (*target_msc > 0) + *target_msc -= flip; + if ((*target_msc != 1) && (*target_msc > vbl.reply.sequence) && ((*target_msc - vbl.reply.sequence) > 100)) xf86DrvMsg(scrn->scrnIndex, X_WARNING, @@ -687,17 +697,32 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, (unsigned long)*target_msc); /* - * If divisor is zero, we just need to make sure target_msc passes - * before waking up the client. + * If divisor is zero, or current_msc is smaller than target_msc + * we just need to make sure target_msc passes before initiating + * the swap. */ - if (divisor == 0) { - vbl.request.type = DRM_VBLANK_NEXTONMISS | - DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + if (divisor == 0 || current_msc < *target_msc) { + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; if (pipe > 0) vbl.request.type |= DRM_VBLANK_SECONDARY; + /* If non-pageflipping, but blitting/exchanging, we need to use + * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later + * on. + */ + if (flip == 0) + vbl.request.type |= DRM_VBLANK_NEXTONMISS; + if (pipe > 0) + vbl.request.type |= DRM_VBLANK_SECONDARY; + + /* If target_msc already reached or passed, set it to + * current_msc to ensure we return a reasonable value back + * to the caller. This makes swap_interval logic more robust. + */ + if (current_msc >= *target_msc) + *target_msc = current_msc; + vbl.request.sequence = *target_msc; - vbl.request.sequence -= flip; vbl.request.signal = (unsigned long)swap_info; ret = drmWaitVBlank(intel->drmSubFD, &vbl); if (ret) { @@ -707,7 +732,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, goto blit_fallback; } - *target_msc = vbl.reply.sequence; + *target_msc = vbl.reply.sequence + flip; swap_info->frame = *target_msc; return TRUE; @@ -715,42 +740,35 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, /* * If we get here, target_msc has already passed or we don't have one, - * so we queue an event that will satisfy the divisor/remainderequation. + * and we need to queue an event that will satisfy the divisor/remainder + * equation. */ - if ((vbl.reply.sequence % divisor) == remainder) { - BoxRec box; - RegionRec region; - - box.x1 = 0; - box.y1 = 0; - box.x2 = draw->width; - box.y2 = draw->height; - REGION_INIT(pScreen, ®ion, &box, 0); - - I830DRI2CopyRegion(draw, ®ion, front, back); - - DRI2SwapComplete(client, draw, 0, 0, 0, - DRI2_BLIT_COMPLETE, func, data); - if (swap_info) - xfree(swap_info); - return TRUE; - } - vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + if (flip == 0) + vbl.request.type |= DRM_VBLANK_NEXTONMISS; if (pipe > 0) vbl.request.type |= DRM_VBLANK_SECONDARY; + vbl.request.sequence = current_msc - (current_msc % divisor) + + remainder; + /* - * If we have no remainder, and the test above failed, it means we've - * passed the last point where seq % divisor == remainder, so we need - * to wait for the next time that will happen. + * If the calculated deadline vbl.request.sequence is smaller than + * or equal to current_msc, it means we've passed the last point + * when effective onset frame seq could satisfy + * seq % divisor == remainder, so we need to wait for the next time + * this will happen. + + * This comparison takes the 1 frame swap delay in pageflipping mode + * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay + * if we are blitting/exchanging instead of flipping. */ - if (!remainder) + if (vbl.request.sequence <= current_msc) vbl.request.sequence += divisor; - vbl.request.sequence = vbl.reply.sequence - - (vbl.reply.sequence % divisor) + remainder; + /* Account for 1 frame extra pageflip delay if flip > 0 */ vbl.request.sequence -= flip; + vbl.request.signal = (unsigned long)swap_info; ret = drmWaitVBlank(intel->drmSubFD, &vbl); if (ret) { @@ -760,7 +778,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, goto blit_fallback; } - *target_msc = vbl.reply.sequence; + /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ + *target_msc = vbl.reply.sequence + flip; swap_info->frame = *target_msc; return TRUE; |