Compare commits

...
40 Commits
Author SHA1 Message Date
sfan5 140ec21c89 Release 0.35.1 2023-01-28 17:49:47 +01:00
Sultan Alsawaf db524988b1 x11: remove PresentNotifyMSC from egl/glx/vulkan to fix xpresent timing
PresentNotifyMSC turns out to be not only redundant, but also harmful with
mesa-backed egl/glx/vulkan VOs because for all of them, mesa uses
PresentPixmap behind the scenes when DRI3 is available, which already
spawns a PresentCompleteNotify event when the buffer swap actually
finishes. This is important because without using the timing information
from these PresentCompleteKindPixmap events, there's no way for mpv to know
exactly when a frame becomes visible on the display.

By using PresentNotifyMSC in conjunction with DRI3-enabled mesa, two
problems are created:
1. mpv assumes that a vblank won't elapse (i.e., it assumes the current MSC
   won't change) between the time when mesa enqueues the buffer swap and
   the time when mpv calls PresentNotifyMSC to ask xorg for a notification
   at the next MSC, relative to the current MSC at the time that xorg reads
   it for the PresentNotifyMSC call. This means that mpv could get a
   notification one or more vblanks later than it expects, since the
   intention here is for mpv to get a notification at the MSC that the
   buffer swap completes.
2. mpv assumes that a buffer swap always takes one vblank to complete,
   which isn't always true. A buffer swap (i.e., a page flip) could take
   longer than that depending on hardware conditions (if the GPU is running
   slowly or needs to exit a low-power state), scheduling delays (under
   heavy system or GPU load), or unfortunate timing (if the raster scan
   line happens to be at one of the last few rows of pixels and a vblank
   elapses just before the buffer swap is enqueued).

This causes mpv to have a faulty assumption of when frames become visible.

Since mpv already receives the PresentCompleteNotify events generated by
mesa's buffer swaps under the hood, the PresentNotifyMSC usage is unneeded
and just throws a wrench in mpv's vsync timing when xpresent is enabled.

Simply removing the PresentNotifyMSC usage from the egl, glx, and vulkan
VOs fixes the xpresent vsync timing.
2023-01-28 17:42:34 +01:00
8e2dc8b02b vo_gpu: implement VO_DR_FLAG_HOST_CACHED
For OpenGL, this is based on simply comparing GL_VENDOR strings against
a list of allowed vendors.

Co-authored-by: Nicolas F. <ovdev@fratti.ch>
Co-authored-by: Niklas Haas <git@haasn.dev>
2023-01-24 16:40:38 +01:00
Niklas Haas 16c0ac226a vo_gpu_next: implement VO_DR_FLAG_HOST_CACHED
For sufficiently new versions of libplacebo.
2023-01-24 16:40:37 +01:00
01374b6830 vd_lavc: add "auto" choice for vd-lavc-dr
--vd-lavc-dr defaulted to "yes", which caused issues on certain
hardware. Instead of disabling it, add a new "auto" value and
make it the default.

The "auto" choice will enable DR only when we can request host-cached
buffers (as signalled by the new VO_DR_FLAG_HOST_CACHED).

Co-authored-by: Nicolas F. <ovdev@fratti.ch>
Co-authored-by: Niklas Haas <git@haasn.dev>
2023-01-24 16:40:37 +01:00
Niklas Haas fc115bce2c vo: add int flags to the get_image signature
This is a huge disgusting mess to thread through everywhere. Maybe I'm
stupid for attempting to solve the problem this way.
2023-01-24 16:40:37 +01:00
Niklas Haas b64f9fe646 mp_image: fix XYZ primaries default
This was incorrectly set to BT.2020, when it should be DCI-P3 for pretty
much all real-world XYZ content (which is digital cinema content).
2023-01-24 16:40:37 +01:00
Dudemanguy 3813cc4a14 wayland: store presentation feedbacks in a pool
Officially, the most cursed part of the wayland code in mpv (third or
fourth try now?) This time, let's allocate a pool during init
(arbitrarily set to the maximum swapchain length mpv allows, 8; don't
even know if this actually works in wayland). Then we add/remove
feedbacks from the pool during the lifecycle of the VO, and clean it up
all at the end. Hopefully, this does the trick for good this time.
2023-01-24 16:40:37 +01:00
Dudemanguy 8ddc0e8888 audio: fix crash during uninit on ao_lavc
The buffer state can be null when using --ao=lavc, so just check it
first. Fixes #10175.
2023-01-24 16:39:33 +01:00
Ionen Wolkens 46cd82a68d meson: also search for rst2html with .py extension
This allows using rst2html.py from docutils if present, this
was already done for rst2man.py (unneeded for rst2pdf).
2023-01-24 16:39:33 +01:00
sfan5 222f9c5635 ra_d3d11: fix incorrect type
As it happens, `SIZE_T` and `size_t` are not the same length on 32-bit Windows
2023-01-24 16:39:33 +01:00
Dudemanguy c5e4d65e71 vo_wlshm: cleanup on failure
If failure occurs during preinit, vo_wlshm should goto an error and
cleaup itself like the other VOs.
2023-01-24 16:39:33 +01:00
Christoph Reiter 9f6e1b3ba1 vulkan: fix build error for 32bit builds with clang
vk->surface is a handle and not a pointer, so assign VK_NULL_HANDLE.
This fixes the following build error on 32bit Windows when using clang for example,
which errors out when assigning a 32bit pointer to a 64bit integer:

  ../mpv-0.35.0/video/out/vulkan/utils.c:37:21:
    error: incompatible pointer to integer conversion assigning to 'VkSurfaceKHR' (aka 'unsigned long long') from 'void *' [-Wint-conversion]
          vk->surface = NULL;
                      ^ ~~~~
