summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-09-27 16:48:45 +0200
committerwm4 <wm4@nowhere>2013-09-27 17:59:44 +0200
commit4d2f354da651a3c1fd9776ed5829f57961a46c10 (patch)
treeaade31a57f48ec4b387ba19077154fca5012f62f /video
parentede652774ee83d2d311763358a1d3b820d9f5e17 (diff)
downloadmpv-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')
-rw-r--r--video/decode/vaapi.c5
-rw-r--r--video/out/vo_vaapi.c3
-rw-r--r--video/vaapi.c83
-rw-r--r--video/vaapi.h6
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