summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drmmode_display.c42
-rw-r--r--src/drmmode_display.h10
-rw-r--r--src/radeon_dri2.c58
3 files changed, 84 insertions, 26 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 1310da7c..9248cb0e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1284,18 +1284,32 @@ static void
drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
- drmmode_ptr drmmode = event_data;
+ drmmode_flipevtcarrier_ptr flipcarrier = event_data;
+ drmmode_ptr drmmode = flipcarrier->drmmode;
+
+ /* Is this the event whose info shall be delivered to higher level? */
+ if (flipcarrier->dispatch_me) {
+ /* Yes: Cache msc, ust for later delivery. */
+ drmmode->fe_frame = frame;
+ drmmode->fe_tv_sec = tv_sec;
+ drmmode->fe_tv_usec = tv_usec;
+ }
+ free(flipcarrier);
+ /* Last crtc completed flip? */
drmmode->flip_count--;
if (drmmode->flip_count > 0)
return;
+ /* Release framebuffer */
drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
if (drmmode->event_data == NULL)
return;
- radeon_dri2_flip_event_handler(frame, tv_sec, tv_usec, drmmode->event_data);
+ /* Deliver cached msc, ust from reference crtc to flip event handler */
+ radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec,
+ drmmode->fe_tv_usec, drmmode->event_data);
}
@@ -1584,7 +1598,7 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
#endif
}
-Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data)
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
{
RADEONInfoPtr info = RADEONPTR(scrn);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1594,6 +1608,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
int i, old_fb_id;
uint32_t tiling_flags = 0;
int height;
+ drmmode_flipevtcarrier_ptr flipcarrier;
if (info->allowColorTiling) {
if (info->ChipFamily >= CHIP_FAMILY_R600)
@@ -1623,6 +1638,10 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
* Also, flips queued on disabled or incorrectly configured displays
* may never complete; this is a configuration error.
*/
+ drmmode->fe_frame = 0;
+ drmmode->fe_tv_sec = 0;
+ drmmode->fe_tv_usec = 0;
+
for (i = 0; i < config->num_crtc; i++) {
if (!config->crtc[i]->enabled)
continue;
@@ -1630,10 +1649,25 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat
drmmode->event_data = data;
drmmode->flip_count++;
drmmode_crtc = config->crtc[i]->driver_private;
+
+ flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
+ if (!flipcarrier) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue: carrier alloc failed.\n");
+ goto error_undo;
+ }
+
+ /* Only the reference crtc will finally deliver its page flip
+ * completion event. All other crtc's events will be discarded.
+ */
+ flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
+ flipcarrier->drmmode = drmmode;
+
if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
- drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, drmmode)) {
+ drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"flip queue failed: %s\n", strerror(errno));
+ free(flipcarrier);
goto error_undo;
}
}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index c3d3561f..548907bb 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -52,9 +52,17 @@ typedef struct {
drmEventContext event_context;
int flip_count;
void *event_data;
+ unsigned int fe_frame;
+ unsigned int fe_tv_sec;
+ unsigned int fe_tv_usec;
} drmmode_rec, *drmmode_ptr;
typedef struct {
+ drmmode_ptr drmmode;
+ Bool dispatch_me;
+} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
+
+typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
int hw_id;
@@ -101,7 +109,7 @@ extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling);
extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
-Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data);
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id);
#endif
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);