diff options
-rw-r--r-- | src/uxa/intel.h | 9 | ||||
-rw-r--r-- | src/uxa/intel_display.c | 118 | ||||
-rw-r--r-- | src/uxa/intel_dri.c | 125 |
3 files changed, 156 insertions, 96 deletions
diff --git a/src/uxa/intel.h b/src/uxa/intel.h index 6ac770e3..f5b3611d 100644 --- a/src/uxa/intel.h +++ b/src/uxa/intel.h @@ -403,6 +403,15 @@ extern int intel_crtc_id(xf86CrtcPtr crtc); extern int intel_output_dpms_status(xf86OutputPtr output); extern void intel_copy_fb(ScrnInfoPtr scrn); +int +intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust); + +uint32_t +intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect); + +uint64_t +intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence); + enum DRI2FrameEventType { DRI2_SWAP, DRI2_SWAP_CHAIN, diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c index 39d85071..bb327a91 100644 --- a/src/uxa/intel_display.c +++ b/src/uxa/intel_display.c @@ -70,9 +70,8 @@ struct intel_mode { DRI2FrameEventPtr flip_info; int old_fb_id; int flip_count; - unsigned int fe_frame; - unsigned int fe_tv_sec; - unsigned int fe_tv_usec; + uint64_t fe_msc; + uint64_t fe_usec; struct list outputs; struct list crtcs; @@ -96,6 +95,9 @@ struct intel_crtc { struct list link; PixmapPtr scanout_pixmap; uint32_t scanout_fb_id; + int32_t vblank_offset; + uint32_t msc_prev; + uint64_t msc_high; }; struct intel_property { @@ -1646,9 +1648,8 @@ 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; + mode->fe_msc = 0; + mode->fe_usec = 0; for (i = 0; i < config->num_crtc; i++) { if (!intel_crtc_on(config->crtc[i])) @@ -1704,6 +1705,102 @@ static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = { intel_xf86crtc_resize }; +static uint32_t pipe_select(int pipe) +{ + if (pipe > 1) + return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; + else if (pipe > 0) + return DRM_VBLANK_SECONDARY; + else + return 0; +} + +/* + * Get the current msc/ust value from the kernel + */ +static int +intel_get_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint32_t *msc, uint64_t *ust) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + drmVBlank vbl; + int ret; + + /* Get current count */ + vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(intel_crtc_to_pipe(crtc)); + vbl.request.sequence = 0; + vbl.request.signal = 0; + ret = drmWaitVBlank(intel->drmSubFD, &vbl); + if (ret) { + *msc = 0; + *ust = 0; + return BadMatch; + } else { + *msc = vbl.reply.sequence; + *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec; + } + return Success; +} + +/* + * Convert a 32-bit kernel MSC sequence number to a 64-bit local sequence + * number, adding in the vblank_offset and high 32 bits, and dealing + * with 64-bit wrapping + */ +uint64_t +intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + sequence += intel_crtc->vblank_offset; + + if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000) + intel_crtc->msc_high += 0x100000000L; + intel_crtc->msc_prev = sequence; + return intel_crtc->msc_high + sequence; +} + +/* + * Get the current 64-bit adjust MSC and UST value + */ +int +intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust) +{ + uint32_t sequence; + int ret; + + ret = intel_get_msc_ust(scrn, crtc, &sequence, ust); + *msc = intel_sequence_to_crtc_msc(crtc, sequence); + return ret; +} + +/* + * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number, + * removing the high 32 bits and subtracting out the vblank_offset term. + * + * This also updates the vblank_offset when it notices that the value should + * change. + */ +uint32_t +intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + uint64_t msc; + uint64_t ust; + int64_t diff; + + intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust); + diff = expect - msc; + + /* We're way off here, assume that the kernel has lost its mind + * and smack the vblank back to something sensible + */ + if (diff < -200 || 200 < diff) { + intel_crtc->vblank_offset += (int32_t) diff; + if (-200 < intel_crtc->vblank_offset && intel_crtc->vblank_offset < 200) + intel_crtc->vblank_offset = 0; + } + return (uint32_t) (expect - intel_crtc->vblank_offset); +} + static void intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, unsigned int tv_usec, void *event) @@ -1721,9 +1818,8 @@ intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, /* 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; + mode->fe_msc = frame; + mode->fe_usec = (uint64_t) tv_sec * 1000000 + tv_usec; } free(flip); @@ -1739,8 +1835,8 @@ intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, return; /* Deliver cached msc, ust from reference crtc to flip event handler */ - I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec, - mode->fe_tv_usec, mode->flip_info); + I830DRI2FlipEventHandler((uint32_t) mode->fe_msc, mode->fe_usec / 1000000, + mode->fe_usec % 1000000, mode->flip_info); } static void diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c index ca58052d..97cbe50a 100644 --- a/src/uxa/intel_dri.c +++ b/src/uxa/intel_dri.c @@ -575,14 +575,13 @@ static void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) } } -static int -I830DRI2DrawablePipe(DrawablePtr pDraw) +static xf86CrtcPtr +I830DRI2DrawableCrtc(DrawablePtr pDraw) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); BoxRec box, crtcbox; xf86CrtcPtr crtc = NULL; - int pipe = -1; box.x1 = pDraw->x; box.y1 = pDraw->y; @@ -594,9 +593,9 @@ I830DRI2DrawablePipe(DrawablePtr pDraw) /* Make sure the CRTC is valid and this is the real front buffer */ if (crtc != NULL && !crtc->rotatedData) - pipe = intel_crtc_to_pipe(crtc); + return crtc; - return pipe; + return NULL; } static RESTYPE frame_event_client_type, frame_event_drawable_type; @@ -954,7 +953,7 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) if (!pScrn->vtSema) return FALSE; - if (I830DRI2DrawablePipe(drawable) < 0) + if (I830DRI2DrawableCrtc(drawable) == NULL) return FALSE; if (!DRI2CanFlip(drawable)) @@ -1164,21 +1163,19 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, ScrnInfoPtr scrn = xf86ScreenToScrn(screen); intel_screen_private *intel = intel_get_screen_private(scrn); drmVBlank vbl; - int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0; + int ret; + xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); + int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; + int flip = 0; DRI2FrameEventPtr swap_info = NULL; enum DRI2FrameEventType swap_type = DRI2_SWAP; - CARD64 current_msc; + uint64_t current_msc, current_ust; + uint64_t request_msc; /* Drawable not displayed... just complete the swap */ if (pipe == -1) goto blit_fallback; - /* Truncate to match kernel interfaces; means occasional overflow - * misses, but that's generally not a big deal */ - *target_msc &= 0xffffffff; - divisor &= 0xffffffff; - remainder &= 0xffffffff; - swap_info = calloc(1, sizeof(DRI2FrameEventRec)); if (!swap_info) goto blit_fallback; @@ -1201,18 +1198,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, I830DRI2ReferenceBuffer(front); I830DRI2ReferenceBuffer(back); - /* Get current count */ - vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); - vbl.request.sequence = 0; - ret = drmWaitVBlank(intel->drmSubFD, &vbl); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "first get vblank counter failed: %s\n", - strerror(errno)); - goto blit_fallback; - } - - current_msc = vbl.reply.sequence; + ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); /* Flips need to be submitted one frame before */ if (can_exchange(draw, front, back)) { @@ -1261,7 +1247,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, if (current_msc >= *target_msc) *target_msc = current_msc; - vbl.request.sequence = *target_msc; + vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc); vbl.request.signal = (unsigned long)swap_info; ret = drmWaitVBlank(intel->drmSubFD, &vbl); if (ret) { @@ -1271,7 +1257,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, goto blit_fallback; } - *target_msc = vbl.reply.sequence + flip; + *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); swap_info->frame = *target_msc; return TRUE; @@ -1287,8 +1273,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, if (flip == 0) vbl.request.type |= DRM_VBLANK_NEXTONMISS; - vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; + request_msc = current_msc - (current_msc % divisor) + + remainder; /* * If the calculated deadline vbl.request.sequence is smaller than @@ -1301,8 +1287,10 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay * if we are blitting/exchanging instead of flipping. */ - if (vbl.request.sequence <= current_msc) - vbl.request.sequence += divisor; + if (request_msc <= current_msc) + request_msc += divisor; + + vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); /* Account for 1 frame extra pageflip delay if flip > 0 */ vbl.request.sequence -= flip; @@ -1317,7 +1305,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, } /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ - *target_msc = vbl.reply.sequence + flip; + *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); swap_info->frame = *target_msc; return TRUE; @@ -1350,35 +1338,20 @@ I830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) { ScreenPtr screen = draw->pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - intel_screen_private *intel = intel_get_screen_private(scrn); - drmVBlank vbl; - int ret, pipe = I830DRI2DrawablePipe(draw); + int ret; + xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); /* Drawable not displayed, make up a *monotonic* value */ - if (pipe == -1) { + if (crtc == NULL) { *ust = gettime_us(); *msc = 0; return TRUE; } - vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); - vbl.request.sequence = 0; + ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust); - ret = drmWaitVBlank(intel->drmSubFD, &vbl); - if (ret) { - static int limit = 5; - if (limit) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "%s:%d get vblank counter failed: %s\n", - __FUNCTION__, __LINE__, - strerror(errno)); - limit--; - } - return FALSE; - } - - *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; - *msc = vbl.reply.sequence; + if (ret) + return FALSE; return TRUE; } @@ -1398,14 +1371,10 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, intel_screen_private *intel = intel_get_screen_private(scrn); DRI2FrameEventPtr wait_info; drmVBlank vbl; - int ret, pipe = I830DRI2DrawablePipe(draw); - CARD64 current_msc; - - /* Truncate to match kernel interfaces; means occasional overflow - * misses, but that's generally not a big deal */ - target_msc &= 0xffffffff; - divisor &= 0xffffffff; - remainder &= 0xffffffff; + int ret; + xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); + int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; + CARD64 current_msc, current_ust, request_msc; /* Drawable not visible, return immediately */ if (pipe == -1) @@ -1427,22 +1396,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, } /* Get current count */ - vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); - vbl.request.sequence = 0; - ret = drmWaitVBlank(intel->drmSubFD, &vbl); - if (ret) { - static int limit = 5; - if (limit) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "%s:%d get vblank counter failed: %s\n", - __FUNCTION__, __LINE__, - strerror(errno)); - limit--; - } - goto out_free; - } - - current_msc = vbl.reply.sequence; + ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); /* * If divisor is zero, or current_msc is smaller than target_msc, @@ -1460,7 +1414,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, target_msc = current_msc; vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); - vbl.request.sequence = target_msc; + vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc); vbl.request.signal = (unsigned long)wait_info; ret = drmWaitVBlank(intel->drmSubFD, &vbl); if (ret) { @@ -1475,7 +1429,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, goto out_free; } - wait_info->frame = vbl.reply.sequence; + wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); DRI2BlockClient(client, draw); return TRUE; } @@ -1487,9 +1441,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); - vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; - + request_msc = current_msc - (current_msc % divisor) + + remainder; /* * If calculated remainder is larger than requested remainder, * it means we've passed the last point where @@ -1497,7 +1450,9 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, * that will happen. */ if ((current_msc % divisor) >= remainder) - vbl.request.sequence += divisor; + request_msc += divisor; + + vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); vbl.request.signal = (unsigned long)wait_info; ret = drmWaitVBlank(intel->drmSubFD, &vbl); @@ -1513,7 +1468,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, goto out_free; } - wait_info->frame = vbl.reply.sequence; + wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); DRI2BlockClient(client, draw); return TRUE; |