xf86-video-intel: src/sna/sna_dri.c

Chris Wilson ickle at kemper.freedesktop.org
Sat Jun 23 09:44:41 PDT 2012


 src/sna/sna_dri.c |  314 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 243 insertions(+), 71 deletions(-)

New commits:
commit fa10005ce31483827547b7f71eae066899f0026c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jun 23 17:28:00 2012 +0100

    sna/dri: Perform an exchange for a composited windowed SwapBuffers
    
    If the front buffer is not attached to the scanout and has not been
    reparented, we can simply exchange the underlying bo between the
    front/back attachments and inform the compositor of the damage.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index a323b4e..3c5722c 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -60,6 +60,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 enum frame_event_type {
 	DRI2_SWAP,
 	DRI2_SWAP_THROTTLE,
+	DRI2_XCHG_THROTTLE,
 	DRI2_ASYNC_FLIP,
 	DRI2_FLIP,
 	DRI2_FLIP_THROTTLE,
@@ -1075,6 +1076,45 @@ can_flip(struct sna * sna,
 	return TRUE;
 }
 
+static Bool
+can_exchange(struct sna * sna,
+	     DrawablePtr draw,
+	     DRI2BufferPtr front,
+	     DRI2BufferPtr back)
+{
+	WindowPtr win = (WindowPtr)draw;
+	PixmapPtr pixmap;
+
+	if (draw->type == DRAWABLE_PIXMAP)
+		return TRUE;
+
+	if (front->format != back->format) {
+		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
+		     __FUNCTION__, front->format, back->format));
+		return FALSE;
+	}
+
+	pixmap = get_window_pixmap(win);
+	if (pixmap == sna->front) {
+		DBG(("%s: no, window is attached to the front buffer\n",
+		     __FUNCTION__));
+		return FALSE;
+	}
+
+	if (pixmap->drawable.width != win->drawable.width ||
+	    pixmap->drawable.height != win->drawable.height) {
+		DBG(("%s: no, window has been reparented, window size %dx%d, parent %dx%d\n",
+		     __FUNCTION__,
+		     win->drawable.width,
+		     win->drawable.height,
+		     pixmap->drawable.width,
+		     pixmap->drawable.height));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 inline static uint32_t pipe_select(int pipe)
 {
 	/* The third pipe was introduced with IvyBridge long after
@@ -1090,6 +1130,75 @@ inline static uint32_t pipe_select(int pipe)
 		return 0;
 }
 
+static void
+sna_dri_exchange_buffers(DrawablePtr draw,
+			 DRI2BufferPtr front,
+			 DRI2BufferPtr back)
+{
+	struct kgem_bo *back_bo, *front_bo;
+	PixmapPtr pixmap;
+	int tmp;
+
+	pixmap = get_drawable_pixmap(draw);
+
+	back_bo = get_private(back)->bo;
+	front_bo = get_private(front)->bo;
+
+	DBG(("%s: exchange front=%d/%d and back=%d/%d\n",
+	     __FUNCTION__,
+	     front_bo->handle, front->name,
+	     back_bo->handle, back->name));
+
+	set_bo(pixmap, back_bo);
+
+	get_private(front)->bo = back_bo;
+	get_private(back)->bo = front_bo;
+
+	tmp = front->name;
+	front->name = back->name;
+	back->name = tmp;
+}
+
+static void chain_swap(struct sna *sna,
+		       DrawablePtr draw,
+		       struct drm_event_vblank *event,
+		       struct sna_dri_frame_event *chain)
+{
+	drmVBlank vbl;
+	int type;
+
+	/* In theory, it shoudln't be possible for cross-chaining to occur! */
+	if (chain->type == DRI2_XCHG_THROTTLE) {
+		DBG(("%s: performing chained exchange\n", __FUNCTION__));
+		sna_dri_exchange_buffers(draw, chain->front, chain->back);
+		type = DRI2_EXCHANGE_COMPLETE;
+	} else {
+		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
+
+		chain->bo = sna_dri_copy_to_front(sna, draw, NULL,
+						  get_private(chain->front)->bo,
+						  get_private(chain->back)->bo,
+						 true);
+
+		type = DRI2_BLIT_COMPLETE;
+	}
+
+	DRI2SwapComplete(chain->client, draw,
+			 event->sequence, event->tv_sec, event->tv_usec,
+			 type, chain->client ? chain->event_complete : NULL, chain->event_data);
+
+	VG_CLEAR(vbl);
+	vbl.request.type =
+		DRM_VBLANK_RELATIVE |
+		DRM_VBLANK_NEXTONMISS |
+		DRM_VBLANK_EVENT |
+		pipe_select(chain->pipe);
+	vbl.request.sequence = 0;
+	vbl.request.signal = (unsigned long)chain;
+	if (sna_wait_vblank(sna, &vbl))
+		sna_dri_frame_event_info_free(sna, chain);
+}
+
 void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 {
 	struct sna_dri_frame_event *info = (void *)(uintptr_t)event->user_data;
@@ -1153,36 +1262,11 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 
 		if (info->chain) {
 			struct sna_dri_frame_event *chain = info->chain;
-			drmVBlank vbl;
-
-			DBG(("%s: emitting chained vsync'ed blit\n",
-			     __FUNCTION__));
 
 			assert(get_private(info->front)->chain == info);
 			get_private(info->front)->chain = chain;
 
-			chain->bo = sna_dri_copy_to_front(sna, draw, NULL,
-							  get_private(chain->front)->bo,
-							  get_private(chain->back)->bo,
-							  true);
-
-			DRI2SwapComplete(chain->client,
-					 draw, event->sequence,
-					 event->tv_sec, event->tv_usec,
-					 DRI2_BLIT_COMPLETE,
-					 chain->client ? chain->event_complete : NULL,
-					 chain->event_data);
-
-			VG_CLEAR(vbl);
-			vbl.request.type =
-				DRM_VBLANK_RELATIVE |
-				DRM_VBLANK_NEXTONMISS |
-				DRM_VBLANK_EVENT |
-				pipe_select(chain->pipe);
-			vbl.request.sequence = 0;
-			vbl.request.signal = (unsigned long)chain;
-			if (sna_wait_vblank(sna, &vbl))
-				sna_dri_frame_event_info_free(sna, chain);
+			chain_swap(sna, draw, event, chain);
 
 			info->chain = NULL;
 		} else if (get_private(info->front)->chain == info) {
@@ -1200,6 +1284,24 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 		}
 		break;
 
+	case DRI2_XCHG_THROTTLE:
+		DBG(("%s: xchg throttle\n", __FUNCTION__));
+
+		if (info->chain) {
+			struct sna_dri_frame_event *chain = info->chain;
+
+			assert(get_private(info->front)->chain == info);
+			get_private(info->front)->chain = chain;
+
+			chain_swap(sna, draw, event, chain);
+
+			info->chain = NULL;
+		} else {
+			DBG(("%s: chain complete\n", __FUNCTION__));
+			get_private(info->front)->chain = NULL;
+		}
+		break;
+
 	case DRI2_WAITMSC:
 		if (info->client)
 			DRI2WaitMSCComplete(info->client, draw,
@@ -1601,6 +1703,108 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	return TRUE;
 }
 
+static void
+sna_dri_immediate_xchg(struct sna *sna,
+		       DrawablePtr draw,
+		       struct sna_dri_frame_event *info)
+{
+	struct sna_dri_private *priv = get_private(info->front);
+	drmVBlank vbl;
+
+	DBG(("%s: emitting immediate exchange, throttling client\n", __FUNCTION__));
+
+	if ((sna->flags & SNA_NO_WAIT) == 0) {
+		info->type = DRI2_XCHG_THROTTLE;
+		if (priv->chain == NULL) {
+			DBG(("%s: no pending xchg, starting chain\n",
+			     __FUNCTION__));
+
+			sna_dri_exchange_buffers(draw, info->front, info->back);
+			DRI2SwapComplete(info->client, draw, 0, 0, 0,
+					 DRI2_EXCHANGE_COMPLETE,
+					 info->event_complete,
+					 info->event_data);
+			vbl.request.type =
+				DRM_VBLANK_RELATIVE |
+				DRM_VBLANK_NEXTONMISS |
+				DRM_VBLANK_EVENT |
+				pipe_select(info->pipe);
+			vbl.request.sequence = 0;
+			vbl.request.signal = (unsigned long)info;
+			if (sna_wait_vblank(sna, &vbl) == 0)
+				priv->chain = info;
+			else
+				sna_dri_frame_event_info_free(sna, info);
+		} else {
+			DBG(("%s: attaching to vsync chain\n",
+			     __FUNCTION__));
+			assert(priv->chain->chain == NULL);
+			priv->chain->chain = info;
+		}
+	} else {
+		DRI2SwapComplete(info->client, draw, 0, 0, 0,
+				 DRI2_EXCHANGE_COMPLETE,
+				 info->event_complete,
+				 info->event_data);
+		sna_dri_frame_event_info_free(sna, info);
+	}
+}
+
+static void
+sna_dri_immediate_blit(struct sna *sna,
+		       DrawablePtr draw,
+		       struct sna_dri_frame_event *info)
+{
+	struct sna_dri_private *priv = get_private(info->front);
+	drmVBlank vbl;
+
+	DBG(("%s: emitting immediate blit, throttling client\n", __FUNCTION__));
+
+	if ((sna->flags & SNA_NO_WAIT) == 0) {
+		info->type = DRI2_SWAP_THROTTLE;
+		if (priv->chain == NULL) {
+			DBG(("%s: no pending blit, starting chain\n",
+			     __FUNCTION__));
+
+			info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+							 get_private(info->front)->bo,
+							 get_private(info->back)->bo,
+							 true);
+			DRI2SwapComplete(info->client, draw, 0, 0, 0,
+					 DRI2_BLIT_COMPLETE,
+					 info->event_complete,
+					 info->event_data);
+
+			vbl.request.type =
+				DRM_VBLANK_RELATIVE |
+				DRM_VBLANK_NEXTONMISS |
+				DRM_VBLANK_EVENT |
+				pipe_select(info->pipe);
+			vbl.request.sequence = 0;
+			vbl.request.signal = (unsigned long)info;
+			if (sna_wait_vblank(sna, &vbl) == 0)
+				priv->chain = info;
+			else
+				sna_dri_frame_event_info_free(sna, info);
+		} else {
+			DBG(("%s: attaching to vsync chain\n",
+			     __FUNCTION__));
+			assert(priv->chain->chain == NULL);
+			priv->chain->chain = info;
+		}
+	} else {
+		info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+						 get_private(info->front)->bo,
+						 get_private(info->back)->bo,
+						 true);
+		DRI2SwapComplete(info->client, draw, 0, 0, 0,
+				 DRI2_BLIT_COMPLETE,
+				 info->event_complete,
+				 info->event_data);
+		sna_dri_frame_event_info_free(sna, info);
+	}
+}
+
 /*
  * ScheduleSwap is responsible for requesting a DRM vblank event for the
  * appropriate frame.
@@ -1654,6 +1858,15 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	/* Drawable not displayed... just complete the swap */
 	pipe = sna_dri_get_pipe(draw);
 	if (pipe == -1) {
+		if (can_exchange(sna, draw, front, back)) {
+			DBG(("%s: unattached, exchange pixmaps\n", __FUNCTION__));
+			sna_dri_exchange_buffers(draw, front, back);
+
+			DRI2SwapComplete(client, draw, 0, 0, 0,
+					 DRI2_EXCHANGE_COMPLETE, func, data);
+			return TRUE;
+		}
+
 		DBG(("%s: off-screen, immediate update\n", __FUNCTION__));
 		goto blit_fallback;
 	}
