Compare commits
40
Commits
harmony-port
...
v0.35.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
140ec21c89 | ||
|
|
db524988b1 | ||
|
|
8e2dc8b02b | ||
|
|
16c0ac226a | ||
|
|
01374b6830 | ||
|
|
fc115bce2c | ||
|
|
b64f9fe646 | ||
|
|
3813cc4a14 | ||
|
|
8ddc0e8888 | ||
|
|
46cd82a68d | ||
|
|
222f9c5635 | ||
|
|
c5e4d65e71 | ||
|
|
9f6e1b3ba1 | ||
|
|
688a321dbb | ||
|
|
46d3dc2a42 | ||
|
|
5436852bf5 | ||
|
|
6076691b94 | ||
|
|
b963113c00 | ||
|
|
fd279c9a2a | ||
|
|
ec2a9d4332 | ||
|
|
666201d716 | ||
|
|
daf9a3c971 | ||
|
|
b960de5fe3 | ||
|
|
c0fa12c958 | ||
|
|
7753a73a17 | ||
|
|
dadcb2e614 | ||
|
|
f8b7170871 | ||
|
|
71346393e2 | ||
|
|
ae7ee7417f | ||
|
|
74baedffec | ||
|
|
495206dd41 | ||
|
|
37869fbcd7 | ||
|
|
954d53612c | ||
|
|
6860343a25 | ||
|
|
f5ce1fbf44 | ||
|
|
214e47854a | ||
|
|
5fb7a23d37 | ||
|
|
f593186e7d | ||
|
|
5149805f6b | ||
|
|
af1e00b2ce |
No files matched your search
@@ -26,6 +26,9 @@ Interface changes
|
||||
|
||||
::
|
||||
|
||||
=======
|
||||
--- mpv 0.35.1 --- (feature backport due to special circumstances)
|
||||
- add `--vd-lavc-dr=auto` and make it the default
|
||||
--- mpv 0.35.0 ---
|
||||
- add the `--vo=gpu-next` video output driver, as well as the options
|
||||
`--allow-delayed-peak-detect`, `--builtin-scalers`,
|
||||
|
||||
@@ -1701,8 +1701,8 @@ Video
|
||||
support this, then it will be treated as ``cpu``, regardless of the setting.
|
||||
Currently, only ``gpu-next`` supports film grain application.
|
||||
|
||||
``--vd-lavc-dr=<yes|no>``
|
||||
Enable direct rendering (default: yes). If this is set to ``yes``, the
|
||||
``--vd-lavc-dr=<auto|yes|no>``
|
||||
Enable direct rendering (default: auto). If this is set to ``yes``, the
|
||||
video will be decoded directly to GPU video memory (or staging buffers).
|
||||
This can speed up video upload, and may help with large resolutions or
|
||||
slow hardware. This works only with the following VOs:
|
||||
@@ -1710,6 +1710,10 @@ Video
|
||||
- ``gpu``: requires at least OpenGL 4.4 or Vulkan.
|
||||
- ``libmpv``: The libmpv render API has optional support.
|
||||
|
||||
The ``auto`` option will try to guess whether DR can improve performance
|
||||
on your particular hardware. Currently this enables it on AMD or NVIDIA
|
||||
if using OpenGL or unconditionally if using Vulkan.
|
||||
|
||||
Using video filters of any kind that write to the image data (or output
|
||||
newly allocated frames) will silently disable the DR code path.
|
||||
|
||||
|
||||
+44
-3
@@ -1,3 +1,44 @@
|
||||
Release 0.35.1
|
||||
==============
|
||||
|
||||
Bug fix release for the 0.35 branch.
|
||||
|
||||
Fixes and Minor Enhancements
|
||||
----------------------------
|
||||
|
||||
- ao_pipewire: log version and other useful debug info
|
||||
- wayland: error out if essential protocol support is missing
|
||||
- wayland: also log refresh rate on surface entrance
|
||||
- vo_gpu_next: fix undefined behavior on alpha-first formats
|
||||
- meson: prepend MPV_CONFDIR path with prefix
|
||||
- meson: unbreak dl check on BSDs without libdl
|
||||
- lcms: fix crash with lcms2-related options if lcms is disabled
|
||||
- meson: fix stdatomic detection on bsd
|
||||
- osc: don't spam window-controls bindings on every render
|
||||
- wayland: check for resize/move in touch event first
|
||||
- ao_coreaudio: use device's nominal sample rate for latency properties
|
||||
- ao_pipewire: properly clean up resources
|
||||
- filter_kernels: fix kaiser
|
||||
- hwdec/d3d11va: fix a possible memory leak
|
||||
- external_files: set log level for potential files to trace
|
||||
- vo_opengl: do not blindly reject all Microsoft's OpenGL implementations
|
||||
- ao_coreaudio: use AudioUnitReset as ao_driver.reset to prevent long restart
|
||||
- hwdec_drmprime: fix memory leak
|
||||
- vo: hwdec: fix libdrm-related memory leak
|
||||
- draw_bmp: ensure last slice width is less than total width
|
||||
- wayland: dispatch and wait for compositor events in uninit
|
||||
- demux: boost read EBU R128 gain values to ReplayGain's reference level
|
||||
- version.py/version.sh: bump copyright year
|
||||
- vulkan: fix build error for 32bit builds with clang
|
||||
- vo_wlshm: cleanup on failure
|
||||
- ra_d3d11: fix incorrect type
|
||||
- meson: also search for rst2html with .py extension
|
||||
- audio: fix crash during uninit with ao_lavc
|
||||
- mp_image: fix XYZ primaries default
|
||||
- vd_lavc: add "auto" choice for vd-lavc-dr
|
||||
- vo: implement VO_DR_FLAG_HOST_CACHED
|
||||
- x11: fix issue with xpresent timing feedback
|
||||
|
||||
Release 0.35.0
|
||||
==============
|
||||
|
||||
@@ -149,7 +190,7 @@ This listing is not complete. Check DOCS/client-api-changes.rst for a history
|
||||
of changes to the client API, and DOCS/interface-changes.rst for a history
|
||||
of changes to other user-visible interfaces.
|
||||
|
||||
A complete changelog can be seen by running `git log v0.34.0..v0.35.0`
|
||||
A complete changelog can be seen by running `git log v0.34.0..v0.35.1`
|
||||
in the git repository or by visiting either
|
||||
https://github.com/mpv-player/mpv/compare/v0.34.0...v0.35.0 or
|
||||
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.34.0..v0.35.0
|
||||
https://github.com/mpv-player/mpv/compare/v0.34.0...v0.35.1 or
|
||||
https://git.srsfckn.biz/mpv/log/?qt=range&q=v0.34.0..v0.35.1
|
||||
@@ -314,11 +314,11 @@ coreaudio_error:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void stop(struct ao *ao)
|
||||
static void reset(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
OSStatus err = AudioOutputUnitStop(p->audio_unit);
|
||||
CHECK_CA_WARN("can't stop audio unit");
|
||||
OSStatus err = AudioUnitReset(p->audio_unit, kAudioUnitScope_Global, 0);
|
||||
CHECK_CA_WARN("can't reset audio unit");
|
||||
}
|
||||
|
||||
static void start(struct ao *ao)
|
||||
@@ -415,7 +415,7 @@ const struct ao_driver audio_out_coreaudio = {
|
||||
.uninit = uninit,
|
||||
.init = init,
|
||||
.control = control,
|
||||
.reset = stop,
|
||||
.reset = reset,
|
||||
.start = start,
|
||||
.hotplug_init = hotplug_init,
|
||||
.hotplug_uninit = hotplug_uninit,
|
||||
|
||||
@@ -456,7 +456,15 @@ int64_t ca_get_device_latency_us(struct ao *ao, AudioDeviceID device)
|
||||
}
|
||||
}
|
||||
|
||||
return ca_frames_to_us(ao, latency_frames);
|
||||
double sample_rate = ao->samplerate;
|
||||
OSStatus err = CA_GET_O(device, kAudioDevicePropertyNominalSampleRate,
|
||||
&sample_rate);
|
||||
CHECK_CA_WARN("cannot get device sample rate, falling back to AO sample rate!");
|
||||
if (err == noErr) {
|
||||
MP_VERBOSE(ao, "Device sample rate: %f\n", sample_rate);
|
||||
}
|
||||
|
||||
return latency_frames / sample_rate * 1e6;
|
||||
}
|
||||
|
||||
static OSStatus ca_change_format_listener(
|
||||
|
||||
+22
-3
@@ -183,6 +183,8 @@ static void on_process(void *userdata)
|
||||
}
|
||||
|
||||
pw_stream_queue_buffer(p->stream, b);
|
||||
|
||||
MP_TRACE(ao, "queued %d of %d samples\n", samples, nframes);
|
||||
}
|
||||
|
||||
static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *param)
|
||||
@@ -422,9 +424,20 @@ static void on_error(void *data, uint32_t id, int seq, int res, const char *mess
|
||||
MP_WARN(ao, "Error during playback: %s, %s\n", spa_strerror(res), message);
|
||||
}
|
||||
|
||||
static void on_core_info(void *data, const struct pw_core_info *info)
|
||||
{
|
||||
struct ao *ao = data;
|
||||
|
||||
MP_VERBOSE(ao, "Core user: %s\n", info->user_name);
|
||||
MP_VERBOSE(ao, "Core host: %s\n", info->host_name);
|
||||
MP_VERBOSE(ao, "Core version: %s\n", info->version);
|
||||
MP_VERBOSE(ao, "Core name: %s\n", info->name);
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
.version = PW_VERSION_CORE_EVENTS,
|
||||
.error = on_error,
|
||||
.info = on_core_info,
|
||||
};
|
||||
|
||||
static int pipewire_init_boilerplate(struct ao *ao)
|
||||
@@ -434,6 +447,8 @@ static int pipewire_init_boilerplate(struct ao *ao)
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
MP_VERBOSE(ao, "Headers version: %s\n", pw_get_headers_version());
|
||||
MP_VERBOSE(ao, "Library version: %s\n", pw_get_library_version());
|
||||
|
||||
p->loop = pw_thread_loop_new("ao-pipewire", NULL);
|
||||
if (p->loop == NULL)
|
||||
@@ -455,6 +470,7 @@ static int pipewire_init_boilerplate(struct ao *ao)
|
||||
if (!p->core) {
|
||||
MP_WARN(ao, "Could not connect to context '%s': %s\n",
|
||||
p->options.remote, strerror(errno));
|
||||
pw_context_destroy(context);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -496,7 +512,7 @@ static int init(struct ao *ao)
|
||||
);
|
||||
|
||||
if (pipewire_init_boilerplate(ao) < 0)
|
||||
goto error;
|
||||
goto error_props;
|
||||
|
||||
ao->device_buffer = p->options.buffer_msec * ao->samplerate / 1000;
|
||||
|
||||
@@ -520,7 +536,7 @@ static int init(struct ao *ao)
|
||||
|
||||
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &audio_info);
|
||||
if (!params[0])
|
||||
goto error;
|
||||
goto error_props;
|
||||
|
||||
if (af_fmt_is_planar(ao->format)) {
|
||||
ao->num_planes = ao->channels.num;
|
||||
@@ -560,6 +576,8 @@ static int init(struct ao *ao)
|
||||
|
||||
return 0;
|
||||
|
||||
error_props:
|
||||
pw_properties_free(props);
|
||||
error:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
@@ -736,7 +754,7 @@ static int hotplug_init(struct ao *ao)
|
||||
|
||||
int res = pipewire_init_boilerplate(ao);
|
||||
if (res)
|
||||
return res;
|
||||
goto error_no_unlock;
|
||||
|
||||
pw_thread_loop_lock(priv->loop);
|
||||
|
||||
@@ -759,6 +777,7 @@ static int hotplug_init(struct ao *ao)
|
||||
|
||||
error:
|
||||
pw_thread_loop_unlock(priv->loop);
|
||||
error_no_unlock:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
+12
-10
@@ -459,7 +459,7 @@ void ao_uninit(struct ao *ao)
|
||||
{
|
||||
struct buffer_state *p = ao->buffer_state;
|
||||
|
||||
if (p->thread_valid) {
|
||||
if (p && p->thread_valid) {
|
||||
pthread_mutex_lock(&p->pt_lock);
|
||||
p->terminate = true;
|
||||
pthread_cond_broadcast(&p->pt_wakeup);
|
||||
@@ -472,17 +472,19 @@ void ao_uninit(struct ao *ao)
|
||||
if (ao->driver_initialized)
|
||||
ao->driver->uninit(ao);
|
||||
|
||||
talloc_free(p->filter_root);
|
||||
talloc_free(p->queue);
|
||||
talloc_free(p->pending);
|
||||
talloc_free(p->convert_buffer);
|
||||
talloc_free(p->temp_buf);
|
||||
if (p) {
|
||||
talloc_free(p->filter_root);
|
||||
talloc_free(p->queue);
|
||||
talloc_free(p->pending);
|
||||
talloc_free(p->convert_buffer);
|
||||
talloc_free(p->temp_buf);
|
||||
|
||||
pthread_cond_destroy(&p->wakeup);
|
||||
pthread_mutex_destroy(&p->lock);
|
||||
pthread_cond_destroy(&p->wakeup);
|
||||
pthread_mutex_destroy(&p->lock);
|
||||
|
||||
pthread_cond_destroy(&p->pt_wakeup);
|
||||
pthread_mutex_destroy(&p->pt_lock);
|
||||
pthread_cond_destroy(&p->pt_wakeup);
|
||||
pthread_mutex_destroy(&p->pt_lock);
|
||||
}
|
||||
|
||||
talloc_free(ao);
|
||||
}
|
||||
|
||||
@@ -2952,6 +2952,11 @@ static struct replaygain_data *decode_rgain(struct mp_log *log,
|
||||
}
|
||||
rg.track_gain /= 256.;
|
||||
rg.album_gain /= 256.;
|
||||
|
||||
// Add 5dB to compensate for the different reference levels between
|
||||
// our reference of ReplayGain 2 (-18 LUFS) and EBU R128 (-23 LUFS).
|
||||
rg.track_gain += 5.;
|
||||
rg.album_gain += 5.;
|
||||
return talloc_dup(NULL, &rg);
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -327,7 +327,7 @@ endif
|
||||
features += {'ta-leak-report': get_option('ta-leak-report')}
|
||||
|
||||
libdl_dep = cc.find_library('dl', required: false)
|
||||
features += {'libdl': libdl_dep.found() and cc.has_function('dlopen', dependencies: libdl_dep, prefix: '#include <dlfcn.h>')}
|
||||
features += {'libdl': cc.has_function('dlopen', dependencies: libdl_dep, prefix: '#include <dlfcn.h>')}
|
||||
if features['libdl']
|
||||
dependencies += libdl_dep
|
||||
endif
|
||||
@@ -716,10 +716,11 @@ if features['sdl2-gamepad']
|
||||
sources += files('input/sdl_gamepad.c')
|
||||
endif
|
||||
|
||||
stdatomic = cc.find_library('atomic', required: get_option('stdatomic'))
|
||||
features += {'stdatomic': stdatomic.found()}
|
||||
stdatomic_dep = cc.find_library('atomic', required: false)
|
||||
features += {'stdatomic': cc.has_header_symbol('stdatomic.h', 'atomic_int', dependencies: stdatomic_dep,
|
||||
required: get_option('stdatomic'))}
|
||||
if features['stdatomic']
|
||||
dependencies += stdatomic
|
||||
dependencies += stdatomic_dep
|
||||
endif
|
||||
|
||||
uchardet_opt = get_option('uchardet').require(
|
||||
@@ -1555,7 +1556,7 @@ if features['manpage-build']
|
||||
)
|
||||
endif
|
||||
|
||||
rst2html = find_program('rst2html', required: get_option('html-build'))
|
||||
rst2html = find_program('rst2html', 'rst2html.py', required: get_option('html-build'))
|
||||
features += {'html-build': rst2html.found()}
|
||||
if features['html-build']
|
||||
datadir = get_option('datadir')
|
||||
@@ -1624,7 +1625,7 @@ sys.stdout.write(features)
|
||||
'''
|
||||
feature_str = run_command(python, '-c', feature_sort, feature_keys, check: true).stdout()
|
||||
conf_data.set_quoted('FULLCONFIG', feature_str)
|
||||
conf_data.set_quoted('MPV_CONFDIR', join_paths(get_option('sysconfdir'), 'mpv'))
|
||||
conf_data.set_quoted('MPV_CONFDIR', join_paths(get_option('prefix'), get_option('sysconfdir'), 'mpv'))
|
||||
configure_file(output : 'config.h', configuration : conf_data)
|
||||
message('List of enabled features: ' + feature_str)
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ static void append_dir_subtitles(struct mpv_global *global, struct MPOpts *opts,
|
||||
if (!limit_fuzziness && fuzz >= 2)
|
||||
prio |= 1;
|
||||
|
||||
mp_dbg(log, "Potential external file: \"%s\" Priority: %d\n",
|
||||
mp_trace(log, "Potential external file: \"%s\" Priority: %d\n",
|
||||
de->d_name, prio);
|
||||
|
||||
if (prio) {
|
||||
|
||||
+9
-3
@@ -122,6 +122,7 @@ local state = {
|
||||
enabled = true,
|
||||
input_enabled = true,
|
||||
showhide_enabled = false,
|
||||
windowcontrols_buttons = false,
|
||||
dmx_cache = 0,
|
||||
using_video_margins = false,
|
||||
border = true,
|
||||
@@ -2409,9 +2410,14 @@ function render()
|
||||
for _,cords in ipairs(osc_param.areas["window-controls"]) do
|
||||
if state.osc_visible then -- activate only when OSC is actually visible
|
||||
set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "window-controls")
|
||||
mp.enable_key_bindings("window-controls")
|
||||
else
|
||||
mp.disable_key_bindings("window-controls")
|
||||
end
|
||||
if state.osc_visible ~= state.windowcontrols_buttons then
|
||||
if state.osc_visible then
|
||||
mp.enable_key_bindings("window-controls")
|
||||
else
|
||||
mp.disable_key_bindings("window-controls")
|
||||
end
|
||||
state.windowcontrols_buttons = state.osc_visible
|
||||
end
|
||||
|
||||
if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then
|
||||
|
||||
@@ -283,6 +283,11 @@ static void mark_rect(struct mp_draw_sub_cache *p, int x0, int y0, int x1, int y
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the very last slice does not extend
|
||||
// beyond the total width.
|
||||
struct slice *last_s = &line[p->s_w - 1];
|
||||
last_s->x1 = MPMIN(p->w - ((p->s_w - 1) * SLICE_W), last_s->x1);
|
||||
|
||||
p->any_osd = true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ date_str = date.strftime("%a %b %d %I:%M:%S %Y")
|
||||
NEW_REVISION = "#define VERSION \"" + version + "\"\n"
|
||||
OLD_REVISION = ""
|
||||
BUILDDATE = "#define BUILDDATE \"" + date_str + "\"\n"
|
||||
MPVCOPYRIGHT = "#define MPVCOPYRIGHT \"Copyright \u00A9 2000-2022 mpv/MPlayer/mplayer2 projects\"" + "\n"
|
||||
MPVCOPYRIGHT = "#define MPVCOPYRIGHT \"Copyright \u00A9 2000-2023 mpv/MPlayer/mplayer2 projects\"" + "\n"
|
||||
|
||||
if os.path.isfile(sys.argv[1]):
|
||||
with open(sys.argv[1], "r") as f:
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ fi
|
||||
NEW_REVISION="#define VERSION \"${VERSION}\""
|
||||
OLD_REVISION=$(head -n 1 "$version_h" 2> /dev/null)
|
||||
BUILDDATE="#define BUILDDATE \"$(date)\""
|
||||
MPVCOPYRIGHT="#define MPVCOPYRIGHT \"Copyright © 2000-2022 mpv/MPlayer/mplayer2 projects\""
|
||||
MPVCOPYRIGHT="#define MPVCOPYRIGHT \"Copyright © 2000-2023 mpv/MPlayer/mplayer2 projects\""
|
||||
|
||||
# Update version.h only on revision changes to avoid spurious rebuilds
|
||||
if test "$NEW_REVISION" != "$OLD_REVISION"; then
|
||||
|
||||
@@ -119,7 +119,8 @@ const struct m_sub_options vd_lavc_conf = {
|
||||
{"vd-lavc-software-fallback", OPT_CHOICE(software_fallback,
|
||||
{"no", INT_MAX}, {"yes", 1}), M_RANGE(1, INT_MAX)},
|
||||
{"vd-lavc-o", OPT_KEYVALUELIST(avopts)},
|
||||
{"vd-lavc-dr", OPT_FLAG(dr)},
|
||||
{"vd-lavc-dr", OPT_CHOICE(dr,
|
||||
{"auto", -1}, {"no", 0}, {"yes", 1})},
|
||||
{"hwdec", OPT_STRING(hwdec_api),
|
||||
.help = hwdec_opt_help,
|
||||
.flags = M_OPT_OPTIONAL_PARAM | UPDATE_HWDEC},
|
||||
@@ -138,7 +139,7 @@ const struct m_sub_options vd_lavc_conf = {
|
||||
.skip_idct = AVDISCARD_DEFAULT,
|
||||
.skip_frame = AVDISCARD_DEFAULT,
|
||||
.framedrop = AVDISCARD_NONREF,
|
||||
.dr = 1,
|
||||
.dr = -1,
|
||||
.hwdec_api = "no",
|
||||
.hwdec_codecs = "h264,vc1,hevc,vp8,vp9,av1,prores",
|
||||
// Maximum number of surfaces the player wants to buffer. This number
|
||||
@@ -967,8 +968,10 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags)
|
||||
|
||||
struct mp_image *img = mp_image_pool_get_no_alloc(p->dr_pool, imgfmt, w, h);
|
||||
if (!img) {
|
||||
MP_DBG(p, "Allocating new DR image...\n");
|
||||
img = vo_get_image(p->vo, imgfmt, w, h, stride_align);
|
||||
bool host_cached = p->opts->dr == -1; // auto
|
||||
int dr_flags = host_cached ? VO_DR_FLAG_HOST_CACHED : 0;
|
||||
MP_DBG(p, "Allocating new%s DR image...\n", host_cached ? " (host-cached)" : "");
|
||||
img = vo_get_image(p->vo, imgfmt, w, h, stride_align, dr_flags);
|
||||
if (!img) {
|
||||
MP_DBG(p, "...failed..\n");
|
||||
goto fallback;
|
||||
|
||||
+4
-4
@@ -885,11 +885,11 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
|
||||
// function, but this field can still be relevant for guiding gamut
|
||||
// mapping optimizations, and it's also used by `mp_get_csp_matrix`
|
||||
// when deciding what RGB space to map XYZ to for VOs that don't want
|
||||
// to directly ingest XYZ into their color pipeline. BT.709 would be a
|
||||
// sane default here, but it runs the risk of clipping any wide gamut
|
||||
// content, so we pick BT.2020 instead to be on the safer side.
|
||||
// to directly ingest XYZ into their color pipeline. We pick DCI-P3
|
||||
// because it is the colorspace most closely matching digital cinema
|
||||
// content, and also has the correct DCI whitepoint.
|
||||
if (params->color.primaries == MP_CSP_PRIM_AUTO)
|
||||
params->color.primaries = MP_CSP_PRIM_BT_2020;
|
||||
params->color.primaries = MP_CSP_PRIM_DCI_P3;
|
||||
if (params->color.gamma == MP_CSP_TRC_AUTO)
|
||||
params->color.gamma = MP_CSP_TRC_LINEAR;
|
||||
} else {
|
||||
|
||||
@@ -67,6 +67,7 @@ static void uninit(struct ra_hwdec *hw)
|
||||
{
|
||||
struct priv_owner *p = hw->priv;
|
||||
hwdec_devices_remove(hw->devs, &p->hwctx);
|
||||
av_buffer_unref(&p->hwctx.av_device_ref);
|
||||
SAFE_RELEASE(p->device);
|
||||
SAFE_RELEASE(p->device1);
|
||||
}
|
||||
|
||||
@@ -2182,7 +2182,7 @@ static void debug_marker(struct ra *ra, const char *msg)
|
||||
bool printed_header = false;
|
||||
uint64_t messages = ID3D11InfoQueue_GetNumStoredMessages(p->iqueue);
|
||||
for (uint64_t i = 0; i < messages; i++) {
|
||||
size_t len;
|
||||
SIZE_T len;
|
||||
hr = ID3D11InfoQueue_GetMessage(p->iqueue, i, NULL, &len);
|
||||
if (FAILED(hr) || !len)
|
||||
goto done;
|
||||
|
||||
@@ -20,7 +20,7 @@ struct dr_helper {
|
||||
atomic_ullong dr_in_flight;
|
||||
|
||||
struct mp_image *(*get_image)(void *ctx, int imgfmt, int w, int h,
|
||||
int stride_align);
|
||||
int stride_align, int flags);
|
||||
void *get_image_ctx;
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ static void dr_helper_destroy(void *ptr)
|
||||
|
||||
struct dr_helper *dr_helper_create(struct mp_dispatch_queue *dispatch,
|
||||
struct mp_image *(*get_image)(void *ctx, int imgfmt, int w, int h,
|
||||
int stride_align),
|
||||
int stride_align, int flags),
|
||||
void *get_image_ctx)
|
||||
{
|
||||
struct dr_helper *dr = talloc_ptrtype(NULL, dr);
|
||||
@@ -108,7 +108,7 @@ static void free_dr_buffer_on_dr_thread(void *opaque, uint8_t *data)
|
||||
|
||||
struct get_image_cmd {
|
||||
struct dr_helper *dr;
|
||||
int imgfmt, w, h, stride_align;
|
||||
int imgfmt, w, h, stride_align, flags;
|
||||
struct mp_image *res;
|
||||
};
|
||||
|
||||
@@ -118,7 +118,7 @@ static void sync_get_image(void *ptr)
|
||||
struct dr_helper *dr = cmd->dr;
|
||||
|
||||
cmd->res = dr->get_image(dr->get_image_ctx, cmd->imgfmt, cmd->w, cmd->h,
|
||||
cmd->stride_align);
|
||||
cmd->stride_align, cmd->flags);
|
||||
if (!cmd->res)
|
||||
return;
|
||||
|
||||
@@ -149,11 +149,14 @@ static void sync_get_image(void *ptr)
|
||||
}
|
||||
|
||||
struct mp_image *dr_helper_get_image(struct dr_helper *dr, int imgfmt,
|
||||
int w, int h, int stride_align)
|
||||
int w, int h, int stride_align, int flags)
|
||||
{
|
||||
struct get_image_cmd cmd = {
|
||||
.dr = dr,
|
||||
.imgfmt = imgfmt, .w = w, .h = h, .stride_align = stride_align,
|
||||
.imgfmt = imgfmt,
|
||||
.w = w, .h = h,
|
||||
.stride_align = stride_align,
|
||||
.flags = flags,
|
||||
};
|
||||
mp_dispatch_run(dr->dispatch, sync_get_image, &cmd);
|
||||
return cmd.res;
|
||||
|
||||
@@ -15,7 +15,7 @@ struct mp_dispatch_queue;
|
||||
// dr_helper instance can be destroyed.
|
||||
struct dr_helper *dr_helper_create(struct mp_dispatch_queue *dispatch,
|
||||
struct mp_image *(*get_image)(void *ctx, int imgfmt, int w, int h,
|
||||
int stride_align),
|
||||
int stride_align, int flags),
|
||||
void *get_image_ctx);
|
||||
|
||||
// Make DR release calls (freeing images) reentrant if they are called on this
|
||||
@@ -34,4 +34,4 @@ void dr_helper_release_thread(struct dr_helper *dr);
|
||||
// allocate a DR'ed image on the render thread (at least not in a way which
|
||||
// actually works if you want foreign threads to be able to free them).
|
||||
struct mp_image *dr_helper_get_image(struct dr_helper *dr, int imgfmt,
|
||||
int w, int h, int stride_align);
|
||||
int w, int h, int stride_align, int flags);
|
||||
@@ -240,7 +240,7 @@ static double kaiser(params *p, double x)
|
||||
{
|
||||
if (x > 1)
|
||||
return 0;
|
||||
double i0a = 1.0 / bessel_i0(p->params[1]);
|
||||
double i0a = 1.0 / bessel_i0(p->params[0]);
|
||||
return bessel_i0(p->params[0] * sqrt(1.0 - x * x)) * i0a;
|
||||
}
|
||||
|
||||
|
||||
+31
-40
@@ -54,40 +54,6 @@ struct gl_lcms {
|
||||
struct mp_icc_opts *opts;
|
||||
};
|
||||
|
||||
static int validate_3dlut_size_opt(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, const char **value)
|
||||
{
|
||||
struct bstr param = bstr0(*value);
|
||||
int p1, p2, p3;
|
||||
char s[20];
|
||||
snprintf(s, sizeof(s), "%.*s", BSTR_P(param));
|
||||
return gl_parse_3dlut_size(s, &p1, &p2, &p3);
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct mp_icc_opts
|
||||
const struct m_sub_options mp_icc_conf = {
|
||||
.opts = (const m_option_t[]) {
|
||||
{"use-embedded-icc-profile", OPT_FLAG(use_embedded)},
|
||||
{"icc-profile", OPT_STRING(profile), .flags = M_OPT_FILE},
|
||||
{"icc-profile-auto", OPT_FLAG(profile_auto)},
|
||||
{"icc-cache-dir", OPT_STRING(cache_dir), .flags = M_OPT_FILE},
|
||||
{"icc-intent", OPT_INT(intent)},
|
||||
{"icc-force-contrast", OPT_CHOICE(contrast, {"no", 0}, {"inf", -1}),
|
||||
M_RANGE(0, 1000000)},
|
||||
{"icc-3dlut-size", OPT_STRING_VALIDATE(size_str, validate_3dlut_size_opt)},
|
||||
{"3dlut-size", OPT_REPLACED("icc-3dlut-size")},
|
||||
{"icc-cache", OPT_REMOVED("see icc-cache-dir")},
|
||||
{"icc-contrast", OPT_REMOVED("see icc-force-contrast")},
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct mp_icc_opts),
|
||||
.defaults = &(const struct mp_icc_opts) {
|
||||
.size_str = "64x64x64",
|
||||
.intent = INTENT_RELATIVE_COLORIMETRIC,
|
||||
.use_embedded = true,
|
||||
},
|
||||
};
|
||||
|
||||
static void lcms2_error_handler(cmsContext ctx, cmsUInt32Number code,
|
||||
const char *msg)
|
||||
{
|
||||
@@ -487,12 +453,6 @@ error_exit:
|
||||
|
||||
#else /* HAVE_LCMS2 */
|
||||
|
||||
const struct m_sub_options mp_icc_conf = {
|
||||
.opts = (const m_option_t[]) { {0} },
|
||||
.size = sizeof(struct mp_icc_opts),
|
||||
.defaults = &(const struct mp_icc_opts) {0},
|
||||
};
|
||||
|
||||
struct gl_lcms *gl_lcms_init(void *talloc_ctx, struct mp_log *log,
|
||||
struct mpv_global *global,
|
||||
struct mp_icc_opts *opts)
|
||||
@@ -522,3 +482,34 @@ bool gl_lcms_get_lut3d(struct gl_lcms *p, struct lut3d **result_lut3d,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int validate_3dlut_size_opt(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, const char **value)
|
||||
{
|
||||
int p1, p2, p3;
|
||||
return gl_parse_3dlut_size(*value, &p1, &p2, &p3) ? 0 : M_OPT_INVALID;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct mp_icc_opts
|
||||
const struct m_sub_options mp_icc_conf = {
|
||||
.opts = (const m_option_t[]) {
|
||||
{"use-embedded-icc-profile", OPT_FLAG(use_embedded)},
|
||||
{"icc-profile", OPT_STRING(profile), .flags = M_OPT_FILE},
|
||||
{"icc-profile-auto", OPT_FLAG(profile_auto)},
|
||||
{"icc-cache-dir", OPT_STRING(cache_dir), .flags = M_OPT_FILE},
|
||||
{"icc-intent", OPT_INT(intent)},
|
||||
{"icc-force-contrast", OPT_CHOICE(contrast, {"no", 0}, {"inf", -1}),
|
||||
M_RANGE(0, 1000000)},
|
||||
{"icc-3dlut-size", OPT_STRING_VALIDATE(size_str, validate_3dlut_size_opt)},
|
||||
{"3dlut-size", OPT_REPLACED("icc-3dlut-size")},
|
||||
{"icc-cache", OPT_REMOVED("see icc-cache-dir")},
|
||||
{"icc-contrast", OPT_REMOVED("see icc-force-contrast")},
|
||||
{0}
|
||||
},
|
||||
.size = sizeof(struct mp_icc_opts),
|
||||
.defaults = &(const struct mp_icc_opts) {
|
||||
.size_str = "64x64x64",
|
||||
.intent = MP_INTENT_RELATIVE_COLORIMETRIC,
|
||||
.use_embedded = true,
|
||||
},
|
||||
};
|
||||
@@ -192,11 +192,11 @@ static int render(struct render_backend *ctx, mpv_render_param *params,
|
||||
}
|
||||
|
||||
static struct mp_image *get_image(struct render_backend *ctx, int imgfmt,
|
||||
int w, int h, int stride_align)
|
||||
int w, int h, int stride_align, int flags)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align);
|
||||
return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align, flags);
|
||||
}
|
||||
|
||||
static void screenshot(struct render_backend *ctx, struct vo_frame *frame,
|
||||
|
||||
@@ -80,6 +80,7 @@ enum {
|
||||
RA_CAP_FRAGCOORD = 1 << 10, // supports reading from gl_FragCoord
|
||||
RA_CAP_PARALLEL_COMPUTE = 1 << 11, // supports parallel compute shaders
|
||||
RA_CAP_NUM_GROUPS = 1 << 12, // supports gl_NumWorkGroups
|
||||
RA_CAP_SLOW_DR = 1 << 13, // direct rendering is assumed to be slow
|
||||
};
|
||||
|
||||
enum ra_ctype {
|
||||
|
||||
@@ -4289,8 +4289,15 @@ static void gl_video_dr_free_buffer(void *opaque, uint8_t *data)
|
||||
}
|
||||
|
||||
struct mp_image *gl_video_get_image(struct gl_video *p, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
if (flags & VO_DR_FLAG_HOST_CACHED) {
|
||||
if (p->ra->caps & RA_CAP_SLOW_DR) {
|
||||
MP_VERBOSE(p, "DR path suspected slow/uncached, disabling..");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gl_video_check_format(p, imgfmt))
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ struct vo;
|
||||
void gl_video_configure_queue(struct gl_video *p, struct vo *vo);
|
||||
|
||||
struct mp_image *gl_video_get_image(struct gl_video *p, int imgfmt, int w, int h,
|
||||
int stride_align);
|
||||
int stride_align, int flags);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -47,6 +47,7 @@ static void uninit(struct ra_hwdec *hw)
|
||||
struct priv_owner *p = hw->priv;
|
||||
if (p->hwctx.driver_name)
|
||||
hwdec_devices_remove(hw->devs, &p->hwctx);
|
||||
av_buffer_unref(&p->hwctx.av_device_ref);
|
||||
}
|
||||
|
||||
const static dmabuf_interop_init interop_inits[] = {
|
||||
|
||||
@@ -299,10 +299,14 @@ static int init(struct ra_hwdec *hw)
|
||||
.driver_name = hw->driver->name,
|
||||
.hw_imgfmt = IMGFMT_DRMPRIME,
|
||||
};
|
||||
|
||||
char *device = drmGetDeviceNameFromFd2(p->ctx->fd);
|
||||
if (!av_hwdevice_ctx_create(&p->hwctx.av_device_ref, AV_HWDEVICE_TYPE_DRM,
|
||||
drmGetDeviceNameFromFd2(p->ctx->fd), NULL, 0)) {
|
||||
device, NULL, 0)) {
|
||||
hwdec_devices_add(hw->devs, &p->hwctx);
|
||||
}
|
||||
if (device)
|
||||
free(device);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ struct render_backend_fns {
|
||||
struct voctrl_performance_data *out);
|
||||
// Like vo_driver.get_image().
|
||||
struct mp_image *(*get_image)(struct render_backend *ctx, int imgfmt,
|
||||
int w, int h, int stride_align);
|
||||
int w, int h, int stride_align, int flags);
|
||||
// This has two purposes: 1. set queue attributes on VO, 2. update the
|
||||
// renderer's OSD pointer. Keep in mind that as soon as the caller releases
|
||||
// the renderer lock, the VO pointer can become invalid. The OSD pointer
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
@@ -37,16 +38,28 @@
|
||||
static bool is_software_gl(GL *gl)
|
||||
{
|
||||
const char *renderer = gl->GetString(GL_RENDERER);
|
||||
const char *vendor = gl->GetString(GL_VENDOR);
|
||||
return !(renderer && vendor) ||
|
||||
// Note we don't attempt to blacklist Microsoft's fallback implementation.
|
||||
// It only provides OpenGL 1.1 and will be skipped anyway.
|
||||
return !renderer ||
|
||||
strcmp(renderer, "Software Rasterizer") == 0 ||
|
||||
strstr(renderer, "llvmpipe") ||
|
||||
strstr(renderer, "softpipe") ||
|
||||
strcmp(vendor, "Microsoft Corporation") == 0 ||
|
||||
strcmp(renderer, "Mesa X11") == 0 ||
|
||||
strcmp(renderer, "Apple Software Renderer") == 0;
|
||||
}
|
||||
|
||||
// This guesses whether our DR path is fast or slow
|
||||
static bool is_fast_dr(GL *gl)
|
||||
{
|
||||
const char *vendor = gl->GetString(GL_VENDOR);
|
||||
if (!vendor)
|
||||
return false;
|
||||
|
||||
return strcasecmp(vendor, "AMD") == 0 ||
|
||||
strcasecmp(vendor, "NVIDIA Corporation") == 0 ||
|
||||
strcasecmp(vendor, "ATI Technologies Inc.") == 0; // AMD on Windows
|
||||
}
|
||||
|
||||
static void GLAPIENTRY dummy_glBindFramebuffer(GLenum target, GLuint framebuffer)
|
||||
{
|
||||
assert(framebuffer == 0);
|
||||
@@ -650,6 +663,9 @@ void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
|
||||
mp_verbose(log, "Detected suspected software renderer.\n");
|
||||
}
|
||||
|
||||
if (!is_fast_dr(gl))
|
||||
gl->mpgl_caps |= MPGL_CAP_SLOW_DR;
|
||||
|
||||
// GL_ARB_compute_shader & GL_ARB_shader_image_load_store
|
||||
if (gl->DispatchCompute && gl->BindImageTexture)
|
||||
gl->mpgl_caps |= MPGL_CAP_COMPUTE_SHADER;
|
||||
|
||||
@@ -59,6 +59,7 @@ enum {
|
||||
MPGL_CAP_COMPUTE_SHADER = (1 << 23), // GL_ARB_compute_shader & GL_ARB_shader_image_load_store
|
||||
MPGL_CAP_NESTED_ARRAY = (1 << 24), // GL_ARB_arrays_of_arrays
|
||||
|
||||
MPGL_CAP_SLOW_DR = (1 << 29), // direct rendering is assumed to be slow
|
||||
MPGL_CAP_SW = (1 << 30), // indirect or sw renderer
|
||||
};
|
||||
|
||||
|
||||
@@ -206,10 +206,8 @@ static bool glx_check_visible(struct ra_ctx *ctx)
|
||||
static void glx_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window);
|
||||
if (ctx->vo->x11->use_present) {
|
||||
vo_x11_present(ctx->vo);
|
||||
if (ctx->vo->x11->use_present)
|
||||
present_sync_swap(ctx->vo->x11->present);
|
||||
}
|
||||
}
|
||||
|
||||
static void glx_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
|
||||
|
||||
@@ -82,10 +82,8 @@ static void mpegl_swap_buffers(struct ra_ctx *ctx)
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
eglSwapBuffers(p->egl_display, p->egl_surface);
|
||||
if (ctx->vo->x11->use_present) {
|
||||
vo_x11_present(ctx->vo);
|
||||
if (ctx->vo->x11->use_present)
|
||||
present_sync_swap(ctx->vo->x11->present);
|
||||
}
|
||||
}
|
||||
|
||||
static void mpegl_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
|
||||
|
||||
@@ -103,6 +103,7 @@ static int ra_init_gl(struct ra *ra, GL *gl)
|
||||
{RA_CAP_COMPUTE, MPGL_CAP_COMPUTE_SHADER},
|
||||
{RA_CAP_NUM_GROUPS, MPGL_CAP_COMPUTE_SHADER},
|
||||
{RA_CAP_NESTED_ARRAY, MPGL_CAP_NESTED_ARRAY},
|
||||
{RA_CAP_SLOW_DR, MPGL_CAP_SLOW_DR},
|
||||
};
|
||||
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(caps_map); i++) {
|
||||
|
||||
@@ -52,6 +52,10 @@ struct ra *ra_create_pl(pl_gpu gpu, struct mp_log *log)
|
||||
if (gpu->limits.max_variables)
|
||||
ra->caps |= RA_CAP_GLOBAL_UNIFORM;
|
||||
#endif
|
||||
#if PL_API_VER >= 234
|
||||
if (!gpu->limits.host_cached)
|
||||
ra->caps |= RA_CAP_SLOW_DR;
|
||||
#endif
|
||||
|
||||
if (gpu->limits.max_tex_1d_dim)
|
||||
ra->caps |= RA_CAP_TEX_1D;
|
||||
|
||||
+5
-5
@@ -1066,10 +1066,10 @@ static void do_redraw(struct vo *vo)
|
||||
}
|
||||
|
||||
static struct mp_image *get_image_vo(void *ctx, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
struct vo *vo = ctx;
|
||||
return vo->driver->get_image(vo, imgfmt, w, h, stride_align);
|
||||
return vo->driver->get_image(vo, imgfmt, w, h, stride_align, flags);
|
||||
}
|
||||
|
||||
static void *vo_thread(void *ptr)
|
||||
@@ -1400,12 +1400,12 @@ struct vo_frame *vo_get_current_vo_frame(struct vo *vo)
|
||||
}
|
||||
|
||||
struct mp_image *vo_get_image(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
if (vo->driver->get_image_ts)
|
||||
return vo->driver->get_image_ts(vo, imgfmt, w, h, stride_align);
|
||||
return vo->driver->get_image_ts(vo, imgfmt, w, h, stride_align, flags);
|
||||
if (vo->in->dr_helper)
|
||||
return dr_helper_get_image(vo->in->dr_helper, imgfmt, w, h, stride_align);
|
||||
return dr_helper_get_image(vo->in->dr_helper, imgfmt, w, h, stride_align, flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -184,6 +184,11 @@ enum {
|
||||
VO_CAP_FILM_GRAIN = 1 << 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
// Require DR buffers to be host-cached (i.e. fast readback)
|
||||
VO_DR_FLAG_HOST_CACHED = 1 << 0,
|
||||
};
|
||||
|
||||
#define VO_MAX_REQ_FRAMES 10
|
||||
|
||||
struct vo;
|
||||
@@ -349,6 +354,8 @@ struct vo_driver {
|
||||
* stride_align is always a value >=1 that is a power of 2. The stride
|
||||
* values of the returned image must be divisible by this value.
|
||||
*
|
||||
* flags is a combination of VO_DR_FLAG_* flags.
|
||||
*
|
||||
* Currently, the returned image must have exactly 1 AVBufferRef set, for
|
||||
* internal implementation simplicity.
|
||||
*
|
||||
@@ -356,7 +363,7 @@ struct vo_driver {
|
||||
* will silently fallback to a default allocator
|
||||
*/
|
||||
struct mp_image *(*get_image)(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align);
|
||||
int stride_align, int flags);
|
||||
|
||||
/*
|
||||
* Thread-safe variant of get_image. Set at most one of these callbacks.
|
||||
@@ -364,7 +371,7 @@ struct vo_driver {
|
||||
* vo_driver.uninit is not called before this function returns.
|
||||
*/
|
||||
struct mp_image *(*get_image_ts)(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align);
|
||||
int stride_align, int flags);
|
||||
|
||||
/*
|
||||
* Render the given frame to the VO's backbuffer. This operation will be
|
||||
@@ -516,7 +523,7 @@ double vo_get_delay(struct vo *vo);
|
||||
void vo_discard_timing_info(struct vo *vo);
|
||||
struct vo_frame *vo_get_current_vo_frame(struct vo *vo);
|
||||
struct mp_image *vo_get_image(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align);
|
||||
int stride_align, int flags);
|
||||
|
||||
void vo_wakeup(struct vo *vo);
|
||||
void vo_wait_default(struct vo *vo, int64_t until_time);
|
||||
|
||||
@@ -329,6 +329,31 @@ static int preinit(struct vo *vo)
|
||||
if (!p->ctx)
|
||||
goto err_out;
|
||||
assert(p->ctx->ra);
|
||||
|
||||
if (!vo->wl->dmabuf) {
|
||||
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
|
||||
zwp_linux_dmabuf_v1_interface.name);
|
||||
return VO_ERROR;
|
||||
}
|
||||
|
||||
if (!vo->wl->shm) {
|
||||
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
|
||||
wl_shm_interface.name);
|
||||
return VO_ERROR;
|
||||
}
|
||||
|
||||
if (!vo->wl->video_subsurface) {
|
||||
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
|
||||
wl_subcompositor_interface.name);
|
||||
return VO_ERROR;
|
||||
}
|
||||
|
||||
if (!vo->wl->viewport) {
|
||||
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
|
||||
wp_viewporter_interface.name);
|
||||
return VO_ERROR;
|
||||
}
|
||||
|
||||
vo->hwdec_devs = hwdec_devices_create();
|
||||
hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo);
|
||||
assert(!p->hwdec_ctx.ra);
|
||||
|
||||
+2
-2
@@ -265,11 +265,11 @@ static void wait_events(struct vo *vo, int64_t until_time_us)
|
||||
}
|
||||
|
||||
static struct mp_image *get_image(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
struct gpu_priv *p = vo->priv;
|
||||
|
||||
return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align);
|
||||
return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align, flags);
|
||||
}
|
||||
|
||||
static void uninit(struct vo *vo)
|
||||
|
||||
+10
-2
@@ -189,13 +189,18 @@ static void free_dr_buf(void *opaque, uint8_t *data)
|
||||
}
|
||||
|
||||
static struct mp_image *get_image(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
pl_gpu gpu = p->gpu;
|
||||
if (!gpu->limits.thread_safe || !gpu->limits.max_mapped_size)
|
||||
return NULL;
|
||||
|
||||
#if PL_API_VER >= 234
|
||||
if ((flags & VO_DR_FLAG_HOST_CACHED) && !gpu->limits.host_cached)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
int size = mp_image_get_alloc_size(imgfmt, w, h, stride_align);
|
||||
if (size < 0)
|
||||
return NULL;
|
||||
@@ -344,7 +349,9 @@ static int plane_data_from_imgfmt(struct pl_plane_data out_data[4],
|
||||
if ((desc.flags & MP_IMGFLAG_TYPE_FLOAT) && (desc.flags & MP_IMGFLAG_YUV))
|
||||
return 0; // Floating-point YUV (currently) unsupported
|
||||
|
||||
bool has_bits = false;
|
||||
bool any_padded = false;
|
||||
|
||||
for (int p = 0; p < desc.num_planes; p++) {
|
||||
struct pl_plane_data *data = &out_data[p];
|
||||
struct mp_imgfmt_comp_desc sorted[MP_NUM_COMPONENTS];
|
||||
@@ -390,8 +397,9 @@ static int plane_data_from_imgfmt(struct pl_plane_data out_data[4],
|
||||
.bit_shift = MPMAX(sorted[c].pad, 0),
|
||||
};
|
||||
|
||||
if (p == 0 && c == 0) {
|
||||
if (!has_bits) {
|
||||
*out_bits = bits;
|
||||
has_bits = true;
|
||||
} else {
|
||||
if (!pl_bit_encoding_equal(out_bits, &bits)) {
|
||||
// Bit encoding differs between components/planes,
|
||||
|
||||
@@ -152,11 +152,11 @@ static void dispatch_wakeup(void *ptr)
|
||||
}
|
||||
|
||||
static struct mp_image *render_get_image(void *ptr, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
struct mpv_render_context *ctx = ptr;
|
||||
|
||||
return ctx->renderer->fns->get_image(ctx->renderer, imgfmt, w, h, stride_align);
|
||||
return ctx->renderer->fns->get_image(ctx->renderer, imgfmt, w, h, stride_align, flags);
|
||||
}
|
||||
|
||||
int mpv_render_context_create(mpv_render_context **res, mpv_handle *mpv,
|
||||
@@ -654,13 +654,13 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||
}
|
||||
|
||||
static struct mp_image *get_image(struct vo *vo, int imgfmt, int w, int h,
|
||||
int stride_align)
|
||||
int stride_align, int flags)
|
||||
{
|
||||
struct vo_priv *p = vo->priv;
|
||||
struct mpv_render_context *ctx = p->ctx;
|
||||
|
||||
if (ctx->dr)
|
||||
return dr_helper_get_image(ctx->dr, imgfmt, w, h, stride_align);
|
||||
return dr_helper_get_image(ctx->dr, imgfmt, w, h, stride_align, flags);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+22
-14
@@ -128,17 +128,38 @@ error0:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void uninit(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
struct buffer *buf;
|
||||
|
||||
while (p->free_buffers) {
|
||||
buf = p->free_buffers;
|
||||
p->free_buffers = buf->next;
|
||||
talloc_free(buf);
|
||||
}
|
||||
vo_wayland_uninit(vo);
|
||||
}
|
||||
|
||||
static int preinit(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
if (!vo_wayland_init(vo))
|
||||
return -1;
|
||||
goto err;
|
||||
if (!vo->wl->shm) {
|
||||
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
|
||||
wl_shm_interface.name);
|
||||
goto err;
|
||||
}
|
||||
p->sws = mp_sws_alloc(vo);
|
||||
p->sws->log = vo->log;
|
||||
mp_sws_enable_cmdline_opts(p->sws, vo->global);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
uninit(vo);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int query_format(struct vo *vo, int format)
|
||||
@@ -273,19 +294,6 @@ static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
|
||||
present_sync_get_info(wl->present, info);
|
||||
}
|
||||
|
||||
static void uninit(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
struct buffer *buf;
|
||||
|
||||
while (p->free_buffers) {
|
||||
buf = p->free_buffers;
|
||||
p->free_buffers = buf->next;
|
||||
talloc_free(buf);
|
||||
}
|
||||
vo_wayland_uninit(vo);
|
||||
}
|
||||
|
||||
const struct vo_driver video_out_wlshm = {
|
||||
.description = "Wayland SHM video output (software scaling)",
|
||||
.name = "wlshm",
|
||||
|
||||
@@ -34,10 +34,8 @@ static bool xlib_check_visible(struct ra_ctx *ctx)
|
||||
|
||||
static void xlib_vk_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
if (ctx->vo->x11->use_present) {
|
||||
vo_x11_present(ctx->vo);
|
||||
if (ctx->vo->x11->use_present)
|
||||
present_sync_swap(ctx->vo->x11->present);
|
||||
}
|
||||
}
|
||||
|
||||
static void xlib_vk_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
|
||||
|
||||
@@ -34,7 +34,7 @@ void mpvk_uninit(struct mpvk_ctx *vk)
|
||||
if (vk->surface) {
|
||||
assert(vk->vkinst);
|
||||
vkDestroySurfaceKHR(vk->vkinst->instance, vk->surface, NULL);
|
||||
vk->surface = NULL;
|
||||
vk->surface = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
pl_vk_inst_destroy(&vk->vkinst);
|
||||
|
||||
+85
-32
@@ -139,6 +139,12 @@ const struct m_sub_options wayland_conf = {
|
||||
},
|
||||
};
|
||||
|
||||
struct vo_wayland_feedback_pool {
|
||||
struct wp_presentation_feedback **fback;
|
||||
struct vo_wayland_state *wl;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct vo_wayland_output {
|
||||
struct vo_wayland_state *wl;
|
||||
struct wl_output *output;
|
||||
@@ -163,7 +169,11 @@ static int lookupkey(int key);
|
||||
static int set_cursor_visibility(struct vo_wayland_state *wl, bool on);
|
||||
static int spawn_cursor(struct vo_wayland_state *wl);
|
||||
|
||||
static void add_feedback(struct vo_wayland_feedback_pool *fback_pool,
|
||||
struct wp_presentation_feedback *fback);
|
||||
static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b);
|
||||
static void remove_feedback(struct vo_wayland_feedback_pool *fback_pool,
|
||||
struct wp_presentation_feedback *fback);
|
||||
static void remove_output(struct vo_wayland_output *out);
|
||||
static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode);
|
||||
static void set_geometry(struct vo_wayland_state *wl);
|
||||
@@ -299,19 +309,20 @@ static void touch_handle_down(void *data, struct wl_touch *wl_touch,
|
||||
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
|
||||
{
|
||||
struct vo_wayland_state *wl = data;
|
||||
|
||||
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
|
||||
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
|
||||
|
||||
enum xdg_toplevel_resize_edge edge;
|
||||
if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y)) {
|
||||
if (check_for_resize(wl, x_w, y_w, wl->opts->edge_pixels_touch, &edge)) {
|
||||
xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edge);
|
||||
} else {
|
||||
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
|
||||
}
|
||||
}
|
||||
|
||||
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
|
||||
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN);
|
||||
|
||||
enum xdg_toplevel_resize_edge edge;
|
||||
if (check_for_resize(wl, x_w, y_w, wl->opts->edge_pixels_touch, &edge)) {
|
||||
xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edge);
|
||||
} else {
|
||||
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
|
||||
}
|
||||
}
|
||||
|
||||
static void touch_handle_up(void *data, struct wl_touch *wl_touch,
|
||||
@@ -752,8 +763,8 @@ static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
|
||||
if (!mp_rect_equals(&old_geometry, &wl->geometry) || force_resize)
|
||||
wl->pending_vo_events |= VO_EVENT_RESIZE;
|
||||
|
||||
MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i\n", o->make,
|
||||
o->model, o->id, wl->scaling);
|
||||
MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i, refresh rate = %f Hz\n",
|
||||
o->make, o->model, o->id, wl->scaling, o->refresh_rate);
|
||||
|
||||
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
|
||||
}
|
||||
@@ -1014,15 +1025,11 @@ static void feedback_presented(void *data, struct wp_presentation_feedback *fbac
|
||||
uint32_t seq_hi, uint32_t seq_lo,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct vo_wayland_state *wl = data;
|
||||
struct vo_wayland_feedback_pool *fback_pool = data;
|
||||
struct vo_wayland_state *wl = fback_pool->wl;
|
||||
|
||||
// NULL is needed to prevent a dangling pointer since presentation_feedback
|
||||
// is created in the frame_callback and not in any of the actual presentation
|
||||
// events.
|
||||
if (fback) {
|
||||
wp_presentation_feedback_destroy(fback);
|
||||
wl->feedback = NULL;
|
||||
}
|
||||
if (fback)
|
||||
remove_feedback(fback_pool, fback);
|
||||
|
||||
if (!wl->use_present)
|
||||
return;
|
||||
@@ -1046,13 +1053,9 @@ static void feedback_presented(void *data, struct wp_presentation_feedback *fbac
|
||||
|
||||
static void feedback_discarded(void *data, struct wp_presentation_feedback *fback)
|
||||
{
|
||||
struct vo_wayland_state *wl = data;
|
||||
|
||||
// Same logic in feedback_presented applies here.
|
||||
if (fback) {
|
||||
wp_presentation_feedback_destroy(fback);
|
||||
wl->feedback = NULL;
|
||||
}
|
||||
struct vo_wayland_feedback_pool *fback_pool = data;
|
||||
if (fback)
|
||||
remove_feedback(fback_pool, fback);
|
||||
}
|
||||
|
||||
static const struct wp_presentation_feedback_listener feedback_listener = {
|
||||
@@ -1074,8 +1077,9 @@ static void frame_callback(void *data, struct wl_callback *callback, uint32_t ti
|
||||
wl_callback_add_listener(wl->frame_callback, &frame_listener, wl);
|
||||
|
||||
if (wl->presentation) {
|
||||
wl->feedback = wp_presentation_feedback(wl->presentation, wl->surface);
|
||||
wp_presentation_feedback_add_listener(wl->feedback, &feedback_listener, wl);
|
||||
struct wp_presentation_feedback *fback = wp_presentation_feedback(wl->presentation, wl->surface);
|
||||
add_feedback(wl->fback_pool, fback);
|
||||
wp_presentation_feedback_add_listener(fback, &feedback_listener, wl->fback_pool);
|
||||
}
|
||||
|
||||
wl->frame_wait = false;
|
||||
@@ -1383,6 +1387,21 @@ static int create_xdg_surface(struct vo_wayland_state *wl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_feedback(struct vo_wayland_feedback_pool *fback_pool,
|
||||
struct wp_presentation_feedback *fback)
|
||||
{
|
||||
for (int i = 0; i < fback_pool->len; ++i) {
|
||||
if (!fback_pool->fback[i]) {
|
||||
fback_pool->fback[i] = fback;
|
||||
break;
|
||||
} else if (i == fback_pool->len - 1) {
|
||||
// Shouldn't happen in practice.
|
||||
wp_presentation_feedback_destroy(fback_pool->fback[i]);
|
||||
fback_pool->fback[i] = fback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_minimize(struct vo_wayland_state *wl)
|
||||
{
|
||||
if (!wl->xdg_toplevel)
|
||||
@@ -1506,6 +1525,28 @@ static void request_decoration_mode(struct vo_wayland_state *wl, uint32_t mode)
|
||||
zxdg_toplevel_decoration_v1_set_mode(wl->xdg_toplevel_decoration, mode);
|
||||
}
|
||||
|
||||
static void clean_feedback_pool(struct vo_wayland_feedback_pool *fback_pool)
|
||||
{
|
||||
for (int i = 0; i < fback_pool->len; ++i) {
|
||||
if (fback_pool->fback[i]) {
|
||||
wp_presentation_feedback_destroy(fback_pool->fback[i]);
|
||||
fback_pool->fback[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_feedback(struct vo_wayland_feedback_pool *fback_pool,
|
||||
struct wp_presentation_feedback *fback)
|
||||
{
|
||||
for (int i = 0; i < fback_pool->len; ++i) {
|
||||
if (fback_pool->fback[i] == fback) {
|
||||
wp_presentation_feedback_destroy(fback);
|
||||
fback_pool->fback[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_output(struct vo_wayland_output *out)
|
||||
{
|
||||
if (!out)
|
||||
@@ -1697,6 +1738,9 @@ static void window_move(struct vo_wayland_state *wl, uint32_t serial)
|
||||
|
||||
static void vo_wayland_dispatch_events(struct vo_wayland_state *wl, int nfds, int timeout)
|
||||
{
|
||||
if (wl->display_fd == -1)
|
||||
return;
|
||||
|
||||
struct pollfd fds[2] = {
|
||||
{.fd = wl->display_fd, .events = POLLIN },
|
||||
{.fd = wl->wakeup_pipe[0], .events = POLLIN },
|
||||
@@ -1911,6 +1955,7 @@ int vo_wayland_init(struct vo *vo)
|
||||
.refresh_interval = 0,
|
||||
.scaling = 1,
|
||||
.wakeup_pipe = {-1, -1},
|
||||
.display_fd = -1,
|
||||
.dnd_fd = -1,
|
||||
.cursor_visible = true,
|
||||
.vo_opts_cache = m_config_cache_alloc(wl, vo->global, &vo_sub_opts),
|
||||
@@ -1931,6 +1976,12 @@ int vo_wayland_init(struct vo *vo)
|
||||
/* Do a roundtrip to run the registry */
|
||||
wl_display_roundtrip(wl->display);
|
||||
|
||||
if (!wl->surface) {
|
||||
MP_FATAL(wl, "Compositor doesn't support %s (ver. 4)\n",
|
||||
wl_compositor_interface.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wl->wm_base) {
|
||||
MP_FATAL(wl, "Compositor doesn't support the required %s protocol!\n",
|
||||
xdg_wm_base_interface.name);
|
||||
@@ -1970,6 +2021,11 @@ int vo_wayland_init(struct vo *vo)
|
||||
}
|
||||
|
||||
if (wl->presentation) {
|
||||
wl->fback_pool = talloc_zero(wl, struct vo_wayland_feedback_pool);
|
||||
wl->fback_pool->wl = wl;
|
||||
wl->fback_pool->len = 8; // max swapchain depth allowed
|
||||
wl->fback_pool->fback = talloc_zero_array(wl->fback_pool, struct wp_presentation_feedback *,
|
||||
wl->fback_pool->len);
|
||||
wl->present = talloc_zero(wl, struct mp_present);
|
||||
} else {
|
||||
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
|
||||
@@ -2122,8 +2178,8 @@ void vo_wayland_uninit(struct vo *vo)
|
||||
if (wl->dnd_offer)
|
||||
wl_data_offer_destroy(wl->dnd_offer);
|
||||
|
||||
if (wl->feedback)
|
||||
wp_presentation_feedback_destroy(wl->feedback);
|
||||
if (wl->fback_pool)
|
||||
clean_feedback_pool(wl->fback_pool);
|
||||
|
||||
if (wl->frame_callback)
|
||||
wl_callback_destroy(wl->frame_callback);
|
||||
@@ -2277,9 +2333,6 @@ void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us)
|
||||
{
|
||||
struct vo_wayland_state *wl = vo->wl;
|
||||
|
||||
if (wl->display_fd == -1)
|
||||
return;
|
||||
|
||||
int64_t wait_us = until_time_us - mp_time_us();
|
||||
int timeout_ms = MPCLAMP((wait_us + 999) / 1000, 0, 10000);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ struct vo_wayland_state {
|
||||
|
||||
/* presentation-time */
|
||||
struct wp_presentation *presentation;
|
||||
struct wp_presentation_feedback *feedback;
|
||||
struct vo_wayland_feedback_pool *fback_pool;
|
||||
struct mp_present *present;
|
||||
int64_t refresh_interval;
|
||||
bool use_present;
|
||||
|
||||
Reference in new issue
Block a user