From 4d2f354da651a3c1fd9776ed5829f57961a46c10 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 27 Sep 2013 16:48:45 +0200 Subject: 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. --- video/decode/vaapi.c | 5 +++- video/out/vo_vaapi.c | 3 +- video/vaapi.c | 83 +++++++++++++++++++++++++++++++++------------------- video/vaapi.h | 6 +++- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c index 82c46de81e..d7ee5b35dc 100644 --- a/video/decode/vaapi.c +++ b/video/decode/vaapi.c @@ -32,6 +32,7 @@ #include "mpvcore/av_common.h" #include "video/fmt-conversion.h" #include "video/vaapi.h" +#include "video/mp_image_pool.h" #include "video/decode/dec_video.h" #include "video/filter/vf.h" @@ -68,6 +69,7 @@ struct priv { struct va_surface_pool *pool; int rt_format; + struct mp_image_pool *sw_pool; bool printed_readback_warning; }; @@ -414,6 +416,7 @@ static int init_with_vactx(struct lavc_ctx *ctx, struct mp_vaapi_ctx *vactx) p->display = p->ctx->display; p->pool = va_surface_pool_alloc(p->display, p->rt_format); + p->sw_pool = talloc_steal(p, mp_image_pool_new(17)); p->va_context->display = p->display; p->va_context->config_id = VA_INVALID_ID; @@ -466,7 +469,7 @@ static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *img) struct va_surface *surface = va_surface_in_mp_image(img); if (surface) { struct mp_image *simg = - va_surface_download(surface, p->ctx->image_formats); + va_surface_download(surface, p->ctx->image_formats, p->sw_pool); if (simg) { if (!p->printed_readback_warning) { mp_msg(MSGT_VO, MSGL_WARN, "[vaapi] Using GPU readback. This " diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 68fb09ff9b..4f79bbbd1f 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -266,7 +266,8 @@ static struct mp_image *get_screenshot(struct priv *p) va_surface_in_mp_image(p->output_surfaces[p->visible_surface]); if (!surface) return NULL; - struct mp_image *img = va_surface_download(surface, p->va_image_formats); + struct mp_image *img = + va_surface_download(surface, p->va_image_formats, NULL); if (!img) return NULL; struct mp_image_params params = p->image_params; 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; } diff --git a/video/vaapi.h b/video/vaapi.h index fa87658391..8e09193fd9 100644 --- a/video/vaapi.h +++ b/video/vaapi.h @@ -72,6 +72,8 @@ #include "mp_image.h" +struct mp_image_pool; + struct mp_vaapi_ctx { VADisplay display; struct va_image_formats *image_formats; @@ -117,6 +119,8 @@ struct mp_image * va_surface_wrap(struct va_surface *surface); // takes o VASurfaceID va_surface_id(const struct va_surface *surface); VASurfaceID va_surface_id_in_mp_image(const struct mp_image *mpi); bool va_surface_upload(struct va_surface *surface, const struct mp_image *mpi); -struct mp_image * va_surface_download(const struct va_surface *surface, const struct va_image_formats *formats); +struct mp_image * va_surface_download(struct va_surface *surface, + const struct va_image_formats *formats, + struct mp_image_pool *pool); #endif -- cgit v1.2.3