2023-01-24 16:39:33 +01:00
Dudemanguy 688a321dbb version.py/version.sh: bump copyright year 2023-01-24 16:39:33 +01:00
Simon Ruderich 46d3dc2a42 demux: boost read EBU R128 gain values to ReplayGain's reference level
Without this change the same track encoded as Opus - which requires R128
tagging - and e.g. Vorbis with ReplayGain tagging have different volumes.
This is caused by ReplayGain 2 having a higher reference level of -18 dB
LUFS, while EBU R128 has a lower reference level of -23 dB LUFS.

For the results of gain application to match, the read EBU R128
values need to be boosted according to the difference in reference
levels.

Patch inspired by mpd's source code.
2023-01-24 16:39:33 +01:00
Dudemanguy 5436852bf5 wayland: initalize display_fd as -1
In the event of a failed wayland initalization, the display_fd is
actually 0 instead of -1 which would correctly indicate it doesn't
exist. Also move the fd check inside vo_wayland_dispatch_events since
that function shouldn't ever do anything if we don't actually have a
display fd.
2023-01-24 15:56:57 +01:00
Dudemanguy 6076691b94 draw_bmp: ensure last slice width is less than total width
e97819f88e corrected a special case
condition that lead to an out of bounds access if the total width
happened to be an integer multiple of SLICE_W (256) which could cause a
crash in software VOs. However, it turns out that the functions in this
file evaluate quite differently when using encoding mode (and presumably
libmpv as well according to reports although I could not independently
verify it).

The logic here gets complicated but what ends up happening is that, in
blend_overlay_with_video, the value of x + w can be greater than p->w in
certain cases in encoding mode. The x is the positional value of the
slice which remained unchanged from before, but w can take the full
value of SLICE_W (256) which is not necessarily correct. The width of
the final slice here should be the total remaining width. We can handle
this in mark_rect by simply always adjusting x1 of the last slice to be
equal to total width - SLICE_W * x so it can never extend beyond where
it should be. In practice, this value should be the maximum allowed
here. I'm not sure if the existing x1 value can possibly already be
lower than SLICE_W, but just MPMIN it to be on the safe side.
Fixes #10908.
2023-01-24 15:56:57 +01:00
repojohnray b963113c00 vo: hwdec: fix drmGetDeviceNameFromFd2() related memory leak
This commit fixes a minor memory leak related to drmGetDeviceNameFromFd2().
This function returns a string allocated with strdup().
2023-01-24 15:56:57 +01:00
repojohnray fd279c9a2a hwdec_drmprime: fix memory leak 2023-01-24 15:56:56 +01:00
Li Chang ec2a9d4332 ao_coreaudio: use AudioUnitReset as ao_driver.reset to prevent long restart
[motivation]
Seeking on MacOS appears to be lagged when users connect
to wireless audio output (airpods for example).

This commit attempts to fix mpv-player/mpv#10270

[observation]
1. When using other media player (VLC to be exact) simultaneously,
the lagging on seek disappear. We could guess that the AudioDevice
is on some sort of "warm-up" state.

See mpv-player/mpv#9243 for detailed description.

2. `AudioOutputUnitStart` takes significant longer time after each seek
or pause/play when using wireless output devices compares to wired devices.

