summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/uxa/intel.h9
-rw-r--r--src/uxa/intel_display.c118
-rw-r--r--src/uxa/intel_dri.c125
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, &current_msc, &current_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, &current_msc, &current_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;