diff --git a/filters/f_hwtransfer.c b/filters/f_hwtransfer.c index 649d28497c..9640f406ad 100644 --- a/filters/f_hwtransfer.c +++ b/filters/f_hwtransfer.c @@ -35,6 +35,10 @@ struct priv { int *fmt_upload_index; int *fmt_upload_num; + // List of source formats that require hwmap instead of hwupload. + int *map_fmts; + int num_map_fmts; + struct mp_hwupload public; }; @@ -58,6 +62,25 @@ static const struct ffmpeg_and_other_bugs shitlist[] = { {0} }; +struct hwmap_pairs { + int first_fmt; + int second_fmt; +}; + +// We cannot discover which pairs of hardware formats need to use hwmap to +// convert between the formats, so we need a lookup table. +static const struct hwmap_pairs hwmap_pairs[] = { + { + .first_fmt = IMGFMT_VAAPI, + .second_fmt = IMGFMT_VULKAN, + }, + { + .first_fmt = IMGFMT_DRMPRIME, + .second_fmt = IMGFMT_VAAPI, + }, + {0} +}; + static bool select_format(struct priv *p, int input_fmt, int *out_sw_fmt, int *out_upload_fmt) { @@ -183,7 +206,19 @@ static void process(struct mp_filter *f) goto error; } - struct mp_image *dst = mp_av_pool_image_hw_upload(p->hw_pool, src); + struct mp_image *dst; + bool map_images = false; + for (int n = 0; n < p->num_map_fmts; n++) { + if (src->imgfmt == p->map_fmts[n]) { + map_images = true; + break; + } + } + + if (map_images) + dst = mp_av_pool_image_hw_map(p->hw_pool, src); + else + dst = mp_av_pool_image_hw_upload(p->hw_pool, src); if (!dst) goto error; @@ -296,6 +331,16 @@ static bool probe_formats(struct mp_hwupload *u, int hw_imgfmt) } } + for (int n = 0; hwmap_pairs[n].first_fmt; n++) { + if (hwmap_pairs[n].first_fmt == hw_imgfmt) { + MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts, + hwmap_pairs[n].second_fmt); + } else if (hwmap_pairs[n].second_fmt == hw_imgfmt) { + MP_TARRAY_APPEND(p, p->map_fmts, p->num_map_fmts, + hwmap_pairs[n].first_fmt); + } + } + for (int n = 0; cstr->valid_sw_formats && cstr->valid_sw_formats[n] != AV_PIX_FMT_NONE; n++) { diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c index cbb3066430..41a3ea4eac 100644 --- a/filters/f_lavfi.c +++ b/filters/f_lavfi.c @@ -561,8 +561,8 @@ static void init_graph(struct lavfi *c) hwdec_ctx = hwdec_devices_get_first(info->hwdec_devs); } if (hwdec_ctx && hwdec_ctx->av_device_ref) { - MP_VERBOSE(c, "Configuring hwdec_interop=%s for filters\n", - hwdec_ctx->driver_name); + MP_VERBOSE(c, "Configuring hwdec_interop=%s for filter graph: %s\n", + hwdec_ctx->driver_name, c->graph_string); for (int n = 0; n < c->graph->nb_filters; n++) { AVFilterContext *filter = c->graph->filters[n]; filter->hw_device_ctx = diff --git a/test/ref/img_formats.txt b/test/ref/img_formats.txt index 2b1cca1522..cd84963b6a 100644 --- a/test/ref/img_formats.txt +++ b/test/ref/img_formats.txt @@ -1239,7 +1239,7 @@ videotoolbox: ctype=unknown planes=0, chroma=0:0 align=1:1 {} AVD: name=videotoolbox_vld chroma=0:0 flags=0x8 [hw] -vulkan: [GENERIC] ctype=unknown +vulkan: ctype=unknown Basic desc: [le][be][hw] planes=0, chroma=0:0 align=1:1 {} diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c index 5194221d50..d200a5db31 100644 --- a/video/fmt-conversion.c +++ b/video/fmt-conversion.c @@ -67,6 +67,7 @@ static const struct { {IMGFMT_CUDA, AV_PIX_FMT_CUDA}, {IMGFMT_P010, AV_PIX_FMT_P010}, {IMGFMT_DRMPRIME, AV_PIX_FMT_DRM_PRIME}, + {IMGFMT_VULKAN, AV_PIX_FMT_VULKAN}, {0, AV_PIX_FMT_NONE} }; diff --git a/video/img_format.h b/video/img_format.h index ebdbd66e29..7559c8c172 100644 --- a/video/img_format.h +++ b/video/img_format.h @@ -319,6 +319,7 @@ enum mp_imgfmt { IMGFMT_VDPAU_OUTPUT, // VdpOutputSurface IMGFMT_VAAPI, IMGFMT_VIDEOTOOLBOX, // CVPixelBufferRef + IMGFMT_VULKAN, // VKImage // Generic pass-through of AV_PIX_FMT_*. Used for formats which don't have // a corresponding IMGFMT_ value. diff --git a/video/mp_image_pool.c b/video/mp_image_pool.c index 2a4a8940c0..d80c65d3b5 100644 --- a/video/mp_image_pool.c +++ b/video/mp_image_pool.c @@ -426,3 +426,30 @@ struct mp_image *mp_av_pool_image_hw_upload(struct AVBufferRef *hw_frames_ctx, mp_image_copy_attributes(dst, src); return dst; } + +struct mp_image *mp_av_pool_image_hw_map(struct AVBufferRef *hw_frames_ctx, + struct mp_image *src) +{ + AVFrame *dst_frame = av_frame_alloc(); + if (!dst_frame) + return NULL; + + dst_frame->format = ((AVHWFramesContext*)hw_frames_ctx->data)->format; + dst_frame->hw_frames_ctx = av_buffer_ref(hw_frames_ctx); + + AVFrame *src_frame = mp_image_to_av_frame(src); + if (av_hwframe_map(dst_frame, src_frame, 0) < 0) { + av_frame_free(&src_frame); + av_frame_free(&dst_frame); + return NULL; + } + av_frame_free(&src_frame); + + struct mp_image *dst = mp_image_from_av_frame(dst_frame); + av_frame_free(&dst_frame); + if (!dst) + return NULL; + + mp_image_copy_attributes(dst, src); + return dst; +} diff --git a/video/mp_image_pool.h b/video/mp_image_pool.h index 3c7e6221d1..ab9065e6e9 100644 --- a/video/mp_image_pool.h +++ b/video/mp_image_pool.h @@ -41,4 +41,6 @@ bool mp_update_av_hw_frames_pool(struct AVBufferRef **hw_frames_ctx, struct mp_image *mp_av_pool_image_hw_upload(struct AVBufferRef *hw_frames_ctx, struct mp_image *src); +struct mp_image *mp_av_pool_image_hw_map(struct AVBufferRef *hw_frames_ctx, + struct mp_image *src); #endif