diff mbox

[1/2] sna/video sprite patch: support for multiple xv ports (exposes minimum Xv ports)

Message ID 1462276827-3778-1-git-send-email-michaelx.hadley@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Michael Hadley May 3, 2016, noon UTC
The current driver exposes a single adaptor port so that only one Xv video
can be played using a single sprite at a given time. This change will allow
available hardware sprites to be used. Exposes the minimum Xv sprite ports
to be compatible with older X11.

v2: function sna_video_num_sprites() checks and returns the minimum number
    of hardware sprites available on the adaptor for combatibility reasons.

v1: updated patch from lornax.mcneill@intel.com. removed/added
    whitespace, re-formatted code, removed redundent variable allocation.

Signed-off-by: Michael Hadley <michaelx.hadley@intel.com>
---
 src/sna/sna.h              |   7 +-
 src/sna/sna_display.c      | 188 +++++++++++++++++++++++++++++++++++++++------
 src/sna/sna_video_sprite.c | 139 ++++++++++++++++++---------------
 3 files changed, 249 insertions(+), 85 deletions(-)
diff mbox

Patch

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 664308f..88bf145 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -610,8 +610,11 @@  static inline void sna_present_vblank_handler(struct drm_event_vblank *event) {
 static inline void sna_present_cancel_flip(struct sna *sna) { }
 #endif
 
-extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
-extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
+extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation, DrawablePtr draw);
+extern uint32_t sna_crtc_num_sprites(xf86CrtcPtr crtc);
+extern bool sna_crtc_drawable_to_sprite_id(xf86CrtcPtr crtc, DrawablePtr draw, uint32_t *id);
+extern bool sna_crtc_sprite_lock(xf86CrtcPtr crtc, DrawablePtr draw);
+extern void sna_crtc_sprite_unlock(xf86CrtcPtr crtc, DrawablePtr draw);
 extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
 
 #define CRTC_VBLANK 0x3
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 759659d..8b0ae72 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -222,7 +222,15 @@  struct sna_crtc {
 			uint32_t supported;
 			uint32_t current;
 		} rotation;
-	} primary, sprite;
+	} primary;
+
+	struct sprite {
+		struct plane plane;
+		DrawablePtr locked_to; /* drawable the sprite was grabbed for */
+		struct xorg_list link;
+	} sprite;
+
+	struct xorg_list sprites; /* sprites that can be displayed on this crtc */
 
 	uint32_t mode_serial, flip_serial;
 
@@ -444,10 +452,109 @@  static inline uint32_t fb_id(struct kgem_bo *bo)
 	return bo->delta;
 }
 
-uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
+uint32_t sna_crtc_num_sprites(xf86CrtcPtr crtc)
+{
+	struct sna_crtc *sna_crtc;
+	struct sprite *sp = NULL;
+	uint32_t num_sprites = 0;
+
+	sna_crtc = to_sna_crtc(crtc);
+
+	xorg_list_for_each_entry(sp, &sna_crtc->sprites, link) {
+		num_sprites++;
+	}
+
+	DBG(("%s: %d sprites\n", __FUNCTION__, num_sprites));
+
+	return num_sprites;
+}
+
+/*
+ * return the sprite attached to the specified crtc
+ * and locked to the specified drawable if there is one.
+ */
+static struct sprite * sna_crtc_drawable_to_sprite(xf86CrtcPtr crtc, DrawablePtr draw)
+{
+	struct sna_crtc *sna_crtc;
+	struct sprite *sp = NULL;
+
+	sna_crtc = to_sna_crtc(crtc);
+
+	xorg_list_for_each_entry(sp, &sna_crtc->sprites, link) {
+		if (sp->locked_to == draw) {
+			return sp;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * gets the sprite id for the sprite attached to the specified crtc
+ * and locked to the specified drawable if there is one.
+ */
+bool sna_crtc_drawable_to_sprite_id(xf86CrtcPtr crtc, DrawablePtr draw, uint32_t *sprite_id)
+{
+	struct sprite *sp = sna_crtc_drawable_to_sprite(crtc, draw);
+
+	if (sp) {
+		*sprite_id = sp->plane.id;
+		return true;
+	}
+	return false;
+}
+
+static void sprite_disable(struct sprite *sp, struct sna *sna)
+{
+	struct local_mode_set_plane s;
+
+	DBG(("%s: unlocking sprite %d\n", __FUNCTION__, sp->plane.id));
+	memset(&s, 0, sizeof(s));
+	s.plane_id = sp->plane.id;
+	if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
+		xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, "failed to disable plane\n");
+}
+
+/*
+ * If there's a sprite on this crtc using the specified drawable, then unlock
+ * it and disable the sprite
+ */
+void sna_crtc_sprite_unlock(xf86CrtcPtr crtc, DrawablePtr draw)
 {
+	struct sprite *sp = NULL;
+	struct sna *sna = to_sna(crtc->scrn);
+
 	assert(to_sna_crtc(crtc));
-	return to_sna_crtc(crtc)->sprite.id;
+
+	if ((sp = sna_crtc_drawable_to_sprite(crtc, draw))) {
+		sprite_disable(sp, sna);
+		sp->locked_to = NULL;
+	}
+}
+
+/*
+ * Lock one of this crtc's sprites to this drawable
+ * if haven't already and there is one available  */
+bool sna_crtc_sprite_lock(xf86CrtcPtr crtc, DrawablePtr draw)
+{
+	struct sna_crtc *sna_crtc;
+	struct sprite *sp = NULL;
+
+	sna_crtc = to_sna_crtc(crtc);
+	assert(to_sna_crtc(crtc));
+
+	sp = sna_crtc_drawable_to_sprite(crtc, draw);
+	if (!sp) {
+		xorg_list_for_each_entry(sp, &sna_crtc->sprites, link) {
+			if (!sp->locked_to) {
+				DBG(("%s: locking sprite %d\n", __FUNCTION__, sp->plane.id));
+				sp->locked_to = draw;
+				return true;
+			}
+		}
+		DBG(("%s: No free sprites\n", __FUNCTION__));
+		return false;
+	}
+	return true;
 }
 
 bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
@@ -1245,17 +1352,20 @@  rotation_reset(struct plane *p)
 	p->rotation.current = 0;
 }
 
-bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation)
+bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation, DrawablePtr draw)
 {
-	assert(to_sna_crtc(crtc));
-	DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
-	     __FUNCTION__,
-	     sna_crtc_id(crtc), sna_crtc_pipe(crtc),
-	     to_sna_crtc(crtc)->sprite.id, rotation));
+	struct sprite *sp = NULL;
 
-	return rotation_set(to_sna(crtc->scrn),
-			    &to_sna_crtc(crtc)->sprite,
-			    rotation_reduce(&to_sna_crtc(crtc)->sprite, rotation));
+	sp = sna_crtc_drawable_to_sprite(crtc, draw);
+	if (sp) {
+		DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
+				__FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc),
+				sp->plane.id, rotation));
+		if (!rotation_set(to_sna(crtc->scrn),
+				&sp->plane, rotation_reduce(&sp->plane, rotation)))
+			return FALSE;
+       }
+	return true;
 }
 
 #if HAS_DEBUG_FULL
@@ -2992,11 +3102,15 @@  sna_crtc_gamma_set(xf86CrtcPtr crtc,
 static void
 sna_crtc_destroy(xf86CrtcPtr crtc)
 {
+	struct sprite *sp = NULL, *tmp = NULL;
 	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
 
 	if (sna_crtc == NULL)
 		return;
 
+	xorg_list_for_each_entry_safe( sp, tmp, &sna_crtc->sprites, link)
+		free(sp);
+
 	free(sna_crtc);
 	crtc->driver_private = NULL;
 }
@@ -3219,9 +3333,19 @@  sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
 			break;
 
 		case DRM_PLANE_TYPE_OVERLAY:
-			if (crtc->sprite.id == 0)
-				crtc->sprite = details;
-			break;
+			{
+				struct sprite *s = calloc(1, sizeof( struct sprite ));
+
+				if (s) {
+					s->locked_to = NULL;
+					s->plane = details;
+					xorg_list_append(&s->link, &crtc->sprites);
+				} else
+					DBG(("%s: Could not allocate memory for sprite \n",
+							__FUNCTION__));
+
+				break;
+			}
 		}
 	}
 
