From 31fc5e85636f8e7b3bec5f133cb82b78e3c86ddb Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 17 Mar 2014 18:22:25 +0100 Subject: vaapi: replace image pool implementation with mp_image_pool Although I at first thought it would be better to have a separate implementation for hwaccels because the difference to software images are too large, it turns out you can actually save some code with it. Note that the old implementation had a small memory management bug. This got painted over in commit 269c1e1, but is hereby solved properly. Also note that I couldn't test vf_vavpp.c (due to lack of hardware), and I hope I didn't accidentally break it. --- video/vaapi.c | 235 ++++++++++++++++++---------------------------------------- 1 file changed, 72 insertions(+), 163 deletions(-) (limited to 'video/vaapi.c') diff --git a/video/vaapi.c b/video/vaapi.c index 0bdffe3c72..edb16ffd48 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -159,75 +159,19 @@ VAImageFormat *va_image_format_from_imgfmt(const struct va_image_formats *format return NULL; } -static void va_surface_destroy(struct va_surface *surface); - -struct va_surface_pool { - struct mp_log *log; - struct mp_vaapi_ctx *ctx; - VADisplay display; - int rt_format; - int num_surfaces, lru_counter; - struct va_surface **surfaces; -}; - typedef struct va_surface_priv { struct mp_vaapi_ctx *ctx; VADisplay display; VAImage image; // used for software decoding case bool is_derived; // is image derived by vaDeriveImage()? - bool is_used; // referenced - bool is_dead; // used, but deallocate VA objects as soon as possible - int order; // for LRU allocation } va_surface_priv_t; -struct va_surface_pool * va_surface_pool_alloc(struct mp_vaapi_ctx *ctx, int rt_format) -{ - struct va_surface_pool *pool = talloc_ptrtype(NULL, pool); - *pool = (struct va_surface_pool) { - .ctx = ctx, - .log = ctx->log, - .display = ctx->display, - .rt_format = rt_format - }; - return pool; -} - - -void va_surface_pool_release(struct va_surface_pool *pool) -{ - if (!pool) - return; - va_surface_pool_clear(pool); - talloc_free(pool); -} - -void va_surface_pool_releasep(struct va_surface_pool **pool) { - if (!pool) - return; - va_surface_pool_release(*pool); - *pool = NULL; -} - -void va_surface_pool_clear(struct va_surface_pool *pool) -{ - for (int i=0; inum_surfaces; ++i) { - struct va_surface *s = pool->surfaces[i]; - if (s->p->is_used) - s->p->is_dead = true; - else - va_surface_destroy(s); - } - talloc_free(pool->surfaces); - pool->num_surfaces = 0; -} - -void va_surface_destroy(struct va_surface *surface) +static void va_surface_destroy(struct va_surface *surface) { if (!surface) return; if (surface->id != VA_INVALID_ID) { va_surface_priv_t *p = surface->p; - assert(!p->is_used); if (p->image.image_id != VA_INVALID_ID) vaDestroyImage(p->display, p->image.image_id); vaDestroySurfaces(p->display, &surface->id, 1); @@ -235,93 +179,40 @@ void va_surface_destroy(struct va_surface *surface) talloc_free(surface); } -void va_surface_release(struct va_surface *surface) +static void release_va_surface(void *arg) { - if (!surface) - return; - surface->p->is_used = false; - if (surface->p->is_dead) - va_surface_destroy(surface); + struct va_surface *surface = arg; + va_surface_destroy(surface); } -void va_surface_releasep(struct va_surface **surface) -{ - if (!surface) - return; - va_surface_release(*surface); - *surface = NULL; -} - -static struct va_surface *va_surface_alloc(struct va_surface_pool *pool, - int w, int h) +static struct mp_image *alloc_surface(struct mp_vaapi_ctx *ctx, int rt_format, + int w, int h) { VASurfaceID id = VA_INVALID_ID; VAStatus status; - status = vaCreateSurfaces(pool->display, w, h, pool->rt_format, 1, &id); - if (!CHECK_VA_STATUS(pool, "vaCreateSurfaces()")) + status = vaCreateSurfaces(ctx->display, w, h, rt_format, 1, &id); + if (!CHECK_VA_STATUS(ctx, "vaCreateSurfaces()")) return NULL; struct va_surface *surface = talloc_ptrtype(NULL, surface); if (!surface) return NULL; - MP_TARRAY_APPEND(NULL, pool->surfaces, pool->num_surfaces, surface); surface->id = id; surface->w = w; surface->h = h; - surface->rt_format = pool->rt_format; + surface->rt_format = rt_format; surface->p = talloc_zero(surface, va_surface_priv_t); - surface->p->ctx = pool->ctx; - surface->p->display = pool->display; + surface->p->ctx = ctx; + surface->p->display = ctx->display; surface->p->image.image_id = surface->p->image.buf = VA_INVALID_ID; - return surface; -} - -struct mp_image *va_surface_pool_get_wrapped(struct va_surface_pool *pool, - int imgfmt, int w, int h) -{ - return va_surface_wrap(va_surface_pool_get_by_imgfmt(pool, imgfmt, w, h)); -} - -int va_surface_pool_rt_format(const struct va_surface_pool *pool) -{ - return pool->rt_format; -} -bool va_surface_pool_reserve(struct va_surface_pool *pool, int count, - int w, int h) -{ - for (int i=0; inum_surfaces && count > 0; ++i) { - const struct va_surface *s = pool->surfaces[i]; - if (s->w == w && s->h == h && !s->p->is_used) - --count; - } - while (count > 0) { - if (!va_surface_alloc(pool, w, h)) - break; - --count; - } - return !count; -} - -struct va_surface *va_surface_pool_get(struct va_surface_pool *pool, - int w, int h) -{ - struct va_surface *best = NULL; - for (int i=0; inum_surfaces; ++i) { - struct va_surface *s = pool->surfaces[i]; - if (!s->p->is_used && s->w == w && s->h == h) { - if (!best || best->p->order > s->p->order) - best = s; - } - } - if (!best) - best = va_surface_alloc(pool, w, h); - if (best) { - best->p->is_used = true; - best->p->order = ++pool->lru_counter; - } - return best; + struct mp_image img = {0}; + mp_image_setfmt(&img, IMGFMT_VAAPI); + mp_image_set_size(&img, surface->w, surface->h); + img.planes[0] = (uint8_t*)surface; + img.planes[3] = (uint8_t*)(uintptr_t)surface->id; + return mp_image_new_custom_ref(&img, surface, release_va_surface); } static void va_surface_image_destroy(struct va_surface *surface) @@ -369,43 +260,20 @@ static VAImage *va_surface_image_alloc(struct va_surface *surface, return &surface->p->image; } - - -struct va_surface *va_surface_pool_get_by_imgfmt(struct va_surface_pool *pool, - int imgfmt, int w, int h) +// img must be a VAAPI surface; make sure its internal VAImage is allocated +// to a format corresponding to imgfmt (or return an error). +int va_surface_image_alloc_imgfmt(struct mp_image *img, int imgfmt) { - if (imgfmt == IMGFMT_VAAPI) - return va_surface_pool_get(pool, w, h); + struct va_surface *surface = va_surface_in_mp_image(img); + if (!surface) + return -1; VAImageFormat *format = - va_image_format_from_imgfmt(pool->ctx->image_formats, imgfmt); + va_image_format_from_imgfmt(surface->p->ctx->image_formats, imgfmt); if (!format) - return NULL; - // WTF: no mapping from VAImageFormat -> VA_RT_FORMAT_ - struct va_surface *surface = va_surface_pool_get(pool, w, h); - if (!surface) - return NULL; - if (va_surface_image_alloc(surface, format)) - return surface; - va_surface_release(surface); - return NULL; -} - -static void free_va_surface(void *arg) -{ - va_surface_release((struct va_surface*)arg); -} - -struct mp_image *va_surface_wrap(struct va_surface *surface) -{ - if (!surface) - return NULL; - - struct mp_image img = {0}; - mp_image_setfmt(&img, IMGFMT_VAAPI); - mp_image_set_size(&img, surface->w, surface->h); - img.planes[0] = (uint8_t*)surface; - img.planes[3] = (uint8_t*)(uintptr_t)surface->id; - return mp_image_new_custom_ref(&img, surface, free_va_surface); + return -1; + if (!va_surface_image_alloc(surface, format)) + return -1; + return 0; } VASurfaceID va_surface_id_in_mp_image(const struct mp_image *mpi) @@ -461,10 +329,12 @@ bool va_image_unmap(struct mp_vaapi_ctx *ctx, VAImage *image) bool va_surface_upload(struct va_surface *surface, struct mp_image *mpi) { va_surface_priv_t *p = surface->p; - if (p->image.image_id == VA_INVALID_ID) - return false; - if (va_fourcc_to_imgfmt(p->image.format.fourcc) != mpi->imgfmt) + VAImageFormat *format = + va_image_format_from_imgfmt(p->ctx->image_formats, mpi->imgfmt); + if (!format) + return false; + if (!va_surface_image_alloc(surface, format)) return false; struct mp_image img; @@ -485,6 +355,18 @@ bool va_surface_upload(struct va_surface *surface, struct mp_image *mpi) return true; } +// va_dst: copy destination, must be IMGFMT_VAAPI +// sw_src: copy source, must be a software surface +int va_surface_upload_image(struct mp_image *va_dst, struct mp_image *sw_src) +{ + struct va_surface *surface = va_surface_in_mp_image(va_dst); + if (!surface) + return -1; + if (!va_surface_upload(surface, sw_src)) + return -1; + return 0; +} + static struct mp_image *try_download(struct va_surface *surface, VAImageFormat *format, struct mp_image_pool *pool) @@ -549,3 +431,30 @@ struct mp_image *va_surface_download(struct va_surface *surface, return NULL; } +struct pool_alloc_ctx { + struct mp_vaapi_ctx *vaapi; + int rt_format; +}; + +static struct mp_image *alloc_pool(void *pctx, int fmt, int w, int h) +{ + struct pool_alloc_ctx *alloc_ctx = pctx; + if (fmt != IMGFMT_VAAPI) + return NULL; + + return alloc_surface(alloc_ctx->vaapi, alloc_ctx->rt_format, w, h); +} + +// The allocator of the given image pool to allocate VAAPI surfaces, using +// the given rt_format. +void va_pool_set_allocator(struct mp_image_pool *pool, struct mp_vaapi_ctx *ctx, + int rt_format) +{ + struct pool_alloc_ctx *alloc_ctx = talloc_ptrtype(pool, alloc_ctx); + *alloc_ctx = (struct pool_alloc_ctx){ + .vaapi = ctx, + .rt_format = rt_format, + }; + mp_image_pool_set_allocator(pool, alloc_pool, alloc_ctx); + mp_image_pool_set_lru(pool); +} -- cgit v1.2.3