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 [email protected]. removed/added
    whitespace, re-formatted code, removed redundent variable allocation.

Cc: Chris Wilson <[email protected]>
Signed-off-by: Michael Hadley <[email protected]>
---
 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 --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..f7064c8 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 list link;
+       } sprite;
+
+       struct 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);
+
+       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);
+
+       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) {
+               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;
 
+       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;
+                                       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;
+
+       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;
        }
 
+       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));
+       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);
+       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);
+
+               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");
-- 
1.9.3

_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to