@@ -1690,51 +1903,10 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	info->type = swap_type;
 	if (divisor == 0) {
-		DBG(("%s: emitting immediate vsync'ed blit, throttling client\n",
-		     __FUNCTION__));
-
-		if ((sna->flags & SNA_NO_WAIT) == 0) {
-			struct sna_dri_private *priv = get_private(front);
-
-			info->type = DRI2_SWAP_THROTTLE;
-			if (priv->chain == NULL) {
-				DBG(("%s: no pending blit, starting chain\n",
-				     __FUNCTION__));
-
-				info->bo = sna_dri_copy_to_front(sna, draw, NULL,
-								 get_private(front)->bo,
-								 get_private(back)->bo,
-								 true);
-
-				DRI2SwapComplete(client, draw, 0, 0, 0,
-						 DRI2_BLIT_COMPLETE, func, data);
-				vbl.request.type =
-					DRM_VBLANK_RELATIVE |
-					DRM_VBLANK_NEXTONMISS |
-					DRM_VBLANK_EVENT |
-					pipe_select(pipe);
-				vbl.request.sequence = 0;
-				vbl.request.signal = (unsigned long)info;
-				if (sna_wait_vblank(sna, &vbl) == 0) {
-					priv->chain = info;
-					return TRUE;
-				}
-			} else {
-				DBG(("%s: attaching to vsync chain\n",
-				     __FUNCTION__));
-				assert(priv->chain->chain == NULL);
-				priv->chain->chain = info;
-				return TRUE;
-			}
-		} else {
-			info->bo = sna_dri_copy_to_front(sna, draw, NULL,
-							 get_private(front)->bo,
-							 get_private(back)->bo,
-							 true);
-		}
-
-		sna_dri_frame_event_info_free(sna, info);
-		DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+		if (can_exchange(sna, draw, info->front, info->back))
+			sna_dri_immediate_xchg(sna, draw, info);
+		else
+			sna_dri_immediate_blit(sna, draw, info);
 		return TRUE;
 	}
 


More information about the xorg-commit mailing list