* [PATCH 0/4] xf86-video-intel DRI3 and Present patch series
@ 2013-11-20 20:53 Keith Packard
2013-11-20 20:53 ` [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about MSC reporting Keith Packard
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-20 20:53 UTC (permalink / raw)
To: xorg-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Here's a series of patches which provide DRI3 and Present support in
the Intel 2D driver. The first two patches pave the way by
synthesizing 64-bit vblank counters and extending the DRM event
handling to allow for both DRI2 and DRI3 events. Then there's a patch
to add DRI2 and miSyncShm support followed by a patch to add Present
support.
[PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about
[PATCH 2/4] Restructure DRM event handling.
[PATCH 3/4] Add DRI3 and miSyncShm support
[PATCH 4/4] Add Present extension support
-keith
_______________________________________________
xorg-devel-go0+a7rfsptAfugRpC6u6w@public.gmane.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about MSC reporting
2013-11-20 20:53 [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Keith Packard
@ 2013-11-20 20:53 ` Keith Packard
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
2013-11-20 20:53 ` [PATCH 4/4] Add Present extension support Keith Packard
2 siblings, 0 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-20 20:53 UTC (permalink / raw)
To: xorg-devel, intel-gfx
The kernel sometimes reports bogus MSC values, especially when
suspending and resuming the machine. Deal with this by tracking an
offset to ensure that the MSC seen by applications increases
monotonically, and at a reasonable pace.
Also, provide a full 64 bits of MSC value by noticing wrapping and
tracking the high 32-bits of MSC separately.
Signed-off-by: Keith Packard <keithp@keithp.com>
---
src/uxa/intel.h | 9 ++++
src/uxa/intel_display.c | 118 ++++++++++++++++++++++++++++++++++++++++-----
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 131f18c..f05b160 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -401,6 +401,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 3c2f964..09cd48f 100644
--- a/src/uxa/intel_display.c
+++ b/src/uxa/intel_display.c
@@ -71,9 +71,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;
@@ -97,6 +96,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 {
@@ -1647,9 +1649,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]))
@@ -1705,6 +1706,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)
@@ -1722,9 +1819,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);
@@ -1740,8 +1836,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 acedd0b..9c2aafd 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;
- int pipe = -1;
box.x1 = pDraw->x;
box.y1 = pDraw->y;
@@ -593,9 +592,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;
@@ -953,7 +952,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))
@@ -1160,21 +1159,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;
@@ -1197,18 +1194,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)) {
@@ -1257,7 +1243,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) {
@@ -1267,7 +1253,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;
@@ -1283,8 +1269,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
@@ -1297,8 +1283,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;
@@ -1313,7 +1301,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;
@@ -1346,35 +1334,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;
}
@@ -1394,14 +1367,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)
@@ -1423,22 +1392,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,
@@ -1456,7 +1410,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) {
@@ -1471,7 +1425,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;
}
@@ -1483,9 +1437,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
@@ -1493,7 +1446,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);
@@ -1509,7 +1464,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;
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] Restructure DRM event handling.
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
@ 2013-11-20 20:53 ` Keith Packard
2013-11-20 20:53 ` [PATCH 3/4] Add DRI3 and miSyncShm support Keith Packard
2013-11-25 13:49 ` [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Chris Wilson
2 siblings, 0 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-20 20:53 UTC (permalink / raw)
To: xorg-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
This refactors the drm interrupt handling logic quite a bit, both to
allow for either DRI2 or Present handlers, but also to eliminate
passing pointers through the kernel. Passing pointers left the kernel
holding the only reference to some internal X server data structures.
After a server reset, the X server would end up using stale pointers
stored in those structures. Using simple integers makes it possible to
empty the queue of pending interrupt data and then ignore the stale
kernel data.
Signed-off-by: Keith Packard <keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
---
src/uxa/intel.h | 31 ++++-
src/uxa/intel_display.c | 316 ++++++++++++++++++++++++++++++++++++++++++------
src/uxa/intel_dri.c | 99 ++++++++++++---
3 files changed, 390 insertions(+), 56 deletions(-)
diff --git a/src/uxa/intel.h b/src/uxa/intel.h
index f05b160..922b208 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -395,6 +395,25 @@ extern void intel_mode_disable_unused_functions(ScrnInfoPtr scrn);
extern void intel_mode_remove_fb(intel_screen_private *intel);
extern void intel_mode_close(intel_screen_private *intel);
extern void intel_mode_fini(intel_screen_private *intel);
+extern int intel_mode_read_drm_events(intel_screen_private *intel);
+
+typedef void (*intel_drm_handler_proc)(ScrnInfoPtr scrn,
+ xf86CrtcPtr crtc,
+ uint64_t seq,
+ uint64_t usec,
+ void *data);
+
+typedef void (*intel_drm_abort_proc)(ScrnInfoPtr scrn,
+ xf86CrtcPtr crtc,
+ void *data);
+
+extern uint32_t intel_drm_queue_alloc(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data, intel_drm_handler_proc handler, intel_drm_abort_proc abort);
+extern void intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data);
+
+/* struct intel_mode *
+ intel_page_flip_handler(void *event_data); */
+
+
extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
extern int intel_crtc_id(xf86CrtcPtr crtc);
@@ -422,6 +441,12 @@ typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type,
CARD64 ust, CARD64 msc, CARD64 sbc);
#endif
+typedef void (*intel_pageflip_handler_proc) (uint64_t frame,
+ uint64_t usec,
+ void *data);
+
+typedef void (*intel_pageflip_abort_proc) (void *data);
+
typedef struct _DRI2FrameEvent {
struct intel_screen_private *intel;
@@ -444,7 +469,11 @@ typedef struct _DRI2FrameEvent {
extern Bool intel_do_pageflip(intel_screen_private *intel,
dri_bo *new_front,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id);
+ int ref_crtc_hw_id,
+ Bool async,
+ void *pageflip_data,
+ intel_pageflip_handler_proc pageflip_handler,
+ intel_pageflip_abort_proc pageflip_abort);
static inline intel_screen_private *
intel_get_screen_private(ScrnInfoPtr scrn)
diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
index 09cd48f..e6cc07a 100644
--- a/src/uxa/intel_display.c
+++ b/src/uxa/intel_display.c
@@ -61,6 +61,23 @@
#define KNOWN_MODE_FLAGS ((1<<14)-1)
+struct intel_drm_queue {
+ struct xorg_list list;
+ xf86CrtcPtr crtc;
+ uint32_t seq;
+ void *data;
+ ScrnInfoPtr scrn;
+ intel_drm_handler_proc handler;
+ intel_drm_abort_proc abort;
+};
+
+static void
+intel_drm_abort_scrn(ScrnInfoPtr scrn);
+
+static uint32_t intel_drm_seq;
+
+static struct xorg_list intel_drm_queue;
+
struct intel_mode {
int fd;
uint32_t fb_id;
@@ -68,7 +85,6 @@ struct intel_mode {
int cpp;
drmEventContext event_context;
- DRI2FrameEventPtr flip_info;
int old_fb_id;
int flip_count;
uint64_t fe_msc;
@@ -76,6 +92,10 @@ struct intel_mode {
struct list outputs;
struct list crtcs;
+
+ void *pageflip_data;
+ intel_pageflip_handler_proc pageflip_handler;
+ intel_pageflip_abort_proc pageflip_abort;
};
struct intel_pageflip {
@@ -536,6 +556,7 @@ intel_crtc_apply(xf86CrtcPtr crtc)
if (scrn->pScreen)
xf86_reload_cursors(scrn->pScreen);
+ intel_drm_abort_scrn(scrn);
done:
free(output_ids);
@@ -1138,11 +1159,23 @@ intel_output_dpms(xf86OutputPtr output, int dpms)
dpms);
intel_output->dpms_mode = dpms;
drmModeFreeProperty(props);
- return;
+ break;
}
drmModeFreeProperty(props);
}
+
+ /* Make sure the associated CRTC is bound to the right fb_id; it won't be if
+ * a page flip happened while this CRTC was turned off
+ */
+ if (dpms == DPMSModeOn) {
+ xf86CrtcPtr crtc = output->crtc;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ drmModeCrtcPtr drm_crtc = drmModeGetCrtc(mode->fd, crtc_id(intel_crtc));
+
+ if (drm_crtc->buffer_id != mode->fb_id)
+ intel_crtc_apply(crtc);
+ }
}
int
@@ -1614,10 +1647,27 @@ fail:
return FALSE;
}
+static void
+intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
+ uint64_t frame, uint64_t usec, void *data);
+
+static void
+intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data);
+
+static void
+intel_pageflip_complete(struct intel_mode *mode);
+
+static void
+intel_drm_abort_seq (ScrnInfoPtr scrn, uint32_t seq);
+
Bool
intel_do_pageflip(intel_screen_private *intel,
dri_bo *new_front,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
+ int ref_crtc_hw_id,
+ Bool async,
+ void *pageflip_data,
+ intel_pageflip_handler_proc pageflip_handler,
+ intel_pageflip_abort_proc pageflip_abort)
{
ScrnInfoPtr scrn = intel->scrn;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1626,6 +1676,8 @@ intel_do_pageflip(intel_screen_private *intel,
unsigned int pitch = scrn->displayWidth * intel->cpp;
struct intel_pageflip *flip;
uint32_t new_fb_id;
+ uint32_t flags;
+ uint32_t seq;
int i;
/*
@@ -1640,6 +1692,10 @@ intel_do_pageflip(intel_screen_private *intel,
intel_glamor_flush(intel);
intel_batch_submit(scrn);
+ mode->pageflip_data = pageflip_data;
+ mode->pageflip_handler = pageflip_handler;
+ mode->pageflip_abort = pageflip_abort;
+
/*
* Queue flips on all enabled CRTCs
* Note that if/when we get per-CRTC buffers, we'll have to update this.
@@ -1652,13 +1708,13 @@ intel_do_pageflip(intel_screen_private *intel,
mode->fe_msc = 0;
mode->fe_usec = 0;
+ flags = DRM_MODE_PAGE_FLIP_EVENT;
+ if (async)
+ flags |= DRM_MODE_PAGE_FLIP_ASYNC;
for (i = 0; i < config->num_crtc; i++) {
if (!intel_crtc_on(config->crtc[i]))
continue;
- mode->flip_info = flip_info;
- mode->flip_count++;
-
crtc = config->crtc[i]->driver_private;
flip = calloc(1, sizeof(struct intel_pageflip));
@@ -1674,19 +1730,39 @@ intel_do_pageflip(intel_screen_private *intel,
flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
flip->mode = mode;
+ seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort);
+ if (!seq) {
+ free(flip);
+ goto error_undo;
+ }
+
+ again:
if (drmModePageFlip(mode->fd,
crtc_id(crtc),
new_fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, flip)) {
+ flags, (void *) seq))
+ {
+ if (intel_mode_read_drm_events(intel)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue retry\n");
+ goto again;
+ }
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"flip queue failed: %s\n", strerror(errno));
+ if (seq)
+ intel_drm_abort_seq(scrn, seq);
free(flip);
goto error_undo;
}
+ mode->flip_count++;
}
mode->old_fb_id = mode->fb_id;
mode->fb_id = new_fb_id;
+
+ if (!mode->flip_count)
+ intel_pageflip_complete(mode);
+
return TRUE;
error_undo:
@@ -1699,6 +1775,8 @@ error_undo:
error_out:
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
strerror(errno));
+
+ mode->flip_count = 0;
return FALSE;
}
@@ -1706,6 +1784,98 @@ static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
intel_xf86crtc_resize
};
+/*
+ * Enqueue a potential drm response; when the associated response
+ * appears, we've got data to pass to the handler from here
+ */
+uint32_t
+intel_drm_queue_alloc(ScrnInfoPtr scrn,
+ xf86CrtcPtr crtc,
+ void *data,
+ intel_drm_handler_proc handler,
+ intel_drm_abort_proc abort)
+{
+ struct intel_drm_queue *q;
+
+ q = calloc (1, sizeof (struct intel_drm_queue));
+
+ if (!q)
+ return 0;
+ if (!intel_drm_seq)
+ ++intel_drm_seq;
+ q->seq = intel_drm_seq++;
+ q->scrn = scrn;
+ q->crtc = crtc;
+ q->data = data;
+ q->handler = handler;
+ q->abort = abort;
+
+ xorg_list_add (&q->list, &intel_drm_queue);
+
+ return q->seq;
+}
+
+/*
+ * Abort one queued DRM entry, removing it
+ * from the list, calling the abort function and
+ * freeing the memory
+ */
+static void
+intel_drm_abort_one(struct intel_drm_queue *q)
+{
+ xorg_list_del(&q->list);
+ (*q->abort) (q->scrn, q->crtc, q->data);
+ free(q);
+}
+
+/*
+ * Externally usable abort function that uses a callback to match a single queued
+ * entry to abort
+ */
+void
+intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data)
+{
+ struct intel_drm_queue *q, *tmp;
+
+ xorg_list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) {
+ if (match (q->data, match_data)) {
+ intel_drm_abort_one(q);
+ break;
+ }
+ }
+}
+
+/*
+ * Abort by drm queue sequence number
+ */
+static void
+intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
+{
+ struct intel_drm_queue *q, *tmp;
+
+ xorg_list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) {
+ if (q->seq == seq) {
+ intel_drm_abort_one(q);
+ break;
+ }
+ }
+}
+
+/*
+ * Abort all queued entries on a specific scrn, used
+ * when resetting the X server
+ */
+static void
+intel_drm_abort_scrn(ScrnInfoPtr scrn)
+{
+ struct intel_drm_queue *q, *tmp;
+
+ xorg_list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) {
+ if (q->scrn == scrn)
+ intel_drm_abort_one(q);
+ }
+}
+
static uint32_t pipe_select(int pipe)
{
if (pipe > 1)
@@ -1802,44 +1972,111 @@ intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
return (uint32_t) (expect - intel_crtc->vblank_offset);
}
+/*
+ * General DRM kernel handler. Looks for the matching sequence number in the
+ * drm event queue and calls the handler for it.
+ */
static void
-intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, void *event)
+intel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *user_ptr)
{
- I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event);
+ struct intel_drm_queue *q, *tmp;
+ uint32_t user_data = (uint32_t) (intptr_t) user_ptr;
+
+ xorg_list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) {
+ if (q->seq == user_data) {
+ uint64_t msc;
+
+ msc = intel_sequence_to_crtc_msc(q->crtc, frame);
+ xorg_list_del(&q->list);
+ (*q->handler) (q->scrn, q->crtc, msc, (uint64_t) sec * 1000000 + usec, q->data);
+ free(q);
+ break;
+ }
+ }
}
+
+/*
+ * Notify the page flip caller that the flip is
+ * complete
+ */
static void
-intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
- unsigned int tv_usec, void *event_data)
+intel_pageflip_complete(struct intel_mode *mode)
+{
+ /* Release framebuffer */
+ drmModeRmFB(mode->fd, mode->old_fb_id);
+
+ if (!mode->pageflip_handler)
+ return;
+
+ (*mode->pageflip_handler) (mode->fe_msc, mode->fe_usec,
+ mode->pageflip_data);
+}
+
+/*
+ * One pageflip event has completed. Update the saved msc/ust values
+ * as needed, then check to see if the whole set of events are
+ * complete and notify the application at that point
+ */
+static struct intel_mode *
+intel_handle_pageflip(struct intel_pageflip *flip, uint64_t msc, uint64_t usec)
{
- struct intel_pageflip *flip = event_data;
- struct intel_mode *mode = flip->mode;
+ struct intel_mode *mode = flip->mode;
- /* 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_msc = frame;
- mode->fe_usec = (uint64_t) tv_sec * 1000000 + tv_usec;
+ mode->fe_msc = msc;
+ mode->fe_usec = usec;
}
free(flip);
/* Last crtc completed flip? */
mode->flip_count--;
if (mode->flip_count > 0)
- return;
+ return NULL;
+
+ return mode;
+}
+
+/*
+ * Called from the DRM event queue when a single flip has completed
+ */
+static void
+intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
+ uint64_t msc, uint64_t usec, void *data)
+{
+ struct intel_pageflip *flip = data;
+ struct intel_mode *mode = intel_handle_pageflip(flip, msc, usec);
+
+ if (!mode)
+ return;
+ intel_pageflip_complete(mode);
+}
+
+/*
+ * Called from the DRM queue abort code when a flip has been aborted
+ */
+static void
+intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
+{
+ struct intel_pageflip *flip = data;
+ struct intel_mode *mode = intel_handle_pageflip(flip, 0, 0);
+
+ if (!mode)
+ return;
/* Release framebuffer */
drmModeRmFB(mode->fd, mode->old_fb_id);
- if (mode->flip_info == NULL)
- return;
+ if (!mode->pageflip_abort)
+ return;
- /* Deliver cached msc, ust from reference crtc to flip event handler */
- I830DRI2FlipEventHandler((uint32_t) mode->fe_msc, mode->fe_usec / 1000000,
- mode->fe_usec % 1000000, mode->flip_info);
+ (*mode->pageflip_abort) (mode->pageflip_data);
}
+/*
+ * Check for pending DRM events and process them.
+ */
static void
drm_wakeup_handler(pointer data, int err, pointer p)
{
@@ -1855,6 +2092,17 @@ drm_wakeup_handler(pointer data, int err, pointer p)
drmHandleEvent(mode->fd, &mode->event_context);
}
+/*
+ * Just try to read drm_events; the fd is non-blocking, so we'll get
+ * zero if there aren't any events to read
+ */
+int
+intel_mode_read_drm_events(struct intel_screen_private *intel)
+{
+ struct intel_mode *mode = intel->modes;
+ return drmHandleEvent(mode->fd, &mode->event_context);
+}
+
static drmModeEncoderPtr
intel_get_kencoder(struct intel_mode *mode, int num)
{
@@ -1954,8 +2202,12 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
xf86InitialConfiguration(scrn, TRUE);
mode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
- mode->event_context.vblank_handler = intel_vblank_handler;
- mode->event_context.page_flip_handler = intel_page_flip_handler;
+ mode->event_context.vblank_handler = intel_drm_handler;
+ mode->event_context.page_flip_handler = intel_drm_handler;
+
+ /* XXX assumes only one intel screen */
+ xorg_list_init(&intel_drm_queue);
+ intel_drm_seq = 0;
has_flipping = 0;
gp.param = I915_PARAM_HAS_PAGEFLIPPING;
@@ -1998,14 +2250,6 @@ intel_mode_remove_fb(intel_screen_private *intel)
}
}
-static Bool has_pending_events(int fd)
-{
- struct pollfd pfd;
- pfd.fd = fd;
- pfd.events = POLLIN;
- return poll(&pfd, 1, 0) == 1;
-}
-
void
intel_mode_close(intel_screen_private *intel)
{
@@ -2014,8 +2258,7 @@ intel_mode_close(intel_screen_private *intel)
if (mode == NULL)
return;
- while (has_pending_events(mode->fd))
- drmHandleEvent(mode->fd, &mode->event_context);
+ intel_drm_abort_scrn(intel->scrn);
RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
drm_wakeup_handler, mode);
@@ -2094,7 +2337,8 @@ Bool intel_crtc_on(xf86CrtcPtr crtc)
return FALSE;
ret = (drm_crtc->mode_valid &&
- intel_crtc->mode->fb_id == drm_crtc->buffer_id);
+ (intel_crtc->mode->fb_id == drm_crtc->buffer_id ||
+ intel_crtc->mode->old_fb_id == drm_crtc->buffer_id));
free(drm_crtc);
return ret;
diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
index 9c2aafd..df07917 100644
--- a/src/uxa/intel_dri.c
+++ b/src/uxa/intel_dri.c
@@ -592,7 +592,7 @@ I830DRI2DrawableCrtc(DrawablePtr pDraw)
/* Make sure the CRTC is valid and this is the real front buffer */
if (crtc != NULL && !crtc->rotatedData)
- return crtc;
+ return crtc;
return NULL;
}
@@ -725,15 +725,15 @@ i830_dri2_add_frame_event(DRI2FrameEventPtr info)
}
static void
-i830_dri2_del_frame_event(DrawablePtr drawable, DRI2FrameEventPtr info)
+i830_dri2_del_frame_event(DRI2FrameEventPtr info)
{
list_del(&info->client_resource);
list_del(&info->drawable_resource);
if (info->front)
- I830DRI2DestroyBuffer(drawable, info->front);
+ I830DRI2DestroyBuffer(NULL, info->front);
if (info->back)
- I830DRI2DestroyBuffer(drawable, info->back);
+ I830DRI2DestroyBuffer(NULL, info->back);
free(info);
}
@@ -831,6 +831,24 @@ static drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
return bo;
}
+static void
+I830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
+{
+ DRI2FrameEventPtr info = pageflip_data;
+
+ I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
+ usec % 1000000,
+ info);
+}
+
+static void
+I830DRI2FlipAbort(void *pageflip_data)
+{
+ DRI2FrameEventPtr info = pageflip_data;
+
+ i830_dri2_del_frame_event(info);
+}
+
/*
* Our internal swap routine takes care of actually exchanging, blitting, or
* flipping buffers as necessary.
@@ -848,7 +866,9 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
info->type = DRI2_SWAP;
if (!intel_do_pageflip(intel,
get_pixmap_bo(priv),
- info, info->pipe))
+ info->pipe, FALSE, info,
+ I830DRI2FlipComplete,
+ I830DRI2FlipAbort))
return FALSE;
I830DRI2ExchangeBuffers(intel, info->front, info->back);
@@ -903,7 +923,7 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
}
old_back = get_pixmap_bo(priv);
- if (!intel_do_pageflip(intel, old_back, info, info->pipe)) {
+ if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
intel->back_buffer = new_back;
return FALSE;
}
@@ -999,7 +1019,7 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
M_ANY, DixWriteAccess);
if (status != Success) {
- i830_dri2_del_frame_event(NULL, swap_info);
+ i830_dri2_del_frame_event(swap_info);
return;
}
@@ -1033,7 +1053,7 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
break;
}
- i830_dri2_del_frame_event(drawable, swap_info);
+ i830_dri2_del_frame_event(swap_info);
}
void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
@@ -1094,7 +1114,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
serverClient,
M_ANY, DixWriteAccess);
if (chain_drawable == NULL) {
- i830_dri2_del_frame_event(chain_drawable, chain);
+ i830_dri2_del_frame_event(chain);
} else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
!I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
I830DRI2FallbackBlitSwap(chain_drawable,
@@ -1105,7 +1125,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
DRI2_BLIT_COMPLETE,
chain->client ? chain->event_complete : NULL,
chain->event_data);
- i830_dri2_del_frame_event(chain_drawable, chain);
+ i830_dri2_del_frame_event(chain);
}
}
break;
@@ -1117,7 +1137,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
break;
}
- i830_dri2_del_frame_event(drawable, flip_info);
+ i830_dri2_del_frame_event(flip_info);
}
static uint32_t pipe_select(int pipe)
@@ -1130,6 +1150,28 @@ static uint32_t pipe_select(int pipe)
return 0;
}
+static void
+intel_dri2_vblank_handler(ScrnInfoPtr scrn,
+ xf86CrtcPtr crtc,
+ uint64_t msc,
+ uint64_t usec,
+ void *data)
+{
+ DRI2FrameEventPtr swap_info = data;
+
+ I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
+}
+
+static void
+intel_dri2_vblank_abort(ScrnInfoPtr scrn,
+ xf86CrtcPtr crtc,
+ void *data)
+{
+ DRI2FrameEventPtr swap_info = data;
+
+ i830_dri2_del_frame_event(swap_info);
+}
+
/*
* ScheduleSwap is responsible for requesting a DRM vblank event for the
* appropriate frame.
@@ -1167,6 +1209,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
enum DRI2FrameEventType swap_type = DRI2_SWAP;
uint64_t current_msc, current_ust;
uint64_t request_msc;
+ uint32_t seq;
/* Drawable not displayed... just complete the swap */
if (pipe == -1)
@@ -1243,8 +1286,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
if (current_msc >= *target_msc)
*target_msc = current_msc;
+ seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
+ if (!seq)
+ goto blit_fallback;
+
vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
- vbl.request.signal = (unsigned long)swap_info;
+ vbl.request.signal = (unsigned long)seq;
+
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1286,12 +1334,15 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
if (request_msc <= current_msc)
request_msc += divisor;
- vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
+
+ seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
+ if (!seq)
+ goto blit_fallback;
/* Account for 1 frame extra pageflip delay if flip > 0 */
- vbl.request.sequence -= flip;
+ vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
+ vbl.request.signal = (unsigned long)seq;
- vbl.request.signal = (unsigned long)swap_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1310,7 +1361,7 @@ blit_fallback:
I830DRI2FallbackBlitSwap(draw, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
if (swap_info)
- i830_dri2_del_frame_event(draw, swap_info);
+ i830_dri2_del_frame_event(swap_info);
*target_msc = 0; /* offscreen, so zero out target vblank count */
return TRUE;
}
@@ -1371,6 +1422,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
CARD64 current_msc, current_ust, request_msc;
+ uint32_t seq;
/* Drawable not visible, return immediately */
if (pipe == -1)
@@ -1406,12 +1458,17 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
* sending us MSC targets from the past by forcibly updating
* their count on this call.
*/
+ seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
+ if (!seq)
+ goto out_free;
+
if (current_msc >= target_msc)
target_msc = current_msc;
vbl.request.type =
DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
- vbl.request.signal = (unsigned long)wait_info;
+ vbl.request.signal = (unsigned long)seq;
+
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
static int limit = 5;
@@ -1448,9 +1505,13 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
if ((current_msc % divisor) >= remainder)
request_msc += divisor;
+ seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
+ if (!seq)
+ goto out_free;
+
vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
+ vbl.request.signal = (unsigned long)seq;
- vbl.request.signal = (unsigned long)wait_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
static int limit = 5;
@@ -1470,7 +1531,7 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
return TRUE;
out_free:
- i830_dri2_del_frame_event(draw, wait_info);
+ i830_dri2_del_frame_event(wait_info);
out_complete:
DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
return TRUE;
--
1.8.4.2
_______________________________________________
xorg-devel-go0+a7rfsptAfugRpC6u6w@public.gmane.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] Add DRI3 and miSyncShm support
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
2013-11-20 20:53 ` [PATCH 2/4] Restructure DRM event handling Keith Packard
@ 2013-11-20 20:53 ` Keith Packard
2013-11-25 13:49 ` [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Chris Wilson
2 siblings, 0 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-20 20:53 UTC (permalink / raw)
To: xorg-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Signed-off-by: Keith Packard <keithp@keithp.com>
---
configure.ac | 14 ++++
src/uxa/Makefile.am | 7 ++
src/uxa/intel.h | 17 +++++
src/uxa/intel_dri3.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++
src/uxa/intel_driver.c | 13 ++++
src/uxa/intel_sync.c | 109 +++++++++++++++++++++++++++++
src/uxa/intel_uxa.c | 1 +
7 files changed, 345 insertions(+)
create mode 100644 src/uxa/intel_dri3.c
create mode 100644 src/uxa/intel_sync.c
diff --git a/configure.ac b/configure.ac
index 0783d61..13b9970 100644
--- a/configure.ac
+++ b/configure.ac
@@ -276,6 +276,7 @@ XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
XORG_DRIVER_CHECK_EXT(XF86DRI, xextproto x11)
XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
+XORG_DRIVER_CHECK_EXT(DRI3, dri3proto)
# Obtain compiler/linker options for the driver dependencies
PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.20]) # libdrm_intel is checked separately
@@ -463,6 +464,19 @@ else
UXA=no
fi
+if test "x$DRI3" != "xno"; then
+ save_CFLAGS=$CFLAGS
+ CFLAGS="$XORG_CFLAGS $DRM_CFLAGS $DRI_CFLAGS $DRI3_CFLAGS"
+ AC_CHECK_DECL(DRI3,
+ [DRI3=yes], [DRI3=no],
+ [#include <xorg-server.h>])
+ CFLAGS=$save_CFLAGS
+ dri_msg="$dri_msg DRI3"
+fi
+AC_MSG_CHECKING([whether to include DRI3 support])
+AM_CONDITIONAL(DRI3, test "x$DRI3" = xyes)
+AC_MSG_RESULT([$DRI3])
+
AC_CHECK_HEADERS([X11/extensions/dpmsconst.h])
AC_MSG_CHECKING([whether to include UXA support])
diff --git a/src/uxa/Makefile.am b/src/uxa/Makefile.am
index 971ac21..3c9e693 100644
--- a/src/uxa/Makefile.am
+++ b/src/uxa/Makefile.am
@@ -80,6 +80,13 @@ libuxa_la_LIBADD += \
$(NULL)
endif
+if DRI3
+libuxa_la_SOURCES += \
+ intel_dri3.c \
+ intel_sync.c \
+ $(NULL)
+endif
+
if XVMC
AM_CFLAGS += -I$(top_srcdir)/xvmc
libuxa_la_SOURCES += \
diff --git a/src/uxa/intel.h b/src/uxa/intel.h
index 922b208..c3d00f4 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -59,6 +59,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "xf86xv.h"
#include "xf86Crtc.h"
#include "xf86RandR12.h"
+#include "misync.h"
#include "xorg-server.h"
#include <pciaccess.h>
@@ -352,6 +353,11 @@ typedef struct intel_screen_private {
InputHandlerProc uevent_handler;
#endif
Bool has_prime_vmap_flush;
+
+ SyncScreenFuncsRec save_sync_screen_funcs;
+
+ void (*flush_rendering)(struct intel_screen_private *intel);
+
} intel_screen_private;
#define INTEL_INFO(intel) ((intel)->info)
@@ -519,6 +525,9 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, DRI2FrameEventPtr flip_info);
+/* intel_dri3.c */
+Bool intel_dri3_screen_init(ScreenPtr screen);
+
extern Bool intel_crtc_on(xf86CrtcPtr crtc);
int intel_crtc_to_pipe(xf86CrtcPtr crtc);
@@ -725,4 +734,12 @@ static inline Bool intel_pixmap_is_offscreen(PixmapPtr pixmap)
return priv && priv->offscreen;
}
+#if DRI3
+Bool
+intel_sync_init(ScreenPtr screen);
+#endif
+
+void
+intel_sync_close(ScreenPtr screen);
+
#endif /* _I830_H_ */
diff --git a/src/uxa/intel_dri3.c b/src/uxa/intel_dri3.c
new file mode 100644
index 0000000..99ac9d5
--- /dev/null
+++ b/src/uxa/intel_dri3.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "xf86Pci.h"
+#include "xf86drm.h"
+
+#include "windowstr.h"
+#include "shadow.h"
+#include "fb.h"
+
+#include "intel.h"
+#include "i830_reg.h"
+
+#include "i915_drm.h"
+
+#include "dri3.h"
+
+#include "intel_glamor.h"
+#include "uxa.h"
+
+static int
+intel_dri3_open(ScreenPtr screen,
+ RRProviderPtr provider,
+ int *fdp)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ drm_magic_t magic;
+ int fd;
+
+ /* Open the device for the client */
+ fd = open(intel->deviceName, O_RDWR | O_CLOEXEC);
+ if (fd == -1 && errno == EINVAL) {
+ fd = open(intel->deviceName, O_RDWR);
+ if (fd != -1)
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ }
+
+ if (fd < 0)
+ return BadAlloc;
+
+ /* Go through the auth dance locally */
+ if (drmGetMagic(fd, &magic) < 0) {
+ close(fd);
+ return BadMatch;
+ }
+
+ if (drmAuthMagic(intel->drmSubFD, magic) < 0) {
+ close (fd);
+ return BadMatch;
+ }
+
+ /* And we're done */
+ *fdp = fd;
+ return Success;
+}
+
+static PixmapPtr intel_dri3_pixmap_from_fd (ScreenPtr screen,
+ int fd,
+ CARD16 width,
+ CARD16 height,
+ CARD16 stride,
+ CARD8 depth,
+ CARD8 bpp)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_pixmap *priv;
+ PixmapPtr pixmap;
+ uint32_t bit_6_swizzle, tiling;
+ int ret;
+
+ if (depth == 1)
+ return NULL;
+
+ pixmap = fbCreatePixmap(screen, 0, 0, depth, 0);
+ if (!pixmap)
+ goto no_pixmap;
+ priv = calloc(1, sizeof (struct intel_pixmap));
+ if (priv == NULL)
+ goto no_priv;
+
+ priv->bo = drm_intel_bo_gem_create_from_prime(intel->bufmgr,
+ fd, (uint32_t) height * stride);
+ if (priv->bo == NULL)
+ goto no_bo;
+
+ ret = drm_intel_bo_get_tiling(priv->bo, &tiling, &bit_6_swizzle);
+ if (ret != 0)
+ goto no_tiling;
+
+ priv->stride = stride;
+ priv->tiling = tiling;
+ priv->offscreen = 1;
+ list_init(&priv->batch);
+ intel_set_pixmap_private(pixmap, priv);
+
+ screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, stride, NULL);
+
+ return pixmap;
+no_tiling:
+ drm_intel_bo_unreference(priv->bo);
+no_bo:
+ free (priv);
+no_priv:
+ fbDestroyPixmap(pixmap);
+no_pixmap:
+ return NULL;
+}
+
+static int intel_dri3_fd_from_pixmap (ScreenPtr screen,
+ PixmapPtr pixmap,
+ CARD16 *stride,
+ CARD32 *size)
+{
+ struct intel_pixmap *priv;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int fd;
+ int ret;
+
+ priv = intel_get_pixmap_private(pixmap);
+ if (!priv)
+ return -1;
+ (*intel->flush_rendering)(intel);
+ ret = drm_intel_bo_gem_export_to_prime(priv->bo, &fd);
+ if (ret < 0)
+ return -1;
+ *stride = priv->stride;
+ *size = priv->bo->size;
+ return fd;
+}
+
+static dri3_screen_info_rec intel_dri3_screen_info = {
+ .version = DRI3_SCREEN_INFO_VERSION,
+
+ .open = intel_dri3_open,
+ .pixmap_from_fd = intel_dri3_pixmap_from_fd,
+ .fd_from_pixmap = intel_dri3_fd_from_pixmap
+};
+
+Bool
+intel_dri3_screen_init(ScreenPtr screen)
+{
+ return dri3_screen_init(screen, &intel_dri3_screen_info);
+}
diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
index 431c34b..12c7b34 100644
--- a/src/uxa/intel_driver.c
+++ b/src/uxa/intel_driver.c
@@ -1050,6 +1050,10 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
if (intel->XvEnabled)
I830InitVideo(screen);
+#if DRI3
+ intel_dri3_screen_init(screen);
+#endif
+
#if defined(DRI2)
switch (intel->directRenderingType) {
case DRI_DRI2:
@@ -1076,6 +1080,11 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
intel_mode_init(intel);
+
+#if DRI3
+ (void) intel_sync_init(screen);
+#endif
+
intel->suspended = FALSE;
#if HAVE_UDEV
@@ -1163,6 +1172,10 @@ static Bool I830CloseScreen(CLOSE_SCREEN_ARGS_DECL)
I830UeventFini(scrn);
#endif
+#if DRI3
+ intel_sync_close(screen);
+#endif
+
intel_mode_close(intel);
DeleteCallback(&FlushCallback, intel_flush_callback, scrn);
diff --git a/src/uxa/intel_sync.c b/src/uxa/intel_sync.c
new file mode 100644
index 0000000..94426d3
--- /dev/null
+++ b/src/uxa/intel_sync.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "intel.h"
+#include "misyncshm.h"
+#include "misyncstr.h"
+
+/*
+ * This whole file exists to wrap a sync fence trigger operation
+ * so that we can flush the batch buffer to provide serialization
+ * between the server and the shm fence client
+ */
+
+static DevPrivateKeyRec intel_sync_fence_private_key;
+
+typedef struct _intel_sync_fence_private {
+ SyncFenceSetTriggeredFunc set_triggered;
+} intel_sync_fence_private;
+
+#define SYNC_FENCE_PRIV(pFence) \
+ (intel_sync_fence_private *) dixLookupPrivate(&pFence->devPrivates, &intel_sync_fence_private_key)
+
+static void
+intel_sync_fence_set_triggered (SyncFence *fence)
+{
+ ScreenPtr screen = fence->pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ intel_sync_fence_private *private = SYNC_FENCE_PRIV(fence);
+
+
+ /* Flush pending rendering operations */
+ if (intel->flush_rendering)
+ intel->flush_rendering(intel);
+
+ fence->funcs.SetTriggered = private->set_triggered;
+ (*fence->funcs.SetTriggered)(fence);
+ private->set_triggered = fence->funcs.SetTriggered;
+ fence->funcs.SetTriggered = intel_sync_fence_set_triggered;
+}
+
+static void
+intel_sync_create_fence(ScreenPtr screen,
+ SyncFence *fence,
+ Bool initially_triggered)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen);
+ intel_sync_fence_private *private = SYNC_FENCE_PRIV(fence);
+
+ screen_funcs->CreateFence = intel->save_sync_screen_funcs.CreateFence;
+ (*screen_funcs->CreateFence)(screen, fence, initially_triggered);
+
+ private->set_triggered = fence->funcs.SetTriggered;
+ fence->funcs.SetTriggered = intel_sync_fence_set_triggered;
+}
+
+Bool
+intel_sync_init(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ SyncScreenFuncsPtr screen_funcs;
+ if (!miSyncShmScreenInit(screen))
+ return FALSE;
+
+ if (!dixPrivateKeyRegistered(&intel_sync_fence_private_key)) {
+ if (!dixRegisterPrivateKey(&intel_sync_fence_private_key,
+ PRIVATE_SYNC_FENCE,
+ sizeof (intel_sync_fence_private)))
+ return FALSE;
+ }
+
+ screen_funcs = miSyncGetScreenFuncs(screen);
+ intel->save_sync_screen_funcs.CreateFence = screen_funcs->CreateFence;
+ screen_funcs->CreateFence = intel_sync_create_fence;
+ return TRUE;
+}
+
+void
+intel_sync_close(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen);
+
+ if (screen_funcs)
+ screen_funcs->CreateFence = intel->save_sync_screen_funcs.CreateFence;
+}
diff --git a/src/uxa/intel_uxa.c b/src/uxa/intel_uxa.c
index 6fb1333..a31d196 100644
--- a/src/uxa/intel_uxa.c
+++ b/src/uxa/intel_uxa.c
@@ -1420,5 +1420,6 @@ Bool intel_uxa_init(ScreenPtr screen)
uxa_set_fallback_debug(screen, intel->fallback_debug);
uxa_set_force_fallback(screen, intel->force_fallback);
+ intel->flush_rendering = intel_flush_rendering;
return TRUE;
}
--
1.8.4.2
_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] Add Present extension support
2013-11-20 20:53 [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Keith Packard
2013-11-20 20:53 ` [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about MSC reporting Keith Packard
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
@ 2013-11-20 20:53 ` Keith Packard
2 siblings, 0 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-20 20:53 UTC (permalink / raw)
To: xorg-devel, intel-gfx
Signed-off-by: Keith Packard <keithp@keithp.com>
---
configure.ac | 15 ++
src/uxa/Makefile.am | 6 +
src/uxa/intel.h | 15 ++
src/uxa/intel_driver.c | 4 +
src/uxa/intel_present.c | 406 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 446 insertions(+)
create mode 100644 src/uxa/intel_present.c
diff --git a/configure.ac b/configure.ac
index 13b9970..8d881a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -277,6 +277,7 @@ XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
XORG_DRIVER_CHECK_EXT(XF86DRI, xextproto x11)
XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
XORG_DRIVER_CHECK_EXT(DRI3, dri3proto)
+XORG_DRIVER_CHECK_EXT(PRESENT, presentproto)
# Obtain compiler/linker options for the driver dependencies
PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.20]) # libdrm_intel is checked separately
@@ -477,6 +478,19 @@ AC_MSG_CHECKING([whether to include DRI3 support])
AM_CONDITIONAL(DRI3, test "x$DRI3" = xyes)
AC_MSG_RESULT([$DRI3])
+if test "x$PRESENT" != "xno"; then
+ save_CFLAGS=$CFLAGS
+ CFLAGS="$XORG_CFLAGS $PRESENT_CFLAGS"
+ AC_CHECK_DECL(PRESENT,
+ [PRESENT=yes], [PRESENT=no],
+ [#include <xorg-server.h>])
+ CFLAGS=$save_CFLAGS
+fi
+echo 'PRESENT is now ' $PRESENT
+AC_MSG_CHECKING([whether to include Present support])
+AM_CONDITIONAL(PRESENT, test "x$PRESENT" = xyes)
+AC_MSG_RESULT([$PRESENT])
+
AC_CHECK_HEADERS([X11/extensions/dpmsconst.h])
AC_MSG_CHECKING([whether to include UXA support])
@@ -731,6 +745,7 @@ echo " Additional debugging support?$debug_msg"
echo " Support for Kernel Mode Setting? $KMS"
echo " Support for legacy User Mode Setting (for i810)? $UMS"
echo " Support for Direct Rendering Infrastructure:$dri_msg"
+echo " Support for Present extension? $PRESENT"
echo " Support for Xv motion compensation (XvMC and libXvMC):$xvmc_msg"
echo " Build additional tools and utilities?$tools_msg"
if test -n "$xp_msg"; then
diff --git a/src/uxa/Makefile.am b/src/uxa/Makefile.am
index 3c9e693..1f6f942 100644
--- a/src/uxa/Makefile.am
+++ b/src/uxa/Makefile.am
@@ -87,6 +87,12 @@ libuxa_la_SOURCES += \
$(NULL)
endif
+if PRESENT
+libuxa_la_SOURCES += \
+ intel_present.c \
+ $(NULL)
+endif
+
if XVMC
AM_CFLAGS += -I$(top_srcdir)/xvmc
libuxa_la_SOURCES += \
diff --git a/src/uxa/intel.h b/src/uxa/intel.h
index c3d00f4..48711e4 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -742,4 +742,19 @@ intel_sync_init(ScreenPtr screen);
void
intel_sync_close(ScreenPtr screen);
+/*
+ * intel_present.c
+ */
+
+#if 0
+#define DebugPresent(x) ErrorF x
+#else
+#define DebugPresent(x)
+#endif
+
+#if PRESENT
+Bool
+intel_present_screen_init(ScreenPtr screen);
+#endif
+
#endif /* _I830_H_ */
diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
index 12c7b34..c760ff6 100644
--- a/src/uxa/intel_driver.c
+++ b/src/uxa/intel_driver.c
@@ -1050,6 +1050,10 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
if (intel->XvEnabled)
I830InitVideo(screen);
+#if PRESENT
+ intel_present_screen_init(screen);
+#endif
+
#if DRI3
intel_dri3_screen_init(screen);
#endif
diff --git a/src/uxa/intel_present.c b/src/uxa/intel_present.c
new file mode 100644
index 0000000..297497b
--- /dev/null
+++ b/src/uxa/intel_present.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "xf86Pci.h"
+#include "xf86drm.h"
+
+#include "windowstr.h"
+#include "shadow.h"
+#include "fb.h"
+
+#include "intel.h"
+#include "i830_reg.h"
+
+#include "i915_drm.h"
+
+#include "present.h"
+
+#include "intel_glamor.h"
+#include "uxa.h"
+
+struct intel_present_vblank_event {
+ uint64_t event_id;
+};
+
+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;
+}
+
+static RRCrtcPtr
+intel_present_get_crtc(WindowPtr window)
+{
+ ScreenPtr screen = window->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
+ BoxRec box, crtcbox;
+ xf86CrtcPtr crtc;
+ RRCrtcPtr randr_crtc = NULL;
+
+ box.x1 = window->drawable.x;
+ box.y1 = window->drawable.y;
+ box.x2 = box.x1 + window->drawable.width;
+ box.y2 = box.y1 + window->drawable.height;
+
+ crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
+
+ /* Make sure the CRTC is valid and this is the real front buffer */
+ if (crtc != NULL && !crtc->rotatedData)
+ randr_crtc = crtc->randr_crtc;
+
+ return randr_crtc;
+}
+
+static int
+intel_present_crtc_pipe(ScreenPtr screen, RRCrtcPtr randr_crtc)
+{
+ xf86CrtcPtr crtc;
+
+ if (randr_crtc == NULL)
+ return 0;
+
+ crtc = randr_crtc->devPrivate;
+ return intel_crtc_to_pipe(crtc);
+}
+
+static int
+intel_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
+{
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ ScreenPtr screen = crtc->pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+
+ return intel_get_crtc_msc_ust(scrn, xf86_crtc, msc, ust);
+}
+
+/*
+ * Flush the DRM event queue when full; this
+ * makes space for new requests
+ */
+static Bool
+intel_present_flush_drm_events(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ return intel_mode_read_drm_events(intel) >= 0;
+}
+
+/*
+ * Called when the queued vblank event has occurred
+ */
+static void
+intel_present_vblank_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t msc, uint64_t usec, void *data)
+{
+ struct intel_present_vblank_event *event = data;
+
+ present_event_notify(event->event_id, usec, msc);
+ free(event);
+}
+
+/*
+ * Called when the queued vblank is aborted
+ */
+static void
+intel_present_vblank_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
+{
+ struct intel_present_vblank_event *event = data;
+
+ free(event);
+}
+
+/*
+ * Queue an event to report back to the Present extension when the specified
+ * MSC has past
+ */
+static int
+intel_present_queue_vblank(RRCrtcPtr crtc,
+ uint64_t event_id,
+ uint64_t msc)
+{
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ ScreenPtr screen = crtc->pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int pipe = intel_present_crtc_pipe(screen, crtc);
+ struct intel_present_vblank_event *event;
+ drmVBlank vbl;
+ int ret;
+ uint32_t seq;
+
+ event = calloc(sizeof (struct intel_present_vblank_event), 1);
+ if (!event)
+ return BadAlloc;
+ event->event_id = event_id;
+ seq = intel_drm_queue_alloc(scrn, xf86_crtc, event,
+ intel_present_vblank_handler,
+ intel_present_vblank_abort);
+ if (!seq) {
+ free(event);
+ return BadAlloc;
+ }
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
+ vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, xf86_crtc, msc);
+ vbl.request.signal = seq;
+ for (;;) {
+ ret = drmWaitVBlank(intel->drmSubFD, &vbl);
+ if (!ret)
+ break;
+ if (errno != EBUSY || !intel_present_flush_drm_events(screen))
+ return BadAlloc;
+ }
+ DebugPresent(("\t\tiq %lld seq %u msc %u (hw msc %u)\n", event_id, seq, low_msc, vbl.request.sequence));
+ return Success;
+}
+
+static Bool
+intel_present_event_match(void *data, void *match_data)
+{
+ struct intel_present_vblank_event *event = data;
+ uint64_t *match = match_data;
+
+ return *match == event->event_id;
+}
+
+
+/*
+ * Remove a pending vblank event from the DRM queue so that it is not reported
+ * to the extension
+ */
+static void
+intel_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
+{
+ ScreenPtr screen = crtc->pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+
+ intel_drm_abort (scrn, intel_present_event_match, &event_id);
+}
+
+/*
+ * Flush our batch buffer when requested by the Present extension.
+ */
+static void
+intel_present_flush(WindowPtr window)
+{
+ ScreenPtr screen = window->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (intel->needs_flush) {
+ if (intel->has_kernel_flush)
+ intel_batch_submit(intel->scrn);
+ else
+ intel_batch_emit_flush(intel->scrn);
+ }
+}
+
+/*
+ * Test to see if page flipping is possible on the target crtc
+ */
+static Bool
+intel_present_check_flip(RRCrtcPtr crtc,
+ WindowPtr window,
+ PixmapPtr pixmap,
+ Bool sync_flip)
+{
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ ScreenPtr screen = window->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+
+ if (!scrn->vtSema)
+ return FALSE;
+
+ if (intel->shadow_present)
+ return FALSE;
+
+ if (!intel->use_pageflipping)
+ return FALSE;
+
+ if (!intel_crtc_on(xf86_crtc))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Once the flip has been completed on all pipes, notify the
+ * extension code telling it when that happened
+ */
+
+static void
+intel_present_flip_event(uint64_t msc, uint64_t ust, void *pageflip_data)
+{
+ struct intel_present_vblank_event *event = pageflip_data;
+
+ present_event_notify(event->event_id, ust, msc);
+ free(event);
+}
+
+/*
+ * The flip has been aborted, free the structure
+ */
+static void
+intel_present_flip_abort(void *pageflip_data)
+{
+ struct intel_present_vblank_event *event = pageflip_data;
+
+ free(event);
+}
+
+/*
+ * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true,
+ * then wait for vblank. Otherwise, flip immediately
+ */
+
+static Bool
+intel_present_flip(RRCrtcPtr crtc,
+ uint64_t event_id,
+ uint64_t target_msc,
+ PixmapPtr pixmap,
+ Bool sync_flip)
+{
+ ScreenPtr screen = crtc->pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_present_vblank_event *event;
+ int pipe = intel_present_crtc_pipe(screen, crtc);
+ dri_bo *bo;
+ Bool ret;
+
+ if (!intel_crtc_on(xf86_crtc))
+ return FALSE;
+
+ bo = intel_get_pixmap_bo(pixmap);
+ if (!bo)
+ return FALSE;
+
+ event = calloc (1, sizeof (struct intel_present_vblank_event));
+ if (!event)
+ return FALSE;
+
+ event->event_id = event_id;
+
+ ret = intel_do_pageflip(intel, bo, pipe, !sync_flip,
+ event,
+ intel_present_flip_event,
+ intel_present_flip_abort);
+ if (!ret)
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "present flip failed\n");
+ return ret;
+}
+
+/*
+ * Queue a flip back to the normal frame buffer
+ */
+static void
+intel_present_unflip(ScreenPtr screen, uint64_t event_id)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_present_vblank_event *event;
+ PixmapPtr pixmap = screen->GetScreenPixmap(screen);
+ dri_bo *bo;
+ Bool ret;
+
+ bo = intel_get_pixmap_bo(pixmap);
+ if (!bo)
+ return;
+
+ event = calloc (1, sizeof (struct intel_present_vblank_event));
+ if (!event)
+ return;
+
+ event->event_id = event_id;
+
+ ret = intel_do_pageflip(intel, bo, 0, FALSE, event, intel_present_flip_event, intel_present_flip_abort);
+ if (!ret) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "present unflip failed\n");
+ }
+}
+
+static present_screen_info_rec intel_present_screen_info = {
+ .version = PRESENT_SCREEN_INFO_VERSION,
+
+ .get_crtc = intel_present_get_crtc,
+ .get_ust_msc = intel_present_get_ust_msc,
+ .queue_vblank = intel_present_queue_vblank,
+ .abort_vblank = intel_present_abort_vblank,
+ .flush = intel_present_flush,
+
+ .capabilities = PresentCapabilityNone,
+ .check_flip = intel_present_check_flip,
+ .flip = intel_present_flip,
+ .unflip = intel_present_unflip,
+};
+
+static Bool
+intel_present_has_async_flip(ScreenPtr screen)
+{
+#ifdef DRM_CAP_ASYNC_PAGE_FLIP
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ int ret;
+ uint64_t value;
+
+ ret = drmGetCap(intel->drmSubFD, DRM_CAP_ASYNC_PAGE_FLIP, &value);
+ if (ret == 0)
+ return value == 1;
+#endif
+ return FALSE;
+}
+
+Bool
+intel_present_screen_init(ScreenPtr screen)
+{
+ if (intel_present_has_async_flip(screen))
+ intel_present_screen_info.capabilities |= PresentCapabilityAsync;
+
+ return present_screen_init(screen, &intel_present_screen_info);
+}
--
1.8.4.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 0/4] xf86-video-intel DRI3 and Present patch series
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
2013-11-20 20:53 ` [PATCH 2/4] Restructure DRM event handling Keith Packard
2013-11-20 20:53 ` [PATCH 3/4] Add DRI3 and miSyncShm support Keith Packard
@ 2013-11-25 13:49 ` Chris Wilson
[not found] ` <20131125134951.GE21316-aII6DKEyn0pWYbfKqPwjAkR8Iwp7RQ6xAL8bYrjMMd8@public.gmane.org>
2 siblings, 1 reply; 7+ messages in thread
From: Chris Wilson @ 2013-11-25 13:49 UTC (permalink / raw)
To: Keith Packard
Cc: xorg-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
On Wed, Nov 20, 2013 at 12:53:33PM -0800, Keith Packard wrote:
> Here's a series of patches which provide DRI3 and Present support in
> the Intel 2D driver. The first two patches pave the way by
> synthesizing 64-bit vblank counters and extending the DRM event
> handling to allow for both DRI2 and DRI3 events. Then there's a patch
> to add DRI2 and miSyncShm support followed by a patch to add Present
> support.
>
> [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about
Some spurious assignments that appear to intentially drop the error code
could be clarified, and intel_crtc_msc_to_sequence() is always called
with a derived current_msc already to hand. The latter present path
obfuscates its derived current_msc.
> [PATCH 2/4] Restructure DRM event handling.
This won't compile against older Xorg due to xorg_list in the common
code.
> [PATCH 3/4] Add DRI3 and miSyncShm support
O_CLOEXEC needs protecting, also would appear to be candidate for a
render-node. The imported and exported DRI3 pixmaps need to be pinned
to prevent the driver using BO exchanges on that pixmap. DRI3 doesn't
respect the xorg.conf Option for disabling. A fence is only tied to a
screen and no XID or Client in particular? So it is a global operation
akin to intel_flush_callback() which would be called before the Sync
reply was sent.
> [PATCH 4/4] Add Present extension support
Yikes. The patch is itself fairly innoculous, but only because the Present
extension in the server appears to be repeating the worst of DRI2,
including its original bugs. The fallback/non-fullscreen case is not
synchronised to screen refresh (if the Client so desired), and should
be passed through to the driver. The whole driver interface seems to be
too low a level, baking in many assumptions, rather the usual approach of
providing a set of mi routines that the driver can plug into or not as the
case may be. That the WindowPixmap no longer points to the actual bo leads
to a few problems, such as the CRTC misconfiguration and GetImage being
broken after a PresentFlip. After a vblank_event, Present must check that
the flip is still valid before execution. In the backend it is not clear
whether the RRCrtc should be the primary CRTC or the only CRTC to flip.
Damage is processed after the fallback but not the Flip path, the lack
of Damage notification would upset Prime amongst others.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
xorg-devel-go0+a7rfsptAfugRpC6u6w@public.gmane.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/4] xf86-video-intel DRI3 and Present patch series
[not found] ` <20131125134951.GE21316-aII6DKEyn0pWYbfKqPwjAkR8Iwp7RQ6xAL8bYrjMMd8@public.gmane.org>
@ 2013-11-26 19:55 ` Keith Packard
0 siblings, 0 replies; 7+ messages in thread
From: Keith Packard @ 2013-11-26 19:55 UTC (permalink / raw)
To: Chris Wilson
Cc: xorg-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
intel-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
[-- Attachment #1.1: Type: text/plain, Size: 4241 bytes --]
Chris Wilson <chris-Y6uKTt2uX1cEflXRtASbqLVCufUGDwFn@public.gmane.org> writes:
>> [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about
>
> Some spurious assignments that appear to intentially drop the error code
> could be clarified,
I can't find any dropped error codes in this patch to add comments to,
please provide patch excerpts for this review.
> and intel_crtc_msc_to_sequence() is always called
> with a derived current_msc already to hand. The latter present path
> obfuscates its derived current_msc.
Present always computes absolute MSC values and provides those to the
driver, instead of expecting every driver to duplicate that logic.
>> [PATCH 2/4] Restructure DRM event handling.
>
> This won't compile against older Xorg due to xorg_list in the common
> code.
Can switch to intel_list, but that would need list_for_each_entry_safe
added. How many versions back is this supposed to compile against?
>> [PATCH 3/4] Add DRI3 and miSyncShm support
>
> O_CLOEXEC needs protecting, also would appear to be candidate for a
> render-node.
Yes, obviously this wants to use render-node. I haven't had complaints
about O_CLOEXEC from BSD or Solaris developers for libxshmfence; what
systems do not have support for this?
> The imported and exported DRI3 pixmaps need to be pinned
> to prevent the driver using BO exchanges on that pixmap.
I don't understand this comment.
> DRI3 doesn't respect the xorg.conf Option for disabling.
Ok, it should check intel->directRenderingType == DRI_DISABLED.
> A fence is only tied to a
> screen and no XID or Client in particular?
DRI3 fences are screen-specific (otherwise you'd have no way of hooking
the fence to a specific driver).
> So it is a global operation
> akin to intel_flush_callback() which would be called before the Sync
> reply was sent.
Yes, the hardware queue is to be flushed before the Sync event is sent
(and before the xshmfence object is triggered, of course). Note that
this is just the mi version of sync fences, which use libxshmfence; the
driver is free to use different code there. If we find that the code for
handling these xshmfence objects is common across drivers, we can move
that into the X server to share.
>> [PATCH 4/4] Add Present extension support
>
> Yikes. The patch is itself fairly innoculous, but only because the Present
> extension in the server appears to be repeating the worst of DRI2,
> including its original bugs.
Please provide more specific comments here.
> The fallback/non-fullscreen case is not
> synchronised to screen refresh (if the Client so desired), and should
> be passed through to the driver.
The fallback case is synchronized as the Present code triggers the
CopyArea call from the vblank hook. In practice, this has proven
sufficient to get images onto the screen without tearing and without
requiring a huge amount of driver and kernel infrastructure.
> The whole driver interface seems to be too low a level, baking in many
> assumptions, rather the usual approach of providing a set of mi
> routines that the driver can plug into or not as the case may be.
Patches to the X server to change the API for better hardware support
are welcome, of course.
> That the WindowPixmap no longer points to the actual bo leads
> to a few problems, such as the CRTC misconfiguration and GetImage being
> broken after a PresentFlip.
A patch for the X server to fix that has been posted.
> After a vblank_event, Present must check that
> the flip is still valid before execution.
The flip proc may return FALSE to indicate failure of any kind. Present
will then fall-back to a simple blt.
> In the backend it is not clear whether the RRCrtc should be the
> primary CRTC or the only CRTC to flip.
There is only one screen pixmap, so of course every CRTC must flip
together. The CRTC provided indicates which one the MSC is from.
> Damage is processed after the fallback but not the Flip path, the lack
> of Damage notification would upset Prime amongst others.
Sounds easy to fix in the X server.
Thanks for your review!
--
keith.packard-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
[-- Attachment #1.2: Type: application/pgp-signature, Size: 827 bytes --]
[-- Attachment #2: Type: text/plain, Size: 219 bytes --]
_______________________________________________
xorg-devel-go0+a7rfsptAfugRpC6u6w@public.gmane.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-11-26 19:55 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-20 20:53 [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Keith Packard
2013-11-20 20:53 ` [PATCH 1/4] Support 64-bit MSC values. Handle kernel vageries about MSC reporting Keith Packard
[not found] ` <1384980817-20535-1-git-send-email-keithp-aN4HjG94KOLQT0dZR+AlfA@public.gmane.org>
2013-11-20 20:53 ` [PATCH 2/4] Restructure DRM event handling Keith Packard
2013-11-20 20:53 ` [PATCH 3/4] Add DRI3 and miSyncShm support Keith Packard
2013-11-25 13:49 ` [PATCH 0/4] xf86-video-intel DRI3 and Present patch series Chris Wilson
[not found] ` <20131125134951.GE21316-aII6DKEyn0pWYbfKqPwjAkR8Iwp7RQ6xAL8bYrjMMd8@public.gmane.org>
2013-11-26 19:55 ` Keith Packard
2013-11-20 20:53 ` [PATCH 4/4] Add Present extension support Keith Packard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox