From b6e0b92f398823629ba8a1ea8f5e62fbf959e725 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 4 Mar 2010 10:07:26 -0800 Subject: DRI2: handle offscreen drawables better at swap time If a drawable isn't visible due to DPMS or redirection, we'll just blit it rather than schedule a swap event. However, we didn't reset the target_msc, so the swap target we receive from the server could get out of sync with the vblank count of the drawable's display. So at DPMS on time, the swap target would be the last good vblank count plus some large number (since the swaps won't have been throttled). Solve this by zeroing out the swap target like we should when we fall back to a blit. Also make the kernel error cases more friendly by making them fall back to blits too. Signed-off-by: Jesse Barnes --- src/i830_dri.c | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/i830_dri.c b/src/i830_dri.c index 64aeb762..0738cdb9 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -641,28 +641,14 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0; DRI2FrameEventPtr swap_info; enum DRI2FrameEventType swap_type = DRI2_SWAP; + BoxRec box; + RegionRec region; swap_info = xcalloc(1, sizeof(DRI2FrameEventRec)); /* Drawable not displayed... just complete the swap */ - if (pipe == -1 || !swap_info) { - 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; - } + if (pipe == -1 || !swap_info) + goto blit_fallback; swap_info->drawable_id = draw->id; swap_info->client = client; @@ -681,7 +667,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "first get vblank counter failed: %s\n", strerror(errno)); - return FALSE; + goto blit_fallback; } /* Flips need to be submitted one frame before */ @@ -693,6 +679,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, swap_info->type = swap_type; + if ((*target_msc != 1) && (*target_msc > vbl.reply.sequence) && + ((*target_msc - vbl.reply.sequence) > 100)) + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "vblank event >100 frames away: cur %ld, target %ld\n", + (unsigned long)vbl.reply.sequence, + (unsigned long)*target_msc); + /* * If divisor is zero, we just need to make sure target_msc passes * before waking up the client. @@ -711,7 +704,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "divisor 0 get vblank counter failed: %s\n", strerror(errno)); - return FALSE; + goto blit_fallback; } *target_msc = vbl.reply.sequence; @@ -764,13 +757,28 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "final get vblank counter failed: %s\n", strerror(errno)); - return FALSE; + goto blit_fallback; } *target_msc = vbl.reply.sequence; swap_info->frame = *target_msc; return TRUE; + +blit_fallback: + 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); + *target_msc = 0; /* offscreen, so zero out target vblank count */ + return TRUE; } /* -- cgit v1.2.3