[rationale]
After investigate codes in ao_coreaudio.c, it appears that the the `stop`
function was used as `ao_driver.reset` function. Therefore every seek
and pause would call `AudioOutputUnitStop`.

It turns out that `ao_driver.reset` function is used in `ao_reset`.
And `ao_reset` function is used to clean up the state of current `ao`
so I think `AudioUnitReset` is more proper than `AudioOutputUnitStop`
under this semantics.

Since ao_coreaudio use pull base mechanism, audio playback behaviors
upon pause/seek could be handled by callback function
(streaming silence when paused) so there is no need to stop AudioUnit when resetting.
Therefore using `AudioUnitReset` as `ao_driver.reset` looks proper.

Additionally, after using proper reset, the AudioUnit that represents
hardware I/O devices doesn't need to be restart everytime seek/pause actions happen.
Restarting wireless devices simply takes longer in MacOS which is
the root cause of lagging observed by users when they seek or pause/play media.

[method]
Use `AudioUnitReset` for ao_driver.reset.
2023-01-24 15:56:56 +01:00
Kacper Michajłow 666201d716 vo_opengl: do not blindly reject all Microsoft's OpenGL implementations
This change enables mpv to work in the WSL2 (WSLg) environment where
OpenGL is implemented on top of D3D12.

This reverts commit 149d98d244.

Mentioned OpenGL implementation (GDI Generic) in the original change
will be rejected by version check, so there is no need to handle it
manually.

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
2023-01-24 15:56:56 +01:00
Nicolas F daf9a3c971 external_files: set log level for potential files to trace
We ask users to freely share log files with us, which is usually
okay, unless a user has some unrelated and potentially embarrassing
files in their working directory. These would show up in the debug
level message output that --log-file enables.

Change the listing of potential external files to trace log level,
to save the users and the developers the embarrassment.
2023-01-24 15:56:56 +01:00
chen70 b960de5fe3 hwdec/d3d11va: fix a possible memory leak 2023-01-24 15:56:56 +01:00
garamond13 c0fa12c958 filter_kernels: fix kaiser
Seems to me that params[1] is set to NAN and here should be the same value as in params[0].
2023-01-24 15:56:56 +01:00
Thomas Weißschuh 7753a73a17 ao_pipewire: clean up when hotplug_init fails 2023-01-24 15:56:56 +01:00
Thomas Weißschuh dadcb2e614 ao_pipewire: destroy context on connection failure 2023-01-24 15:56:56 +01:00
Thomas Weißschuh f8b7170871 ao_pipewire: free properties on failure 2023-01-24 15:56:56 +01:00
rcombs 71346393e2 ao_coreaudio: use device's nominal sample rate for latency properties
Fixes sync issues when using high-latency devices at non-native sample rates

Closes #10984
2023-01-24 15:56:56 +01:00
Dudemanguy ae7ee7417f wayland: check for resize/move in touch event first
8300830951 rearranged/simplified some of
the wayland touch code mainly because what was there before was
completely broken on my machine in those days (dragging was unreliable,
resizing was really buggy, etc.). However, one user said that touch
input no longer worked for him after that change. I could not ever
reproduce it, but it seems the issue was putting down the key before
testing for resize/move in the code. Now who knows why this actually
matters, but apparently it works for the user in question and I don't
observe any unexpected behavior on my end when swapping the order. Like
the mouse/pointer code, we also now do a test for dragging before
actually trying a resize/move which is a little more consistent than
before. Fixes #9771.
2023-01-24 15:56:56 +01:00
Dudemanguy 74baedffec osc: don't spam window-controls bindings on every render
Not sure when this actually started happening, but it's probably been
like this for years. Currently, the logic for the window-controls works
by simply checking if the osc is visible and then either enabling or
disabling the associated keybindings. The problem is that this can just
constantly spam mp.enable_keybindings/disable_key_bindings on every
single render call if the user disables the border at any point in time.
This does a lot of pointless work and also results in the logs being
spammed with lines like "disable-section". Clearly, this should just
work like the code for checking the input keybindings just above it.
Keep track of an internal state variable and check when it doesn't match
the osc visibility. In that case, we can then either enable or disable
the key bindings and just update the variable.
2023-01-24 15:56:56 +01:00
Thomas Weißschuh 495206dd41 ao_pipewire: log sample queueing
This allows us to more easily see the datapath from mpv to pipewire.

We know how often the callbacks are triggered, how big the buffers are
and how much data mpv provides to pipewire.
2023-01-24 15:56:56 +01:00
Dudemanguy 37869fbcd7 meson: fix stdatomic detection on bsd
BSDs use compiler-rt instead of libatomic for atomic types. In this
case, we can handle it similar to how dl is detected. Check for the
library (allowing for it to fail), and then check for a header symbol
while linking latomic. Fixes #10906.
2023-01-24 15:56:56 +01:00
Niklas Haas 954d53612c lcms: fix validate_3dlut_size_opt
Not only was this function needlessly convoluted, it was also broken -
since it returned a bool value where an error code was expected.
2023-01-24 15:56:56 +01:00
Niklas Haas 6860343a25 lcms: always parse lcms2-related options
Currently, the lcms-related options are only defined when lcms2 is
enabled at build time. However, this causes issues (e.g. segfault) for
vo_gpu_next, which relies on the presence of these options (to forward
them to libplacebo).

(That libplacebo internally depends on lcms2 as well is an
implementation detail - compiling mpv *without* lcms against libplacebo
*with* lcms should be possible in principle)

Fixes: #10891
Closes: #10856
2023-01-24 15:56:56 +01:00
Dudemanguy f5ce1fbf44 meson: unbreak dl check on BSDs without libdl
Regression from 1835dfc05c. The actual
libdl dependency is not always required for the function symbol check.
Fixes #10901.
2023-01-24 15:56:56 +01:00
Dudemanguy 214e47854a meson: prepend MPV_CONFDIR path with prefix
Meson uses the sysconfdir option for setting the global config
directory. This conveniently defaults to /etc if the prefix is set to
/usr which is nice for linux distros. BSDs tend to use /usr/local which
causes this value to become 'etc' by default which is not an absolute
path so you would need to set something like -Dsysconfdir=/usr/local/etc
as well in the configuration step. It turns out we can have our cake and
eat it too by just joining the paths of prefix and sysconfdir together.
In the case where -Dprefix=/usr, this still results in /etc/mpv as the
path since the path joining logic just drops the leading '/usr/'. For
the /usr/local case, it ends up as /usr/local/etc/mpv as expected. This
fixes #10882.
2023-01-24 15:56:56 +01:00
Niklas Haas 5fb7a23d37 vo_gpu_next: fix undefined behavior on alpha-first formats
When the alpha channel is the first component, this code block gets
skipped by the continue, meaning the check for c==0 never passes.

Fix it by explicitly keeping track of whether bits have been set.
2023-01-24 15:56:56 +01:00
Dudemanguy f593186e7d wayland: also log refresh rate on surface entrance
Never bothered to log this for some reason, but it's pretty convenient
when debugging.
2023-01-24 15:56:56 +01:00
Dudemanguy 5149805f6b wayland: error out if essential protocol support is missing
Related issue: #10868. While most protocols are in theory optional, a
small amount of them are absolutely essential and nothing will work
without them. We should make sure to error out in those cases and not
try to actually do anything. For wayland support in general,
wl_compositor support is obviously required. If there is no wl_surface,
you can't do anything. Additionally, vo_wlshm quite obviously requires
wl_shm so mark that one as well. vo_dmabuf_wayland needs linux_dmabuf,
viewporter, wl_shm, and wl_subcompositor. In practice, these are all
very standard protocols and shouldn't be missing but the linked issue
above is at least one example where a compositor was stuck on an ancient
version of a wayland interface.
2023-01-24 15:56:56 +01:00
Thomas Weißschuh af1e00b2ce ao_pipewire: log version information and metadata 2023-01-24 15:56:56 +01:00
47 changed files with 398 additions and 176 deletions

No files matched your search

+3
View File
@@ -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`,
+6 -2
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
0.35.0
0.35.1
+4 -4
View File
@@ -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,
+9 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+5
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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
+7 -4
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -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);
}
+1 -1
View File
@@ -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;
+9 -6
View File
@@ -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;
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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,
},
};
+2 -2
View File
@@ -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,
+1
View File
@@ -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 {
+8 -1
View File
@@ -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;
+1 -1
View File
@@ -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
+1
View File
@@ -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[] = {
+5 -1
View File
@@ -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
View File
@@ -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
+19 -3
View File
@@ -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;
+1
View File
@@ -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
};
+1 -3
View File
@@ -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)
+1 -3
View File
@@ -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)
+1
View File
@@ -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++) {
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+25
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+4 -4
View File
@@ -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
View File
@@ -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",
+1 -3
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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;