[PATCH 2/4] Restructure DRM event handling.

Keith Packard keithp at keithp.com
Wed Nov 20 12:53:35 PST 2013


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 at keithp.com>
---
 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



More information about the xorg-devel mailing list