Skip to content

Commit c0e65d2

Browse files
committed
f_autoconvert: only copy through system memory when unmappable
1 parent ccd35da commit c0e65d2

3 files changed

Lines changed: 33 additions & 6 deletions

File tree

filters/f_autoconvert.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,28 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
233233
} else if (dst_all_hw && num_fmts > 0) {
234234
bool upload_created = false;
235235
int sw_fmt = imgfmt_is_sw ? img->imgfmt : img->params.hw_subfmt;
236-
// None of the targets accept the source's hardware format, so this is
237-
// a transfer between two different devices, which cannot be done
238-
// directly. Route the frame through system memory instead, which also
239-
// lets the scaler fix up the sw format if the devices disagree.
240-
bool download_first = !imgfmt_is_sw;
241-
242236
for (int i = 0; i < num_fmts; i++) {
243237
// We can probably use this! Very lazy and very approximate.
244238
struct mp_hwupload upload = mp_hwupload_create(conv, fmts[i],
245239
sw_fmt, false);
246240
if (upload.successful_init) {
241+
// None of the targets accept the source's hardware format. If
242+
// the two can share frames the uploader maps them directly.
243+
// Otherwise this is a transfer between separate devices, which
244+
// libavutil cannot do, so route it through system memory. That
245+
// is also what makes a sw format conversion possible below.
246+
bool download_first = !imgfmt_is_sw &&
247+
!mp_hwupload_can_map(fmts[i], img->imgfmt);
248+
249+
if (download_first) {
250+
mp_warn(log, "Transferring %s to %s through system memory. "
251+
"These are separate devices and cannot share "
252+
"frames, so every frame is copied twice. Use a "
253+
"decoder that outputs %s to avoid this.\n",
254+
mp_imgfmt_to_name(img->imgfmt),
255+
mp_imgfmt_to_name(fmts[i]),
256+
mp_imgfmt_to_name(fmts[i]));
257+
}
247258
mp_info(log, "HW-uploading to %s\n", mp_imgfmt_to_name(fmts[i]));
248259
filters[2] = upload.f;
249260
hwupload_fmt = upload.selected_sw_imgfmt;

filters/f_hwtransfer.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ static const struct hwmap_pairs hwmap_pairs[] = {
6868
{0}
6969
};
7070

71+
bool mp_hwupload_can_map(int dst_hw_imgfmt, int src_imgfmt)
72+
{
73+
for (int n = 0; hwmap_pairs[n].first_fmt; n++) {
74+
if ((hwmap_pairs[n].first_fmt == dst_hw_imgfmt &&
75+
hwmap_pairs[n].second_fmt == src_imgfmt) ||
76+
(hwmap_pairs[n].second_fmt == dst_hw_imgfmt &&
77+
hwmap_pairs[n].first_fmt == src_imgfmt))
78+
return true;
79+
}
80+
return false;
81+
}
82+
7183
/**
7284
* @brief Find the closest supported format when hw uploading
7385
*

filters/f_hwtransfer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ struct mp_hwupload {
1818
struct mp_hwupload mp_hwupload_create(struct mp_filter *parent, int hw_imgfmt,
1919
int sw_imgfmt, bool src_is_same_hw);
2020

21+
// Whether uploading to dst_hw_imgfmt from the hardware format src_imgfmt maps
22+
// the frame instead of copying it.
23+
bool mp_hwupload_can_map(int dst_hw_imgfmt, int src_imgfmt);
24+
2125
// A filter which downloads sw frames from hw. Ignores sw frames.
2226
struct mp_hwdownload {
2327
struct mp_filter *f;

0 commit comments

Comments
 (0)