@@ -3232,10 +3356,14 @@  sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
 static void
 sna_crtc_init__rotation(struct sna *sna, struct sna_crtc *crtc)
 {
+	struct sprite *sp = NULL;
+
 	crtc->rotation = RR_Rotate_0;
 	crtc->primary.rotation.supported = RR_Rotate_0;
 	crtc->primary.rotation.current = RR_Rotate_0;
-	crtc->sprite.rotation = crtc->primary.rotation;
+
+	xorg_list_for_each_entry(sp, &crtc->sprites, link)
+		sp->plane.rotation = crtc->primary.rotation;
 }
 
 static void
@@ -3260,6 +3388,8 @@  sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
 	xf86CrtcPtr crtc;
 	struct sna_crtc *sna_crtc;
 	struct drm_i915_get_pipe_from_crtc_id get_pipe;
+	int sprite_count = 0;
+	struct sprite *sprite;
 
 	DBG(("%s(%d): is-zaphod? %d\n", __FUNCTION__, id, is_zaphod(scrn)));
 
@@ -3287,14 +3417,22 @@  sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
 		return true;
 	}
 
+	xorg_list_init(&sna_crtc->sprites);
+
 	sna_crtc_init__rotation(sna, sna_crtc);
 
 	sna_crtc_find_planes(sna, sna_crtc);
 
-	DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n",
-	     __FUNCTION__, id, get_pipe.pipe,
-	     sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current,
-	     sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current));
+	DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x,"
+			" current-rotation=%x\n", __FUNCTION__, id, get_pipe.pipe,
+			sna_crtc->primary.id, sna_crtc->primary.rotation.supported,
+			sna_crtc->primary.rotation.current));
+
+	DBG(("Sprites added to CRTC: %d \n", id));
+	xorg_list_for_each_entry(sprite, &sna_crtc->sprites, link) {
+		sprite_count++;
+		DBG(("Sprite: %d, plane ID = %d \n", sprite_count, sprite->plane.id));
+	}
 
 	list_init(&sna_crtc->shadow_link);
 
@@ -8013,6 +8151,7 @@  static bool
 sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
 {
 	struct local_mode_set_plane s;
+	struct sprite *sp = NULL;
 
 	if (crtc->primary.id == 0)
 		return false;
@@ -8022,8 +8161,8 @@  sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
 	if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
 		return false;
 
-	s.plane_id = crtc->sprite.id;
-	(void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s);
+	xorg_list_for_each_entry(sp, &crtc->sprites, link)
+		sprite_disable(sp, sna);
 
 	__sna_crtc_disable(sna, crtc);
 	return true;
@@ -8046,13 +8185,16 @@  void sna_mode_reset(struct sna *sna)
 	assert(sna->mode.front_active == 0);
 
 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
+		struct sprite *sp = NULL;
 		struct sna_crtc *sna_crtc = to_sna_crtc(config->crtc[i]);
 
 		assert(sna_crtc != NULL);
 
 		/* Force the rotation property to be reset on next use */
 		rotation_reset(&sna_crtc->primary);
-		rotation_reset(&sna_crtc->sprite);
+
+		xorg_list_for_each_entry(sp, &sna_crtc->sprites, link)
+			rotation_reset(&sp->plane);
 	}
 
 	/* VT switching, likely to be fbcon so make the backlight usable */
diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c
index 1498707..943be59 100644
--- a/src/sna/sna_video_sprite.c
+++ b/src/sna/sna_video_sprite.c
@@ -77,7 +77,6 @@  static const XvAttributeRec attribs[] = {
 static int sna_video_sprite_stop(ddStopVideo_ARGS)
 {
 	struct sna_video *video = port->devPriv.ptr;
-	struct local_mode_set_plane s;
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn);
 	int i;
 
@@ -90,11 +89,7 @@  static int sna_video_sprite_stop(ddStopVideo_ARGS)
 		if (video->bo[pipe] == NULL)
 			continue;
 
-		memset(&s, 0, sizeof(s));
-		s.plane_id = sna_crtc_to_sprite(crtc);
-		if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
-			xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
-				   "failed to disable plane\n");
+		sna_crtc_sprite_unlock(crtc, draw);
 
 		if (video->bo[pipe])
 			kgem_bo_destroy(&video->sna->kgem, video->bo[pipe]);
