add new app_bridge objc file for bridging between mpv core and app
functionality. replace old EventsResponder singleton with AppHub.
another step to clean up all App functionality and have one central
place for it.
cocoa-cb was always pre-allocated in the Application itself because
libmpv needs to be set up before usage, an opengl context has to be set
and because it was decided mac specific code should be kept out of
libmpv.
this means that a completely working libmpv and opengl renderer was set
up even if it wasn't used. leading to unnecessary log message, resources
being used or reserved on the system that might not be used, triggering
of dedicated GPU unnecessarily and many other things.
even if not optimal, this wasn't the biggest problem since we only had
that one working vo on macOS. though now that we have a vulkan
gpu(-next) backend on macOS that was made the default, we always have
that dangling cocoa-cb instance, which is completely unnecessary.
move the cocoa-cb initialisation into libmpv preinit function and only
init cocoa-cb when we are a standalone App and cocoa-cb support is build
into.
this partially reverts commit 7b5a258. back then the only properly
working vo on macOS was cocoa-cb (libmpv). it would always use the
deprecated opengl cocoa backend or no vo at all. because of that libmpv
was moved to the top of the auto-probing order, so the preferred vo
was used on macOS only.
we now have a working vulkan gpu/gpu-next backend on macOS which should
be the new default vo. though disabling the auto-probing again for
libmpv would probably cause the undesired behaviour on macOS that
cocoa-cb would never be auto selected again. especially if not build
with vulkan support or without vulkan driver on macOS, this would lead
to no video output at all. so instead of completely reverting the
mentioned commit, we instead move libmpv to the bottom of the
auto-probing order but only auto select it when mpv was built with
cocoa-cb support. this restores the previous behaviour on all other
platforms besides macOS, but also lets us auto select cocoa-cb if
supported.
Since 03cf150ff3, the only purpose of this
VOCTRL was to signal a redraw to the vo. It actualy could have been
removed in 531868fe0d, but this was
missed. The UPDATE_VIDEO flag is better anyway because it allows us to
handle a wide variety of options scattered around that require the VO to
update itself and redraw. We can remove both of the custom callbacks in
vo.c and only leave the VOCTRL_VO_OPTS_CHANGED one. Additionally, that
commit also introduced vo_set_want_redraw, but this is redundant and not
needed. The VOs that use VOCTRL_UPDATE_RENDER_OPTS already set
vo->want_redraw, and those are the only VOs where these options are
relevant in the first place. So we can remove this as well and just let
the big callback in player/command do everything.
since i was going to fix the include order of stdatomic, might as well
sort the surrouding includes in accordance with the project's coding
style.
some headers can sometime require specific include order. standard
library headers usually don't. but mpv might "hack into" the standard
headers (e.g pthreads) so that complicates things a bit more.
hopefully nothing breaks. if it does, the style guide is to blame.
replace it with <stdatomic.h> and replace the mp_atomic_* typedefs with
explicit _Atomic qualified types.
also add missing config.h includes on some files.
This can be used to make vo_libmpv render video to a memory buffer. It
only adds a new backend API that takes memory surfaces. All the render
API (such as frame rendering control and so on) is reused.
I'm not quite convinced of the usefulness of this, and until now I
always resisted providing something like this. It only seems to
facilitate inefficient implementation. But whatever.
Unfortunately, this duplicates the software rendering glue code yet
again (like it exists in vo_x11, vo_wlshm, vo_drm, and probably more).
But in theory, these could reuse this backend in the future, just like
vo_gpu could reuse the render_gl API.
Fixes: #7852
The render API (vo_libmpv) had potential deadlock problems with
MPV_RENDER_PARAM_ADVANCED_CONTROL. This required vd-lavc-dr to be
enabled (the default). I never observed these deadlocks in the wild
(doesn't mean they didn't happen), although I could specifically provoke
them with some code changes.
The problem was mostly about DR (direct rendering, letting the video
decoder write to OpenGL buffer memory). Allocating/freeing a DR image
needs to be done on the OpenGL thread, even though _lots_ of threads are
involved with handling images. Freeing a DR image is a special case that
can happen any time. dr_helper.c does most of the evil magic of
achieving this. Unfortunately, there was a (sort of) circular lock
dependency: freeing an image while certain internal locks are held would
trigger the user's context update callback, which in turn would call
mpv_render_context_update(), which processed all pending free requests,
and then acquire an internal lock - which the caller might not release
until a further DR image could be freed.
"Solve" this by making freeing DR images asynchronous. This is slightly
risky, but actually not much. The DR images will be free'd eventually.
The biggest disadvantage is probably that debugging might get trickier.
Any solution to this problem will probably add images to free to some
sort of queue, and then process it later. I considered making this more
explicit (so there'd be a point where the caller forcibly waits for all
queued items to be free'd), but discarded these ideas as this probably
would only increase complexity.
Another consequence is that freeing DR images on the GL thread is not
synchronous anymore. Instead, it mpv_render_context_update() will do it
with a delay. This seems roundabout, but doesn't actually change
anything, and avoids additional code.
This also fixes that the render API required the render API user to
remain on the same thread, even though this wasn't documented. As such,
it was a bug. OpenGL essentially forces you to do all GL usage on a
single thread, but in theory the API user could for example move the GL
context to another thread.
The API bump is because I think you can't make enough noise about this.
Since we don't backport fixes to old versions, I'm specifically stating
that old versions are broken, and I'm supplying workarounds.
Internally, dr_helper_create() does not use pthread_self() anymore, thus
the vo.c change. I think it's better to make binding to the current
thread as explicit as possible.
Of course it's not sure that this fixes all deadlocks (probably not).
This is mostly for the case when mpv_render_context_free() is called
while video is going on. This is supposed to gracefully stop video and
deinitialize everything properly. (I feel like it would put too much on
the API user to require that video is stopped before calling this
function. Whether video is running or not is a fairly highlevel thing,
and the API user could not do it in a race-free way.)
One problem was that unit() accessed ctx after ctx->in_use was set to
false. The update(ctx) call was basically a racy use-after-free. It
needed that call to wake up the mpv_render_context_free() loop that
waited for VO uninit. Fix this by triggering the wakeup inside the lock,
and then doing "barrier" locking in mpv_render_context_free().
Another problem was that the wait loop didn't really wait properly. IT
seems the had_kill_update field was a botched attempt to do that. It's
indeed quite hairy to do that with update(). Instead make use of the
dispatch queue (infinite timeout, using mp_dispatch_interrupt()), which
handles the problem of having to wait both for dispatch queue updates
and VO uninit at the same time.
Preparation for the next commit. Until now, it was only needed if DR was
involved. One reason for not always creating it was that you normally
must not use it if advanced_control is not enabled. This is why e.g.
VOCTRL_SCREENSHOT now checks for that variable; it still can't use
ctx->dispatch if the render API user did not enable it.
render api needs to wait for vo to be destroyed before frees the context.
The purpose of kill_cb is to wake up render api after vo is destroyed,
but uninit did that before kill_cb, so kill_cb tries using the freed
memory. Remove kill_cb to fix the issue as uninit is able to do the
work.
Attempts to enable the following things:
- let a render API user do "proper" audio-sync video timing itself
- make it possible to not re-render repeated frames if the API user has
better mechanisms available (e.g. waiting for a DisplayLink cycle
instead)
- allow the user to delay or skip redraws if it makes sense
Basically this information will be needed by API users who want to be
"clever" about optimizing timing and rendering.
In MPV_RENDER_PARAM_ADVANCED_CONTROL mode, a simple update callback does
not necessarily make the API user redraw. So handle it differently.
For one, setting vo->want_redraw already uses the "normal" redraw path,
which will call draw_frame() and set next_frame.
Then there are redraws trigered by mpv_render_context_set_parameter(),
which are on the render thread, and would require a separate mechanism.
I decided this is not really a good idea, since it's not even clear that
setting an arbitrary parameter should redraw. Also this could trigger an
unbounded number of redraws. The user can trigger redraws manually if
really needed, depending on the parameter that's being set. If we really
wanted vo_libmpv to do this, we could add a new flag like need_redraw,
which would be 4 lines of code or so.
update() used to require the lock, but now it doesn't matter. It's
slightly better to do it outside of the lock now, in case the update
callback reschedules before returning, and the user render thread tries
to acquire the still held lock (which would require 2 more context
switches).
DR (letting the decoder allocate texture memory) requires running the
allocation on the render thread. This is rather hard with the render
API, because the user controls this thread and when it's entered. It was
not possible until now.
This commit adds a bunch of infrastructure to make this possible. We add
a new optional mode (MPV_RENDER_PARAM_ADVANCED_CONTROL) which basically
lets the user's render thread and libmpv agree how this should be done.
Misuse would lead to deadlocks. To make this less likely, strictly
document thread safety/locking issues. In particular, document which
libmpv functions can be called without issues. (The rest has to be
assumed unsafe.)
The worst issue is destruction of the render context while video is
still active. To avoid certain unintended recursive locks (i.e.
deadlocks, unless we'd make the locks recursive), make the update
callback lock separate. Make "killing" the video chain asynchronous, so
we can do extra work while video is being destroyed.
Because losing wakeups is a big deal, setting the update callback now
triggers a wakeup. (It would have been better if the wakeup callback
were a parameter to mpv_render_context_create(), but too late.)
This commit does not add DR yet; the following commit does this.
The purpose of the new API is to make it useable with other APIs than
OpenGL, especially D3D11 and vulkan. In theory it's now possible to
support other vo_gpu backends, as well as backends that don't use the
vo_gpu code at all.
This also aims to get rid of the dumb mpv_get_sub_api() function. The
life cycle of the new mpv_render_context is a bit different from
mpv_opengl_cb_context, and you explicitly create/destroy the new
context, instead of calling init/uninit on an object returned by
mpv_get_sub_api().
In other to make the render API generic, it's annoyingly EGL style, and
requires you to pass in API-specific objects to generic functions. This
is to avoid explicit objects like the internal ra API has, because that
sounds more complicated and annoying for an API that's supposed to never
change.
The opengl_cb API will continue to exist for a bit longer, but
internally there are already a few tradeoffs, like reduced
thread-safety.
Mostly untested. Seems to work fine with mpc-qt.