diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2015-08-14 18:41:57 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2015-08-14 18:41:57 +0900 |
commit | 63948ea091a9b324327ade7ec4fc5d67ca7e6f6f (patch) | |
tree | 341df0e144510b3213ff109d2191fc2236ab4f55 /src/amdgpu_dri2.c | |
parent | 55a4461bd95698cb8d52f9f6c28583f8f81afb4e (diff) |
DRI2: Keep MSC monotonic when moving window between CRTCs
This mirrors the DRI3 implementation in xserver. Fixes VDPAU video
playback hanging when moving the window between CRTCs.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66384
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src/amdgpu_dri2.c')
-rw-r--r-- | src/amdgpu_dri2.c | 202 |
1 files changed, 134 insertions, 68 deletions
diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c index bbf286c..cdef3f2 100644 --- a/src/amdgpu_dri2.c +++ b/src/amdgpu_dri2.c @@ -65,6 +65,28 @@ struct dri2_buffer_priv { unsigned int refcnt; }; +struct dri2_window_priv { + xf86CrtcPtr crtc; + int vblank_delta; +}; + +#if HAS_DEVPRIVATEKEYREC + +static DevPrivateKeyRec dri2_window_private_key_rec; +#define dri2_window_private_key (&dri2_window_private_key_rec) + +#else + +static int dri2_window_private_key_index; +DevPrivateKey dri2_window_private_key = &dri2_window_private_key_index; + +#endif /* HAS_DEVPRIVATEKEYREC */ + +#define get_dri2_window_priv(window) \ + ((struct dri2_window_priv*) \ + dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key)) + + static PixmapPtr get_drawable_pixmap(DrawablePtr drawable) { if (drawable->type == DRAWABLE_PIXMAP) @@ -420,16 +442,80 @@ amdgpu_dri2_client_state_changed(CallbackListPtr * ClientStateCallback, } } +/* + * Get current frame count delta for the specified drawable and CRTC + */ +static uint32_t amdgpu_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (pDraw && pDraw->type == DRAWABLE_WINDOW) + return drmmode_crtc->interpolated_vblanks + + get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; + + return drmmode_crtc->interpolated_vblanks; +} + +/* + * Get current frame count and timestamp of the specified CRTC + */ +static Bool amdgpu_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) +{ + if (!amdgpu_crtc_is_enabled(crtc) || + drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { + /* CRTC is not running, extrapolate MSC and timestamp */ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + ScrnInfoPtr scrn = crtc->scrn; + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + CARD64 now, delta_t, delta_seq; + + if (!drmmode_crtc->dpms_last_ust) + return FALSE; + + if (drmmode_get_current_ust(info->dri2.drm_fd, &now) != 0) { + 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 += delta_seq; + } + + return TRUE; +} + static xf86CrtcPtr amdgpu_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + xf86CrtcPtr crtc = amdgpu_pick_best_crtc(pScrn, consider_disabled, + pDraw->x, pDraw->x + pDraw->width, + pDraw->y, pDraw->y + pDraw->height); + + if (crtc && pDraw->type == DRAWABLE_WINDOW) { + struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); + + if (priv->crtc && priv->crtc != crtc) { + CARD64 ust, mscold, mscnew; - return amdgpu_pick_best_crtc(pScrn, consider_disabled, - pDraw->x, - pDraw->x + pDraw->width, - pDraw->y, pDraw->y + pDraw->height); + amdgpu_dri2_get_crtc_msc(priv->crtc, &ust, &mscold); + amdgpu_dri2_get_crtc_msc(crtc, &ust, &mscnew); + priv->vblank_delta += mscold - mscnew; + } + + priv->crtc = crtc; + } + + return crtc; } static void @@ -456,7 +542,7 @@ amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, if (!flip->crtc) goto abort; - frame += amdgpu_get_interpolated_vblanks(flip->crtc); + frame += amdgpu_get_msc_delta(drawable, flip->crtc); screen = scrn->pScreen; pixmap = screen->GetScreenPixmap(screen); @@ -692,7 +778,7 @@ static void amdgpu_dri2_frame_event_handler(ScrnInfoPtr scrn, uint32_t seq, if (status != Success) goto cleanup; - seq += amdgpu_get_interpolated_vblanks(event->crtc); + seq += amdgpu_get_msc_delta(drawable, event->crtc); switch (event->type) { case DRI2_FLIP: @@ -782,8 +868,6 @@ CARD32 amdgpu_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; uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; - int interpolated_vblanks = drmmode_crtc->interpolated_vblanks; - int target_seq; CARD64 now, target_time, delta_t; int64_t d, delta_seq; int ret; @@ -800,16 +884,15 @@ CARD32 amdgpu_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 * target_msc, *target_msc = 0; return FALLBACK_SWAP_DELAY; } - target_seq = (int)*target_msc - interpolated_vblanks; - delta_seq = (int64_t) target_seq - (int64_t) last_vblank_seq; + delta_seq = *target_msc - last_vblank_seq; delta_seq *= 1000000; target_time = last_vblank_ust; target_time += delta_seq / nominal_frame_rate; d = target_time - now; if (d < 0) { /* we missed the event, adjust target_msc, do the divisor magic */ - CARD64 current_msc; - current_msc = last_vblank_seq + interpolated_vblanks; + CARD64 current_msc = last_vblank_seq; + delta_t = now - last_vblank_ust; delta_seq = delta_t * nominal_frame_rate; current_msc += delta_seq / 1000000; @@ -823,9 +906,7 @@ CARD32 amdgpu_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 * target_msc, if ((current_msc % divisor) >= remainder) *target_msc += divisor; *target_msc &= 0xffffffff; - target_seq = (int)*target_msc - interpolated_vblanks; - delta_seq = - (int64_t) target_seq - (int64_t) last_vblank_seq; + delta_seq = *target_msc - last_vblank_seq; delta_seq *= 1000000; target_time = last_vblank_ust; target_time += delta_seq / nominal_frame_rate; @@ -852,7 +933,6 @@ CARD32 amdgpu_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 * target_msc, static int amdgpu_dri2_get_msc(DrawablePtr draw, CARD64 * ust, CARD64 * msc) { xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE); - int ret; /* Drawable not displayed, make up a value */ if (crtc == NULL) { @@ -861,43 +941,12 @@ static int amdgpu_dri2_get_msc(DrawablePtr draw, CARD64 * ust, CARD64 * msc) return TRUE; } - if (amdgpu_crtc_is_enabled(crtc)) { - /* CRTC is running, read vblank counter and timestamp */ - ret = drmmode_crtc_get_ust_msc(crtc, ust, msc); - if (ret != Success) - return FALSE; - - *msc += amdgpu_get_interpolated_vblanks(crtc); - *msc &= 0xffffffff; - } else { - /* CRTC is not running, extrapolate MSC and timestamp */ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - ScrnInfoPtr scrn = crtc->scrn; - AMDGPUInfoPtr info = AMDGPUPTR(scrn); - 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 += drmmode_crtc->interpolated_vblanks; - *msc += delta_seq; - *msc &= 0xffffffff; - } + if (!amdgpu_dri2_get_crtc_msc(crtc, ust, msc)) + return FALSE; - return ret == Success; + *msc += amdgpu_get_msc_delta(draw, crtc); + *msc &= 0xffffffff; + return TRUE; } static @@ -985,6 +1034,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, DRI2FrameEventPtr wait_info = NULL; struct amdgpu_drm_queue_entry *wait = NULL; xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE); + uint32_t msc_delta; drmVBlank vbl; int ret; CARD64 current_msc; @@ -999,6 +1049,8 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, if (crtc == NULL) goto out_complete; + msc_delta = amdgpu_get_msc_delta(draw, crtc); + wait_info = calloc(1, sizeof(DRI2FrameEventRec)); if (!wait_info) goto out_complete; @@ -1014,6 +1066,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, */ if (!amdgpu_crtc_is_enabled(crtc)) { CARD32 delay; + target_msc -= msc_delta; delay = amdgpu_dri2_extrapolate_msc_delay(crtc, &target_msc, divisor, remainder); amdgpu_dri2_schedule_event(delay, wait_info); @@ -1032,8 +1085,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, goto out_complete; } - current_msc = - vbl.reply.sequence + amdgpu_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + msc_delta; current_msc &= 0xffffffff; wait = amdgpu_drm_queue_alloc(scrn, client, AMDGPU_DRM_QUEUE_ID_DEFAULT, @@ -1062,8 +1114,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, target_msc = current_msc; vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.type |= amdgpu_populate_vbl_request_type(crtc); - vbl.request.sequence = target_msc; - vbl.request.sequence -= amdgpu_get_interpolated_vblanks(crtc); + vbl.request.sequence = target_msc - msc_delta; vbl.request.signal = (unsigned long)wait; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { @@ -1085,7 +1136,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, vbl.request.type |= amdgpu_populate_vbl_request_type(crtc); vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; + remainder - msc_delta; /* * If calculated remainder is larger than requested remainder, @@ -1095,7 +1146,6 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, */ if ((current_msc % divisor) >= remainder) vbl.request.sequence += divisor; - vbl.request.sequence -= amdgpu_get_interpolated_vblanks(crtc); vbl.request.signal = (unsigned long)wait; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); @@ -1145,6 +1195,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, ScrnInfoPtr scrn = xf86ScreenToScrn(screen); AMDGPUInfoPtr info = AMDGPUPTR(scrn); xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE); + uint32_t msc_delta; drmVBlank vbl; int ret, flip = 0; DRI2FrameEventPtr swap_info = NULL; @@ -1170,6 +1221,8 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (crtc == NULL) goto blit_fallback; + msc_delta = amdgpu_get_msc_delta(draw, crtc); + swap_info = calloc(1, sizeof(DRI2FrameEventRec)); if (!swap_info) goto blit_fallback; @@ -1200,8 +1253,11 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, */ if (!amdgpu_crtc_is_enabled(crtc)) { CARD32 delay; + *target_msc -= msc_delta; delay = amdgpu_dri2_extrapolate_msc_delay(crtc, target_msc, divisor, remainder); + *target_msc += msc_delta; + *target_msc &= 0xffffffff; amdgpu_dri2_schedule_event(delay, swap_info); return TRUE; } @@ -1218,8 +1274,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, goto blit_fallback; } - current_msc = - vbl.reply.sequence + amdgpu_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + msc_delta; current_msc &= 0xffffffff; /* Flips need to be submitted one frame before */ @@ -1257,8 +1312,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (current_msc >= *target_msc) *target_msc = current_msc; - vbl.request.sequence = *target_msc; - vbl.request.sequence -= amdgpu_get_interpolated_vblanks(crtc); + vbl.request.sequence = *target_msc - msc_delta; vbl.request.signal = (unsigned long)swap; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { @@ -1268,8 +1322,8 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, goto blit_fallback; } - *target_msc = vbl.reply.sequence + flip; - *target_msc += amdgpu_get_interpolated_vblanks(crtc); + *target_msc = vbl.reply.sequence + flip + msc_delta; + *target_msc &= 0xffffffff; swap_info->frame = *target_msc; return TRUE; @@ -1286,7 +1340,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, vbl.request.type |= amdgpu_populate_vbl_request_type(crtc); vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; + remainder - msc_delta; /* * If the calculated deadline vbl.request.sequence is smaller than @@ -1301,7 +1355,6 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, */ if (vbl.request.sequence <= current_msc) vbl.request.sequence += divisor; - vbl.request.sequence -= amdgpu_get_interpolated_vblanks(crtc); /* Account for 1 frame extra pageflip delay if flip > 0 */ vbl.request.sequence -= flip; @@ -1316,8 +1369,8 @@ static int amdgpu_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 += amdgpu_get_interpolated_vblanks(crtc); + *target_msc = vbl.reply.sequence + flip + msc_delta; + *target_msc &= 0xffffffff; swap_info->frame = *target_msc; return TRUE; @@ -1400,6 +1453,19 @@ Bool amdgpu_dri2_screen_init(ScreenPtr pScreen) driverNames[0] = driverNames[1] = dri2_info.driverName; if (DRI2InfoCnt == 0) { +#if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(dri2_window_private_key, + PRIVATE_WINDOW, + sizeof(struct dri2_window_priv))) { +#else + if (!dixRequestPrivate(dri2_window_private_key, + sizeof(struct dri2_window_priv))) { +#endif + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to get DRI2 window private\n"); + return FALSE; + } + AddCallback(&ClientStateCallback, amdgpu_dri2_client_state_changed, 0); } |