commit 9d25327cbf58d217b4ba844f35ad4b41698d10f0 Author: Michel Dänzer Date: Fri Jul 12 17:42:29 2013 +0200 DRI2: Keep MSC consistent per window diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index fa3719d..846f43f 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -518,21 +518,35 @@ typedef struct _DRI2ClientEvents { struct xorg_list reference_list; } DRI2ClientEventsRec, *DRI2ClientEventsPtr; +typedef struct _DRI2Window { + xf86CrtcPtr crtc; + int vblank_delta; +} DRI2WindowRec, *DRI2WindowPtr; + #if HAS_DEVPRIVATEKEYREC static DevPrivateKeyRec DRI2ClientEventsPrivateKeyRec; #define DRI2ClientEventsPrivateKey (&DRI2ClientEventsPrivateKeyRec) +static DevPrivateKeyRec DRI2WindowPrivateKeyRec; +#define DRI2WindowPrivateKey (&DRI2WindowPrivateKeyRec) + #else static int DRI2ClientEventsPrivateKeyIndex; DevPrivateKey DRI2ClientEventsPrivateKey = &DRI2ClientEventsPrivateKeyIndex; +static int DRI2WindowPrivateKeyIndex; +DevPrivateKey DRI2WindowPrivateKey = &DRI2WindowPrivateKeyIndex; + #endif /* HAS_DEVPRIVATEKEYREC */ #define GetDRI2ClientEvents(pClient) ((DRI2ClientEventsPtr) \ dixLookupPrivate(&(pClient)->devPrivates, DRI2ClientEventsPrivateKey)) +#define GetDRI2Window(pClient) ((DRI2WindowPtr) \ + dixLookupPrivate(&(pClient)->devPrivates, DRI2WindowPrivateKey)) + static int ListAddDRI2ClientEvents(ClientPtr client, struct xorg_list *entry) { @@ -606,6 +620,75 @@ radeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer d } } +/* + * Get current frame count, based on drawable's crtc. + */ +static uint32_t radeon_get_drawable_vblanks(DrawablePtr pDraw, xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (pDraw->type == DRAWABLE_WINDOW) { + DRI2WindowPtr pWindowPriv = GetDRI2Window((WindowPtr)pDraw); + return drmmode_crtc->interpolated_vblanks + pWindowPriv->vblank_delta; + } + + return drmmode_crtc->interpolated_vblanks; +} + +/* + * Get current frame count and frame count timestamp of the specified crtc. + */ +static int radeon_dri2_get_crtc_msc(ScrnInfoPtr scrn, xf86CrtcPtr crtc, + CARD64 *ust, CARD64 *msc) +{ + RADEONInfoPtr info = RADEONPTR(scrn); + drmVBlank vbl; + int ret; + + if (radeon_crtc_is_enabled(crtc)) { + /* CRTC is running, read vblank counter and timestamp */ + vbl.request.type = DRM_VBLANK_RELATIVE; + vbl.request.type |= radeon_populate_vbl_request_type(crtc); + vbl.request.sequence = 0; + + ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "get vblank counter failed: %s\n", strerror(errno)); + return FALSE; + } + + *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; + *msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); + *msc &= 0xffffffff; + } else { + /* CRTC is not running, extrapolate MSC and timestamp */ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + CARD64 now, delta_t, delta_seq; + + if (!drmmode_crtc->dpms_last_ust) + return FALSE; + ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "%s cannot get current time\n", __func__); + return FALSE; + } + delta_t = now - drmmode_crtc->dpms_last_ust; + delta_seq = delta_t * drmmode_crtc->dpms_last_fps; + delta_seq /= 1000000; + *ust = drmmode_crtc->dpms_last_ust; + delta_t = delta_seq * 1000000; + delta_t /= drmmode_crtc->dpms_last_fps; + *ust += delta_t; + *msc = drmmode_crtc->dpms_last_seq; + *msc += radeon_get_interpolated_vblanks(crtc); + *msc += delta_seq; + *msc &= 0xffffffff; + } + return TRUE; +} + static xf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) { @@ -620,10 +703,27 @@ xf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) pDraw->y + pDraw->height); /* Make sure the CRTC is valid and this is the real front buffer */ - if (crtc != NULL && !crtc->rotatedData) + if (crtc != NULL && !crtc->rotatedData) { + if (pDraw->type == DRAWABLE_WINDOW) { + DRI2WindowPtr pWindowPriv = GetDRI2Window((WindowPtr)pDraw); + + if (pWindowPriv->crtc && pWindowPriv->crtc != crtc) { + CARD64 ust, mscold, mscnew; + + ErrorF("drawable %p delta before: %d\n", pDraw, pWindowPriv->vblank_delta); + radeon_dri2_get_crtc_msc(pScrn, pWindowPriv->crtc, &ust, &mscold); + radeon_dri2_get_crtc_msc(pScrn, crtc, &ust, &mscnew); + pWindowPriv->vblank_delta += mscold - mscnew; + ErrorF("drawable %p delta after: %d\n", pDraw, pWindowPriv->vblank_delta); + } + + pWindowPriv->crtc = crtc; + } + return crtc; - else - return NULL; + } + + return NULL; } static Bool @@ -894,7 +994,7 @@ CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, int nominal_frame_rate = drmmode_crtc->dpms_last_fps; CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; int last_vblank_seq = drmmode_crtc->dpms_last_seq; - int interpolated_vblanks = drmmode_crtc->interpolated_vblanks; + int interpolated_vblanks = radeon_get_interpolated_vblanks(crtc); int target_seq; CARD64 now, target_time, delta_t; int64_t d, delta_seq; @@ -963,8 +1063,6 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) { ScreenPtr screen = draw->pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - RADEONInfoPtr info = RADEONPTR(scrn); - drmVBlank vbl; int ret; xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); @@ -974,48 +1072,15 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) *msc = 0; return TRUE; } - if (radeon_crtc_is_enabled(crtc)) { - /* CRTC is running, read vblank counter and timestamp */ - vbl.request.type = DRM_VBLANK_RELATIVE; - vbl.request.type |= radeon_populate_vbl_request_type(crtc); - vbl.request.sequence = 0; - ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "get vblank counter failed: %s\n", strerror(errno)); - return FALSE; - } - - *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; - *msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); - *msc &= 0xffffffff; - } else { - /* CRTC is not running, extrapolate MSC and timestamp */ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - CARD64 now, delta_t, delta_seq; + ret = radeon_dri2_get_crtc_msc(scrn, crtc, ust, msc); - if (!drmmode_crtc->dpms_last_ust) - return FALSE; - ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "%s cannot get current time\n", __func__); - return FALSE; - } - delta_t = now - drmmode_crtc->dpms_last_ust; - delta_seq = delta_t * drmmode_crtc->dpms_last_fps; - delta_seq /= 1000000; - *ust = drmmode_crtc->dpms_last_ust; - delta_t = delta_seq * 1000000; - delta_t /= drmmode_crtc->dpms_last_fps; - *ust += delta_t; - *msc = drmmode_crtc->dpms_last_seq; - *msc += drmmode_crtc->interpolated_vblanks; - *msc += delta_seq; - *msc &= 0xffffffff; + if (draw->type == DRAWABLE_WINDOW) { + DRI2WindowPtr pWindowPriv = GetDRI2Window((WindowPtr)draw); + *msc += pWindowPriv->vblank_delta; } - return TRUE; + + return ret; } static @@ -1163,7 +1228,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, goto out_complete; } - current_msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + radeon_get_drawable_vblanks(draw, crtc); current_msc &= 0xffffffff; /* @@ -1183,7 +1248,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.type |= radeon_populate_vbl_request_type(crtc); vbl.request.sequence = target_msc; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); + vbl.request.sequence -= radeon_get_drawable_vblanks(draw, crtc); vbl.request.signal = (unsigned long)wait_info; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { @@ -1193,7 +1258,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, } wait_info->frame = vbl.reply.sequence; - wait_info->frame += radeon_get_interpolated_vblanks(crtc); + wait_info->frame += radeon_get_drawable_vblanks(draw, crtc); DRI2BlockClient(client, draw); return TRUE; } @@ -1216,7 +1281,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, */ if ((current_msc % divisor) >= remainder) vbl.request.sequence += divisor; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); + vbl.request.sequence -= radeon_get_drawable_vblanks(draw, crtc); vbl.request.signal = (unsigned long)wait_info; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); @@ -1227,7 +1292,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, } wait_info->frame = vbl.reply.sequence; - wait_info->frame += radeon_get_interpolated_vblanks(crtc); + wait_info->frame += radeon_get_drawable_vblanks(draw, crtc); DRI2BlockClient(client, draw); return TRUE; @@ -1261,7 +1326,7 @@ void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, free(flip); return; } - frame += radeon_get_interpolated_vblanks(flip->crtc); + frame += radeon_get_drawable_vblanks(drawable, flip->crtc); screen = drawable->pScreen; scrn = xf86ScreenToScrn(screen); @@ -1402,7 +1467,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, return TRUE; } - current_msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + radeon_get_drawable_vblanks(draw, crtc); current_msc &= 0xffffffff; /* Flips need to be submitted one frame before */ @@ -1443,7 +1508,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, *target_msc = current_msc; vbl.request.sequence = *target_msc; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); + vbl.request.sequence -= radeon_get_drawable_vblanks(draw, crtc); vbl.request.signal = (unsigned long)swap_info; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { @@ -1456,7 +1521,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, } *target_msc = vbl.reply.sequence + flip; - *target_msc += radeon_get_interpolated_vblanks(crtc); + *target_msc += radeon_get_drawable_vblanks(draw, crtc); swap_info->frame = *target_msc; return TRUE; @@ -1488,7 +1553,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, */ if (vbl.request.sequence <= current_msc) vbl.request.sequence += divisor; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); + vbl.request.sequence -= radeon_get_drawable_vblanks(draw, crtc); /* Account for 1 frame extra pageflip delay if flip > 0 */ vbl.request.sequence -= flip; @@ -1506,7 +1571,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ *target_msc = vbl.reply.sequence + flip; - *target_msc += radeon_get_interpolated_vblanks(crtc); + *target_msc += radeon_get_drawable_vblanks(draw, crtc); swap_info->frame = *target_msc; return TRUE; @@ -1609,6 +1674,18 @@ radeon_dri2_screen_init(ScreenPtr pScreen) if (pRADEONEnt->dri2_info_cnt == 0) { #if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(DRI2WindowPrivateKey, + PRIVATE_WINDOW, sizeof(DRI2WindowRec))) { +#else + if (!dixRequestPrivate(DRI2WindowPrivateKey, + sizeof(DRI2WindowRec))) { +#endif + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requesting " + "private key to window failed\n"); + return FALSE; + } + +#if HAS_DIXREGISTERPRIVATEKEY if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey, PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 registering "