From 7b7e15a460f2a24ba8c42f6caa71f1ca0ad25499 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 22 May 2014 20:55:17 +0200 Subject: vdpau: move RGB surface management out of the VO Integrate it with the existing surface allocator in vdpau.c. The changes are a bit violent, because the vdpau API is so non-orthogonal: compared to video surfaces, output surfaces use a different ID type, different format types, and different API functions. Also, introduce IMGFMT_VDPAU_OUTPUT for VdpOutputSurfaces wrapped in mp_image, rather than hacking it. This is a bit cleaner. --- video/img_format.c | 18 +++++++- video/img_format.h | 6 ++- video/out/vo_vdpau.c | 88 ++----------------------------------- video/vdpau.c | 119 ++++++++++++++++++++++++++++++++++++++++----------- video/vdpau.h | 5 +++ 5 files changed, 123 insertions(+), 113 deletions(-) (limited to 'video') diff --git a/video/img_format.c b/video/img_format.c index c8f1851a43..01bf2b2b87 100644 --- a/video/img_format.c +++ b/video/img_format.c @@ -42,6 +42,8 @@ struct mp_imgfmt_entry { }; static const struct mp_imgfmt_entry mp_imgfmt_list[] = { + // not in ffmpeg + FMT("vdpau_output", IMGFMT_VDPAU_OUTPUT) // these formats are pretty common, and the "le"/"be" suffixes enforced // by FFmpeg are annoying FMT("yuv420p10", IMGFMT_420P10) @@ -128,12 +130,26 @@ const char *mp_imgfmt_to_name(int fmt) return "unknown"; } +static struct mp_imgfmt_desc mp_only_imgfmt_desc(int mpfmt) +{ + switch (mpfmt) { + case IMGFMT_VDPAU_OUTPUT: + return (struct mp_imgfmt_desc) { + .id = mpfmt, + .avformat = AV_PIX_FMT_NONE, + .name = mp_imgfmt_to_name(mpfmt), + .flags = MP_IMGFLAG_BE | MP_IMGFLAG_LE | MP_IMGFLAG_RGB, + }; + } + return (struct mp_imgfmt_desc) {0}; +} + struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) { enum AVPixelFormat fmt = imgfmt2pixfmt(mpfmt); const AVPixFmtDescriptor *pd = av_pix_fmt_desc_get(fmt); if (!pd || fmt == AV_PIX_FMT_NONE) - return (struct mp_imgfmt_desc) {0}; + return mp_only_imgfmt_desc(mpfmt); struct mp_imgfmt_desc desc = { .id = mpfmt, diff --git a/video/img_format.h b/video/img_format.h index 31c72f41be..9277b0698c 100644 --- a/video/img_format.h +++ b/video/img_format.h @@ -252,7 +252,8 @@ enum mp_imgfmt { // Hardware accelerated formats. Plane data points to special data // structures, instead of pixel data. - IMGFMT_VDPAU, + IMGFMT_VDPAU, // VdpVideoSurface + IMGFMT_VDPAU_OUTPUT, // VdpOutputSurface IMGFMT_VDA, IMGFMT_VAAPI, @@ -330,7 +331,8 @@ static inline bool IMGFMT_IS_RGB(int fmt) #define IMGFMT_RGB_DEPTH(fmt) (mp_imgfmt_get_desc(fmt).plane_bits) #define IMGFMT_IS_HWACCEL(fmt) \ - ((fmt) == IMGFMT_VDPAU || (fmt) == IMGFMT_VAAPI || (fmt) == IMGFMT_VDA) + ((fmt) == IMGFMT_VDPAU || (fmt) == IMGFMT_VDPAU_OUTPUT || \ + (fmt) == IMGFMT_VAAPI || (fmt) == IMGFMT_VDA) int mp_imgfmt_from_name(bstr name, bool allow_hwaccel); const char *mp_imgfmt_to_name(int fmt); diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 260b9dccff..b6728e79d8 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -60,7 +60,6 @@ /* number of video and output surfaces */ #define MAX_OUTPUT_SURFACES 15 -#define NUM_BUFFERED_VIDEO 5 /* Pixelformat used for output surfaces */ #define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8 @@ -83,8 +82,6 @@ struct vdpctx { VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES]; VdpOutputSurface screenshot_surface; int num_output_surfaces; - VdpOutputSurface rgb_surfaces[NUM_BUFFERED_VIDEO]; - bool rgb_surfaces_used[NUM_BUFFERED_VIDEO]; VdpOutputSurface black_pixel; struct mp_image *current_image; @@ -177,7 +174,7 @@ static int render_video_to_output_surface(struct vo *vo, "vdp_presentation_queue_block_until_surface_idle"); if (vc->rgb_mode) { - VdpOutputSurface surface = (uintptr_t)mpi->planes[0]; + VdpOutputSurface surface = (uintptr_t)mpi->planes[3]; int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0; vdp_st = vdp->output_surface_render_output_surface(output_surface, NULL, vc->black_pixel, @@ -373,15 +370,6 @@ static void free_video_specific(struct vo *vo) } vc->screenshot_surface = VDP_INVALID_HANDLE; - for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) { - assert(!vc->rgb_surfaces_used[n]); - if (vc->rgb_surfaces[n] != VDP_INVALID_HANDLE) { - vdp_st = vdp->output_surface_destroy(vc->rgb_surfaces[n]); - CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy"); - } - vc->rgb_surfaces[n] = VDP_INVALID_HANDLE; - } - if (vc->black_pixel != VDP_INVALID_HANDLE) { vdp_st = vdp->output_surface_destroy(vc->black_pixel); CHECK_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy"); @@ -389,14 +377,6 @@ static void free_video_specific(struct vo *vo) vc->black_pixel = VDP_INVALID_HANDLE; } -static int get_rgb_format(int imgfmt) -{ - switch (imgfmt) { - case IMGFMT_BGR32: return VDP_RGBA_FORMAT_B8G8R8A8; - default: return -1; - } -} - static int initialize_vdpau_objects(struct vo *vo) { struct vdpctx *vc = vo->priv; @@ -412,17 +392,6 @@ static int initialize_vdpau_objects(struct vo *vo) if (win_x11_init_vdpau_flip_queue(vo) < 0) return -1; - if (vc->rgb_mode) { - int format = get_rgb_format(vc->image_format); - for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) { - vdp_st = vdp->output_surface_create(vc->vdp_device, - format, - vc->vid_width, vc->vid_height, - &vc->rgb_surfaces[n]); - CHECK_VDP_ERROR(vo, "Allocating RGB surface"); - } - } - if (vc->black_pixel == VDP_INVALID_HANDLE) { vdp_st = vdp->output_surface_create(vc->vdp_device, OUTPUT_RGBA_FORMAT, 1, 1, &vc->black_pixel); @@ -443,8 +412,6 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) { struct vdpctx *vc = vo->priv; - for (int i = 0; i < NUM_BUFFERED_VIDEO; i++) - vc->rgb_surfaces[i] = VDP_INVALID_HANDLE; forget_frames(vo, false); vc->black_pixel = VDP_INVALID_HANDLE; vc->video_mixer->video_mixer = VDP_INVALID_HANDLE; @@ -502,7 +469,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags) vc->vid_width = params->w; vc->vid_height = params->h; - vc->rgb_mode = get_rgb_format(params->imgfmt) >= 0; + vc->rgb_mode = mp_vdpau_get_rgb_format(params->imgfmt, NULL); free_video_specific(vo); @@ -872,33 +839,6 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration) vc->surface_num = WRAP_ADD(vc->surface_num, 1, vc->num_output_surfaces); } -static void free_rgb_surface(void *ptr) -{ - bool *entry = ptr; - *entry = false; -} - -static struct mp_image *get_rgb_surface(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - assert(vc->rgb_mode); - - for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) { - bool *used = &vc->rgb_surfaces_used[n]; - if (!*used) { - *used = true; - struct mp_image mpi = {0}; - mp_image_setfmt(&mpi, IMGFMT_VDPAU); // not really, but keep csp flags - mpi.planes[0] = (void *)(uintptr_t)vc->rgb_surfaces[n]; - return mp_image_new_custom_ref(&mpi, used, free_rgb_surface); - } - } - - MP_ERR(vo, "no surfaces available in get_rgb_surface\n"); - return NULL; -} - static void draw_image(struct vo *vo, struct mp_image *mpi) { struct vdpctx *vc = vo->priv; @@ -912,29 +852,10 @@ static void draw_image(struct vo *vo, struct mp_image *mpi) static struct mp_image *filter_image(struct vo *vo, struct mp_image *mpi) { struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - struct mp_image *reserved_mpi = NULL; - VdpStatus vdp_st; check_preemption(vo); - if (vc->rgb_mode) { - reserved_mpi = get_rgb_surface(vo); - if (!reserved_mpi) - goto end; - VdpOutputSurface rgb_surface = (uintptr_t)reserved_mpi->planes[0]; - if (rgb_surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->output_surface_put_bits_native(rgb_surface, - &(const void *){mpi->planes[0]}, - &(uint32_t){mpi->stride[0]}, - NULL); - CHECK_VDP_WARNING(vo, "Error when calling " - "output_surface_put_bits_native"); - } - } else { - reserved_mpi = mp_vdpau_upload_video_surface(vc->mpvdp, mpi); - } - + struct mp_image *reserved_mpi = mp_vdpau_upload_video_surface(vc->mpvdp, mpi); if (!reserved_mpi) goto end; @@ -1014,8 +935,7 @@ static int query_format(struct vo *vo, uint32_t format) int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW; if (mp_vdpau_get_format(format, NULL, NULL)) return flags; - int rgb_format = get_rgb_format(format); - if (!vc->force_yuv && rgb_format >= 0) + if (!vc->force_yuv && mp_vdpau_get_rgb_format(format, NULL)) return flags; return 0; } diff --git a/video/vdpau.c b/video/vdpau.c index e59befebdc..20fbf2566f 100644 --- a/video/vdpau.c +++ b/video/vdpau.c @@ -28,8 +28,11 @@ static void mark_vdpau_objects_uninitialized(struct mp_vdpau_ctx *ctx) { - for (int i = 0; i < MAX_VIDEO_SURFACES; i++) + for (int i = 0; i < MAX_VIDEO_SURFACES; i++) { ctx->video_surfaces[i].surface = VDP_INVALID_HANDLE; + ctx->video_surfaces[i].osurface = VDP_INVALID_HANDLE; + ctx->video_surfaces[i].allocated = false; + } ctx->vdp_device = VDP_INVALID_HANDLE; } @@ -181,30 +184,45 @@ static struct mp_image *create_ref(struct mp_vdpau_ctx *ctx, int index) struct mp_image *res = mp_image_new_custom_ref(&(struct mp_image){0}, ref, release_decoder_surface); - mp_image_setfmt(res, IMGFMT_VDPAU); + mp_image_setfmt(res, e->rgb ? IMGFMT_VDPAU_OUTPUT : IMGFMT_VDPAU); mp_image_set_size(res, e->w, e->h); res->planes[0] = (void *)"dummy"; // must be non-NULL, otherwise arbitrary - res->planes[3] = (void *)(intptr_t)e->surface; + res->planes[3] = (void *)(intptr_t)(e->rgb ? e->osurface : e->surface); return res; } -struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, - VdpChromaType chroma, int w, int h) +static struct mp_image *mp_vdpau_get_surface(struct mp_vdpau_ctx *ctx, + VdpChromaType chroma, + VdpRGBAFormat rgb_format, + bool rgb, int w, int h) { struct vdp_functions *vdp = &ctx->vdp; int surface_index = -1; VdpStatus vdp_st; + if (rgb) { + chroma = (VdpChromaType)-1; + } else { + rgb_format = (VdpChromaType)-1; + } + pthread_mutex_lock(&ctx->pool_lock); // Destroy all unused surfaces that don't have matching parameters for (int n = 0; n < MAX_VIDEO_SURFACES; n++) { struct surface_entry *e = &ctx->video_surfaces[n]; - if (!e->in_use && e->surface != VDP_INVALID_HANDLE) { - if (e->chroma != chroma || e->w != w || e->h != h) { - vdp_st = vdp->video_surface_destroy(e->surface); - CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_destroy"); - e->surface = VDP_INVALID_HANDLE; + if (!e->in_use && e->allocated) { + if (e->w != w || e->h != h || e->rgb != rgb || + e->chroma != chroma || e->rgb_format != rgb_format) + { + if (e->rgb) { + vdp_st = vdp->output_surface_destroy(e->osurface); + } else { + vdp_st = vdp->video_surface_destroy(e->surface); + } + CHECK_VDP_WARNING(ctx, "Error when destroying surface"); + e->surface = e->osurface = VDP_INVALID_HANDLE; + e->allocated = false; } } } @@ -212,9 +230,11 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, // Try to find an existing unused surface for (int n = 0; n < MAX_VIDEO_SURFACES; n++) { struct surface_entry *e = &ctx->video_surfaces[n]; - if (!e->in_use && e->surface != VDP_INVALID_HANDLE) { + if (!e->in_use && e->allocated) { assert(e->w == w && e->h == h); assert(e->chroma == chroma); + assert(e->rgb_format == rgb_format); + assert(e->rgb == rgb); surface_index = n; goto done; } @@ -225,12 +245,23 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, struct surface_entry *e = &ctx->video_surfaces[n]; if (!e->in_use) { assert(e->surface == VDP_INVALID_HANDLE); + assert(e->osurface == VDP_INVALID_HANDLE); + assert(!e->allocated); e->chroma = chroma; + e->rgb_format = rgb_format; + e->rgb = rgb; e->w = w; e->h = h; - vdp_st = vdp->video_surface_create(ctx->vdp_device, chroma, - w, h, &e->surface); - CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_create"); + if (rgb) { + vdp_st = vdp->output_surface_create(ctx->vdp_device, rgb_format, + w, h, &e->osurface); + e->allocated = e->osurface != VDP_INVALID_HANDLE; + } else { + vdp_st = vdp->video_surface_create(ctx->vdp_device, chroma, + w, h, &e->surface); + e->allocated = e->surface != VDP_INVALID_HANDLE; + } + CHECK_VDP_WARNING(ctx, "Error when allocating surface"); surface_index = n; goto done; } @@ -248,6 +279,12 @@ done: ; return mpi; } +struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, + VdpChromaType chroma, int w, int h) +{ + return mp_vdpau_get_surface(ctx, chroma, 0, false, w, h); +} + struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log, struct vo_x11_state *x11) { @@ -281,6 +318,10 @@ void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx) vdp_st = vdp->video_surface_destroy(ctx->video_surfaces[i].surface); CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_destroy"); } + if (ctx->video_surfaces[i].osurface != VDP_INVALID_HANDLE) { + vdp_st = vdp->output_surface_destroy(ctx->video_surfaces[i].osurface); + CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_destroy"); + } } if (vdp->device_destroy && ctx->vdp_device != VDP_INVALID_HANDLE) { @@ -327,6 +368,22 @@ bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type, return true; } +bool mp_vdpau_get_rgb_format(int imgfmt, VdpRGBAFormat *out_rgba_format) +{ + VdpRGBAFormat format = (VdpRGBAFormat)-1; + + switch (imgfmt) { + case IMGFMT_BGR32: + format = VDP_RGBA_FORMAT_B8G8R8A8; break; + default: + return false; + } + + if (out_rgba_format) + *out_rgba_format = format; + return true; +} + // Use mp_vdpau_get_video_surface, and upload mpi to it. Return NULL on failure. // If the image is already a vdpau video surface, just return a reference. struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx, @@ -335,26 +392,36 @@ struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx, struct vdp_functions *vdp = &ctx->vdp; VdpStatus vdp_st; - if (mpi->imgfmt == IMGFMT_VDPAU) + if (mpi->imgfmt == IMGFMT_VDPAU || mpi->imgfmt == IMGFMT_VDPAU_OUTPUT) return mp_image_new_ref(mpi); - VdpChromaType chroma_type; - VdpYCbCrFormat pixel_format; - if (!mp_vdpau_get_format(mpi->imgfmt, &chroma_type, &pixel_format)) + VdpChromaType chroma = (VdpChromaType)-1; + VdpYCbCrFormat ycbcr = (VdpYCbCrFormat)-1; + VdpRGBAFormat rgbafmt = (VdpRGBAFormat)-1; + bool rgb = !mp_vdpau_get_format(mpi->imgfmt, &chroma, &ycbcr); + if (rgb && !mp_vdpau_get_rgb_format(mpi->imgfmt, &rgbafmt)) return NULL; struct mp_image *hwmpi = - mp_vdpau_get_video_surface(ctx, chroma_type, mpi->w, mpi->h); + mp_vdpau_get_surface(ctx, chroma, rgbafmt, rgb, mpi->w, mpi->h); if (!hwmpi) return NULL; - VdpVideoSurface surface = (intptr_t)hwmpi->planes[3]; - const void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]}; - if (mpi->imgfmt == IMGFMT_NV12) - destdata[1] = destdata[2]; - vdp_st = vdp->video_surface_put_bits_y_cb_cr(surface, - pixel_format, destdata, mpi->stride); - CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_put_bits_y_cb_cr"); + if (hwmpi->imgfmt == IMGFMT_VDPAU) { + VdpVideoSurface surface = (intptr_t)hwmpi->planes[3]; + const void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]}; + if (mpi->imgfmt == IMGFMT_NV12) + destdata[1] = destdata[2]; + vdp_st = vdp->video_surface_put_bits_y_cb_cr(surface, + ycbcr, destdata, mpi->stride); + } else { + VdpOutputSurface rgb_surface = (intptr_t)hwmpi->planes[3]; + vdp_st = vdp->output_surface_put_bits_native(rgb_surface, + &(const void *){mpi->planes[0]}, + &(uint32_t){mpi->stride[0]}, + NULL); + } + CHECK_VDP_WARNING(ctx, "Error when uploading surface"); mp_image_copy_attributes(hwmpi, mpi); return hwmpi; diff --git a/video/vdpau.h b/video/vdpau.h index acf4280266..3aea414700 100644 --- a/video/vdpau.h +++ b/video/vdpau.h @@ -58,8 +58,12 @@ struct mp_vdpau_ctx { pthread_mutex_t pool_lock; struct surface_entry { VdpVideoSurface surface; + VdpOutputSurface osurface; + bool allocated; int w, h; + VdpRGBAFormat rgb_format; VdpChromaType chroma; + bool rgb; bool in_use; } video_surfaces[MAX_VIDEO_SURFACES]; }; @@ -75,6 +79,7 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx, bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type, VdpYCbCrFormat *out_pixel_format); +bool mp_vdpau_get_rgb_format(int imgfmt, VdpRGBAFormat *out_rgba_format); struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx, struct mp_image *mpi); -- cgit v1.2.3