diff options
author | Mario Kleiner <mario.kleiner@tuebingen.mpg.de> | 2010-12-09 03:12:35 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-12-16 11:42:43 +0000 |
commit | 2177e6032146f4720f244e98f7c0d6df1b925784 (patch) | |
tree | 5413bb44147007f9024e292ec44073219e22b94e | |
parent | 71af40a75fbdd1054b1111e8cbe67ad1f97e6613 (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.h | 2 | ||||
-rw-r--r-- | src/intel_display.c | 55 | ||||
-rw-r--r-- | src/intel_dri.c | 5 |
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 |