summaryrefslogtreecommitdiffstats
path: root/video/vaapi.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-03-17 18:22:25 +0100
committerwm4 <wm4@nowhere>2014-03-17 18:22:25 +0100
commit31fc5e85636f8e7b3bec5f133cb82b78e3c86ddb (patch)
tree702027b802cb1d2f00b266280faac3de1b5b13f2 /video/vaapi.c
parent88aa3b8c986e0fdb74ae805b6a09d43789fb903e (diff)
downloadmpv-31fc5e85636f8e7b3bec5f133cb82b78e3c86ddb.tar.bz2
mpv-31fc5e85636f8e7b3bec5f133cb82b78e3c86ddb.tar.xz
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.
Diffstat (limited to 'video/vaapi.c')
-rw-r--r--video/vaapi.c235
1 files changed, 72 insertions, 163 deletions
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; i<pool->num_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; i<pool->num_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; i<pool->num_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);
+}