@@ -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
@@ -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 */
@@ -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");
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(-)