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@xxxxxxxxx. removed/added whitespace, re-formatted code, removed redundent variable allocation. Cc: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> Signed-off-by: Michael Hadley <michaelx.hadley@xxxxxxxxx> --- 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 Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx