diff options
author | Mario Kleiner <mario.kleiner@tuebingen.mpg.de> | 2010-11-23 04:41:53 +0100 |
---|---|---|
committer | Alex Deucher <alexdeucher@gmail.com> | 2010-12-01 20:30:42 -0500 |
commit | f48af8a6cfa1ac665f07b8f9712e94b77bc4f5e9 (patch) | |
tree | 92d0baf4f1f7b5f638dfd15629813b952fc11f81 /src/drmmode_display.c | |
parent | 122536ee0aeb1eef1a9d80d5e464dcb423dc2837 (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/drmmode_display.c')
-rw-r--r-- | src/drmmode_display.c | 42 |
1 files changed, 38 insertions, 4 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; } } |