@@ -216,6 +211,7 @@  sna_video_sprite_show(struct sna *sna,
 		      struct sna_video *video,
 		      struct sna_video_frame *frame,
 		      xf86CrtcPtr crtc,
+		      DrawablePtr draw,
 		      BoxPtr dstBox)
 {
 	struct local_mode_set_plane s;
@@ -224,7 +220,12 @@  sna_video_sprite_show(struct sna *sna,
 	/* XXX handle video spanning multiple CRTC */
 
 	VG_CLEAR(s);
-	s.plane_id = sna_crtc_to_sprite(crtc);
+
+	if(!sna_crtc_drawable_to_sprite_id(crtc, draw, &s.plane_id)) {
+		ERR(("%s: no sprite for this drawable\n", __FUNCTION__));
+		return false;
+	}
+
 
 #define DRM_I915_SET_SPRITE_COLORKEY 0x2b
 #define LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct local_intel_sprite_colorkey)
@@ -420,12 +421,9 @@  static int sna_video_sprite_put_image(ddPutImage_ARGS)
 off:
 			assert(pipe < ARRAY_SIZE(video->bo));
 			if (video->bo[pipe]) {
-				struct local_mode_set_plane s;
-				memset(&s, 0, sizeof(s));
-				s.plane_id = sna_crtc_to_sprite(crtc);
-				if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
-					xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
-						   "failed to disable plane\n");
+				DBG(("%s: unlock sprite as no longer intersects\n", __FUNCTION__));
+				/* image no longer on sprite plane, unlock sprite */
+				sna_crtc_sprite_unlock(crtc, draw);
 				video->bo[pipe] = NULL;
 			}
 			continue;
@@ -444,6 +442,14 @@  off:
 		if (!ret)
 			goto off;
 
+		ret = sna_crtc_sprite_lock(crtc, draw);
+		if (!ret) {
+			xf86DrvMsg(sna->scrn->scrnIndex,
+					X_ERROR, "failed to get a sprite plane \n");
+
+			goto err;
+		}
+
 		frame.src.x1 = x1 >> 16;
 		frame.src.y1 = y1 >> 16;
 		frame.src.x2 = (x2 + 0xffff) >> 16;
@@ -461,8 +467,8 @@  off:
 
 		/* if sprite can't handle rotation natively, store it for the copy func */
 		rotation = RR_Rotate_0;
-		if (!sna_crtc_set_sprite_rotation(crtc, crtc->rotation)) {
-			sna_crtc_set_sprite_rotation(crtc, RR_Rotate_0);
+		if (!sna_crtc_set_sprite_rotation(crtc, crtc->rotation, draw)) {
+			sna_crtc_set_sprite_rotation(crtc, RR_Rotate_0, draw);
 			rotation = crtc->rotation;
 		}
 		sna_video_frame_set_rotation(video, &frame, rotation);
@@ -564,7 +570,7 @@  off:
 		}
 
 		ret = Success;
-		if (!sna_video_sprite_show(sna, video, &frame, crtc, &dst)) {
+		if (!sna_video_sprite_show(sna, video, &frame, crtc, draw, &dst)) {
 			DBG(("%s: failed to show video frame\n", __FUNCTION__));
 			ret = BadAlloc;
 		}
@@ -651,45 +657,53 @@  static int sna_video_sprite_color_key(struct sna *sna)
 	return color_key & ((1 << scrn->depth) - 1);
 }
 
-static bool sna_video_has_sprites(struct sna *sna)
+static uint32_t sna_video_num_sprites(struct sna *sna)
 {
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
-	int i;
+	int i, curr_n = 0, min_n = 0;
 
 	DBG(("%s: num_crtc=%d\n", __FUNCTION__, sna->mode.num_real_crtc));
 
 	if (sna->mode.num_real_crtc == 0)
-		return false;
+		return 0;
 
+	/* Loop through each real pipe and record the min number of sprites */
 	for (i = 0; i < sna->mode.num_real_crtc; i++) {
-		if (!sna_crtc_to_sprite(config->crtc[i])) {
-			DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_pipe(config->crtc[i])));
-			return false;
+		curr_n  = sna_crtc_num_sprites(config->crtc[i]);
+
+		if (i == 0) {
+			min_n = curr_n;
+			continue;
 		}
+
+		if (curr_n < min_n)
+			min_n = curr_n;
 	}
 
-	DBG(("%s: yes\n", __FUNCTION__));
-	return true;
+	DBG(("%s: %d sprites\n", __FUNCTION__, min_n));
+	return min_n;
 }
 
 void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
 {
 	XvAdaptorPtr adaptor;
 	struct sna_video *video;
-	XvPortPtr port;
+	uint32_t i, nports = 0;
+
+	nports = sna_video_num_sprites(sna);
 
-	if (!sna_video_has_sprites(sna))
+	if (!nports)
 		return;
 
 	adaptor = sna_xv_adaptor_alloc(sna);
 	if (!adaptor)
 		return;
 
-	video = calloc(1, sizeof(*video));
-	port = calloc(1, sizeof(*port));
-	if (video == NULL || port == NULL) {
+	video = calloc(nports, sizeof(*video));
+	adaptor->pPorts = calloc(nports, sizeof(XvPortRec));
+	if (video == NULL || adaptor->pPorts == NULL) {
 		free(video);
-		free(port);
+		free(adaptor->pPorts);
 		sna->xv.num_adaptors--;
 		return;
 	}
@@ -731,36 +745,41 @@  void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
 	adaptor->ddPutImage = sna_video_sprite_put_image;
 	adaptor->ddQueryImageAttributes = sna_video_sprite_query;
 
-	adaptor->nPorts = 1;
-	adaptor->pPorts = port;
-
-	adaptor->base_id = port->id = FakeClientID(0);
-	AddResource(port->id, XvGetRTPort(), port);
-	port->pAdaptor = adaptor;
-	port->pNotify =  NULL;
-	port->pDraw =  NULL;
-	port->client =  NULL;
-	port->grab.client =  NULL;
-	port->time = currentTime;
-	port->devPriv.ptr = video;
-
-	video->sna = sna;
-	video->alignment = 64;
-	video->color_key = sna_video_sprite_color_key(sna);
-	video->color_key_changed = ~0;
-	video->has_color_key = true;
-	video->brightness = -19;	/* (255/219) * -16 */
-	video->contrast = 75;	/* 255/219 * 64 */
-	video->saturation = 146;	/* 128/112 * 128 */
-	video->desired_crtc = NULL;
-	video->gamma5 = 0xc0c0c0;
-	video->gamma4 = 0x808080;
-	video->gamma3 = 0x404040;
-	video->gamma2 = 0x202020;
-	video->gamma1 = 0x101010;
-	video->gamma0 = 0x080808;
-	RegionNull(&video->clip);
-	video->SyncToVblank = 1;
+	for (i = 0; i < nports; ++i) {
+		struct sna_video *v = &video[i];
+		XvPortPtr port = &adaptor->pPorts[i];
+
+		port->id = FakeClientID(0);
+		AddResource(port->id, XvGetRTPort(), port);
+		port->pAdaptor = adaptor;
+		port->pNotify =  NULL;
+		port->pDraw =  NULL;
+		port->client =  NULL;
+		port->grab.client =  NULL;
+		port->time = currentTime;
+		port->devPriv.ptr = v;
+
+		v->sna = sna;
+		v->alignment = 64;
+		v->color_key = sna_video_sprite_color_key(sna);
+		v->color_key_changed = ~0;
+		v->has_color_key = true;
+		v->brightness = -19;    /* (255/219) * -16 */
+		v->contrast = 75;       /* 255/219 * 64 */
+		v->saturation = 146;    /* 128/112 * 128 */
+		v->desired_crtc = NULL;
+		v->gamma5 = 0xc0c0c0;
+		v->gamma4 = 0x808080;
+		v->gamma3 = 0x404040;
+		v->gamma2 = 0x202020;
+		v->gamma1 = 0x101010;
+		v->gamma0 = 0x080808;
+		RegionNull(&v->clip);
+		v->SyncToVblank = 1;
+	}
+
+	adaptor->base_id = adaptor->pPorts[0].id;
+	adaptor->nPorts = nports;
 
 	xvColorKey = MAKE_ATOM("XV_COLORKEY");
 	xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP");