diff options
author | wm4 <wm4@nowhere> | 2013-09-27 16:48:45 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-09-27 17:59:44 +0200 |
commit | 4d2f354da651a3c1fd9776ed5829f57961a46c10 (patch) | |
tree | aade31a57f48ec4b387ba19077154fca5012f62f /video/vaapi.c | |
parent | ede652774ee83d2d311763358a1d3b820d9f5e17 (diff) | |
download | mpv-4d2f354da651a3c1fd9776ed5829f57961a46c10.tar.bz2 mpv-4d2f354da651a3c1fd9776ed5829f57961a46c10.tar.xz |
vaapi: potentially make reading surfaces back to system RAM faster
Don't allocate a VAImage and a mp_image every time. VAImage are cached
in the surfaces themselves, and for mp_image an explicit pool is
created. The retry loop runs only once for each surface now.
This also makes use of vaDeriveImage() if possible.
Diffstat (limited to 'video/vaapi.c')
-rw-r--r-- | video/vaapi.c | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/video/vaapi.c b/video/vaapi.c index 70ab691323..b18b9135cd 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -22,6 +22,7 @@ #include "mpvcore/mp_msg.h" #include "mp_image.h" #include "img_format.h" +#include "mp_image_pool.h" #define VA_VERBOSE(...) mp_msg(MSGT_VO, MSGL_V, "[vaapi] " __VA_ARGS__) #define VA_ERROR(...) mp_msg(MSGT_VO, MSGL_ERR, "[vaapi] " __VA_ARGS__) @@ -168,7 +169,7 @@ struct va_surface_pool { typedef struct va_surface_priv { VADisplay display; - VAImage image; // used for sofwtare decoding case + 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 @@ -476,44 +477,66 @@ bool va_surface_upload(struct va_surface *surface, const struct mp_image *mpi) return true; } -struct mp_image *va_surface_download(const struct va_surface *surface, - const struct va_image_formats *formats) +static struct mp_image *try_download(struct va_surface *surface, + VAImageFormat *format, + struct mp_image_pool *pool) +{ + VAStatus status; + + enum mp_imgfmt imgfmt = va_fourcc_to_imgfmt(format->fourcc); + if (imgfmt == IMGFMT_NONE) + return NULL; + + if (!va_surface_image_alloc(surface, format)) + return NULL; + + VAImage *image = &surface->p->image; + + if (!surface->p->is_derived) { + status = vaGetImage(surface->p->display, surface->id, 0, 0, + surface->w, surface->h, image->image_id); + if (status != VA_STATUS_SUCCESS) + return NULL; + } + + struct mp_image *dst = NULL; + struct mp_image tmp; + if (va_image_map(surface->p->display, image, &tmp)) { + assert(tmp.imgfmt == imgfmt); + dst = pool ? mp_image_pool_get(pool, imgfmt, tmp.w, tmp.h) + : mp_image_alloc(imgfmt, tmp.w, tmp.h); + mp_image_copy(dst, &tmp); + va_image_unmap(surface->p->display, image); + } + return dst; +} + +// pool is optional (used for allocating returned images). +// Note: unlike va_surface_upload(), this will attempt to (re)create the +// VAImage stored with the va_surface. +struct mp_image *va_surface_download(struct va_surface *surface, + const struct va_image_formats *formats, + struct mp_image_pool *pool) { VAStatus status = vaSyncSurface(surface->p->display, surface->id); if (!check_va_status(status, "vaSyncSurface()")) return NULL; + VAImage *image = &surface->p->image; + if (image->image_id != VA_INVALID_ID) { + struct mp_image *mpi = try_download(surface, &image->format, pool); + if (mpi) + return mpi; + } + // We have no clue which format will work, so try them all. - // This code is just for screenshots, so it's ok not to cache the right - // format (to prevent unnecessary work), and we don't attempt to use - // vaDeriveImage() for direct access either. for (int i = 0; i < formats->num; i++) { VAImageFormat *format = &formats->entries[i]; - const enum mp_imgfmt imgfmt = va_fourcc_to_imgfmt(format->fourcc); - if (imgfmt == IMGFMT_NONE) - continue; - VAImage image; - status = vaCreateImage(surface->p->display, format, - surface->w, surface->h, &image); - if (!check_va_status(status, "vaCreateImage()")) - continue; - status = vaGetImage(surface->p->display, surface->id, 0, 0, - surface->w, surface->h, image.image_id); - if (status != VA_STATUS_SUCCESS) { - vaDestroyImage(surface->p->display, image.image_id); - continue; - } - struct mp_image *dst = NULL; - struct mp_image tmp; - if (va_image_map(surface->p->display, &image, &tmp)) { - assert(tmp.imgfmt == imgfmt); - dst = mp_image_alloc(imgfmt, tmp.w, tmp.h); - mp_image_copy(dst, &tmp); - va_image_unmap(surface->p->display, &image); - } - vaDestroyImage(surface->p->display, image.image_id); - return dst; + struct mp_image *mpi = try_download(surface, format, pool); + if (mpi) + return mpi; } + VA_ERROR("failed to get surface data.\n"); return NULL; } |