summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2010-12-09 03:12:35 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-16 11:42:43 +0000
commit2177e6032146f4720f244e98f7c0d6df1b925784 (patch)
tree5413bb44147007f9024e292ec44073219e22b94e
parent71af40a75fbdd1054b1111e8cbe67ad1f97e6613 (diff)
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 = I830DRI2DrawablePipe(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. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/intel.h2
-rw-r--r--src/intel_display.c55
-rw-r--r--src/intel_dri.c5
3 files changed, 54 insertions, 8 deletions
diff --git a/src/intel.h b/src/intel.h
index dc88d747..8d31ac1e 100644
--- a/src/intel.h
+++ b/src/intel.h
@@ -503,7 +503,7 @@ extern int intel_output_dpms_status(xf86OutputPtr output);
extern Bool intel_do_pageflip(intel_screen_private *intel,
dri_bo *new_front,
- void *data);
+ void *data, int ref_crtc_hw_id);
static inline intel_screen_private *
intel_get_screen_private(ScrnInfoPtr scrn)
diff --git a/src/intel_display.c b/src/intel_display.c
index bb8d7085..11980135 100644
--- a/src/intel_display.c
+++ b/src/intel_display.c
@@ -53,11 +53,19 @@ struct intel_mode {
void *event_data;
int old_fb_id;
int flip_count;
+ unsigned int fe_frame;
+ unsigned int fe_tv_sec;
+ unsigned int fe_tv_usec;
struct list outputs;
struct list crtcs;
};
+struct intel_pageflip {
+ struct intel_mode *mode;
+ Bool dispatch_me;
+};
+
struct intel_crtc {
struct intel_mode *mode;
drmModeModeInfo kmode;
@@ -1416,13 +1424,14 @@ fail:
Bool
intel_do_pageflip(intel_screen_private *intel,
dri_bo *new_front,
- void *data)
+ void *data, int ref_crtc_hw_id)
{
ScrnInfoPtr scrn = intel->scrn;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
struct intel_crtc *crtc = config->crtc[0]->driver_private;
struct intel_mode *mode = crtc->mode;
unsigned int pitch = scrn->displayWidth * intel->cpp;
+ struct intel_pageflip *flip;
int i, old_fb_id;
/*
@@ -1443,18 +1452,39 @@ intel_do_pageflip(intel_screen_private *intel,
* Also, flips queued on disabled or incorrectly configured displays
* may never complete; this is a configuration error.
*/
+ mode->fe_frame = 0;
+ mode->fe_tv_sec = 0;
+ mode->fe_tv_usec = 0;
+
for (i = 0; i < config->num_crtc; i++) {
if (!config->crtc[i]->enabled)
continue;
mode->event_data = data;
mode->flip_count++;
+
+ crtc = config->crtc[i]->driver_private;
+
+ flip = calloc(1, sizeof(struct intel_pageflip));
+ if (flip == NULL) {
+ 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.
+ */
+ flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
+ flip->mode = mode;
+
if (drmModePageFlip(mode->fd,
- crtc_id(config->crtc[i]->driver_private),
+ crtc_id(crtc),
mode->fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, mode)) {
+ DRM_MODE_PAGE_FLIP_EVENT, flip)) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"flip queue failed: %s\n", strerror(errno));
+ free(flip);
goto error_undo;
}
}
@@ -1487,19 +1517,32 @@ static void
intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
- struct intel_mode *mode = event_data;
-
+ struct intel_pageflip *flip = event_data;
+ struct intel_mode *mode = flip->mode;
+
+ /* Is this the event whose info shall be delivered to higher level? */
+ if (flip->dispatch_me) {
+ /* Yes: Cache msc, ust for later delivery. */
+ mode->fe_frame = frame;
+ mode->fe_tv_sec = tv_sec;
+ mode->fe_tv_usec = tv_usec;
+ }
+ free(flip);
+ /* Last crtc completed flip? */
mode->flip_count--;
if (mode->flip_count > 0)
return;
+ /* Release framebuffer */
drmModeRmFB(mode->fd, mode->old_fb_id);
if (mode->event_data == NULL)
return;
- I830DRI2FlipEventHandler(frame, tv_sec, tv_usec, mode->event_data);
+ /* Deliver cached msc, ust from reference crtc to flip event handler */
+ I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec,
+ mode->fe_tv_usec, mode->event_data);
}
static void
diff --git a/src/intel_dri.c b/src/intel_dri.c
index 67f7be9d..e3835482 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -634,6 +634,9 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
I830DRI2BufferPrivatePtr back_priv;
DRI2FrameEventPtr flip_info;
+ /* Main crtc for this drawable shall finally deliver pageflip event. */
+ int ref_crtc_hw_id = I830DRI2DrawablePipe(draw);
+
flip_info = calloc(1, sizeof(DRI2FrameEventRec));
if (!flip_info)
return FALSE;
@@ -648,7 +651,7 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
back_priv = back->driverPrivate;
return intel_do_pageflip(intel,
intel_get_pixmap_bo(back_priv->pixmap),
- flip_info);
+ flip_info, ref_crtc_hw_id);
}
static Bool