summaryrefslogtreecommitdiff
path: root/src/radeon_dri2.c
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2010-11-23 04:41:53 +0100
committerAlex Deucher <alexdeucher@gmail.com>2010-12-01 20:30:42 -0500
commitf48af8a6cfa1ac665f07b8f9712e94b77bc4f5e9 (patch)
tree92d0baf4f1f7b5f638dfd15629813b952fc11f81 /src/radeon_dri2.c
parent122536ee0aeb1eef1a9d80d5e464dcb423dc2837 (diff)
ddx/ati: Fix reporting of pageflip completion events on multi-head.
When a drawable is page-flipped on multiple crtc's (fullscreen drawable on mirror-mode or multi-head x-screen), only one pageflip event is finally delivered, after the last participating crtc signals flip completion, this to avoid visual corruption. Old code returned vblank count and timestamps of flip completion of this last crtc, instead of the values of the "master crtc", the one that was used for initially scheduling/triggering the pagflip via vblank events. (master = radeon_dri2_drawable_crtc(drawable)) This patch makes sure that the pageflip completion values of the "master" crtc are returned, otherwise client applications will get confused by the random (msc, ust) values returned by whichever crtc was the last to complete its flip. Without this, the returned values change randomly and jump forward and backward in time and count. The patch also implements a consistency check on returned vblank count values of pageflip completion. Impossible values are detected, a x-warning is logged and returned (msc,ust) values are marked invalid, so clients could perform error handling. Such a warning would indicate bugs in the pageflip completion routine of future kms drivers or the ddx to aid driver debugging. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Diffstat (limited to 'src/radeon_dri2.c')
-rw-r--r--src/radeon_dri2.c58
1 files changed, 37 insertions, 21 deletions
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index c28017cd..8b12872a 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -571,6 +571,26 @@ radeon_dri2_unref_buffer(BufferPtr buffer)
}
}
+static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ xf86CrtcPtr crtc;
+ int crtc_id = -1;
+
+ crtc = radeon_pick_best_crtc(pScrn,
+ pDraw->x,
+ pDraw->x + pDraw->width,
+ pDraw->y,
+ pDraw->y + pDraw->height);
+
+ /* Make sure the CRTC is valid and this is the real front buffer */
+ if (crtc != NULL && !crtc->rotatedData) {
+ crtc_id = drmmode_get_crtc_id(crtc);
+ }
+ return crtc_id;
+}
+
static Bool
radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
DrawablePtr draw, DRI2BufferPtr front,
@@ -581,6 +601,9 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
struct radeon_exa_pixmap_priv *exa_priv;
DRI2FrameEventPtr flip_info;
+ /* Main crtc for this drawable shall finally deliver pageflip event. */
+ int ref_crtc_hw_id = radeon_dri2_drawable_crtc(draw);
+
flip_info = calloc(1, sizeof(DRI2FrameEventRec));
if (!flip_info)
return FALSE;
@@ -596,7 +619,8 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
/* Page flip the full screen buffer */
back_priv = back->driverPrivate;
exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
- return radeon_do_pageflip(scrn, exa_priv->bo, flip_info);
+
+ return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id);
}
static Bool
@@ -735,26 +759,6 @@ cleanup:
free(event);
}
-static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
-{
- ScreenPtr pScreen = pDraw->pScreen;
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- xf86CrtcPtr crtc;
- int crtc_id = -1;
-
- crtc = radeon_pick_best_crtc(pScrn,
- pDraw->x,
- pDraw->x + pDraw->width,
- pDraw->y,
- pDraw->y + pDraw->height);
-
- /* Make sure the CRTC is valid and this is the real front buffer */
- if (crtc != NULL && !crtc->rotatedData) {
- crtc_id = drmmode_get_crtc_id(crtc);
- }
- return crtc_id;
-}
-
/*
* Get current frame count and frame count timestamp, based on drawable's
* crtc.
@@ -952,6 +956,18 @@ void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
/* We assume our flips arrive in order, so we don't check the frame */
switch (flip->type) {
case DRI2_SWAP:
+ /* 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.
+ */
+ if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "%s: Pageflip completion event has impossible msc %d < target_msc %d\n",
+ __func__, frame, flip->frame);
+ /* All-Zero values signal failure of (msc, ust) timestamping to client. */
+ frame = tv_sec = tv_usec = 0;
+ }
+
DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
DRI2_FLIP_COMPLETE, flip->event_complete,
flip->event_data);