1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-17 21:27:08 +00:00
mpv/video/out/wayland_common.h

198 lines
6.2 KiB
C
Raw Normal View History

/*
2013-09-09 16:37:33 +00:00
* This file is part of mpv video player.
*
Relicense some non-MPlayer source files to LGPL 2.1 or later This covers source files which were added in mplayer2 and mpv times only, and where all code is covered by LGPL relicensing agreements. There are probably more files to which this applies, but I'm being conservative here. A file named ao_sdl.c exists in MPlayer too, but the mpv one is a complete rewrite, and was added some time after the original ao_sdl.c was removed. The same applies to vo_sdl.c, for which the SDL2 API is radically different in addition (MPlayer supports SDL 1.2 only). common.c contains only code written by me. But common.h is a strange case: although it originally was named mp_common.h and exists in MPlayer too, by now it contains only definitions written by uau and me. The exceptions are the CONTROL_ defines - thus not changing the license of common.h yet. codec_tags.c contained once large tables generated from MPlayer's codecs.conf, but all of these tables were removed. From demux_playlist.c I'm removing a code fragment from someone who was not asked; this probably could be done later (see commit 15dccc37). misc.c is a bit complicated to reason about (it was split off mplayer.c and thus contains random functions out of this file), but actually all functions have been added post-MPlayer. Except get_relative_time(), which was written by uau, but looks similar to 3 different versions of something similar in each of the Unix/win32/OSX timer source files. I'm not sure what that means in regards to copyright, so I've just moved it into another still-GPL source file for now. screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but they're all gone.
2016-01-19 17:36:06 +00:00
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
2013-09-09 16:37:33 +00:00
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Relicense some non-MPlayer source files to LGPL 2.1 or later This covers source files which were added in mplayer2 and mpv times only, and where all code is covered by LGPL relicensing agreements. There are probably more files to which this applies, but I'm being conservative here. A file named ao_sdl.c exists in MPlayer too, but the mpv one is a complete rewrite, and was added some time after the original ao_sdl.c was removed. The same applies to vo_sdl.c, for which the SDL2 API is radically different in addition (MPlayer supports SDL 1.2 only). common.c contains only code written by me. But common.h is a strange case: although it originally was named mp_common.h and exists in MPlayer too, by now it contains only definitions written by uau and me. The exceptions are the CONTROL_ defines - thus not changing the license of common.h yet. codec_tags.c contained once large tables generated from MPlayer's codecs.conf, but all of these tables were removed. From demux_playlist.c I'm removing a code fragment from someone who was not asked; this probably could be done later (see commit 15dccc37). misc.c is a bit complicated to reason about (it was split off mplayer.c and thus contains random functions out of this file), but actually all functions have been added post-MPlayer. Except get_relative_time(), which was written by uau, but looks similar to 3 different versions of something similar in each of the Unix/win32/OSX timer source files. I'm not sure what that means in regards to copyright, so I've just moved it into another still-GPL source file for now. screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but they're all gone.
2016-01-19 17:36:06 +00:00
* GNU Lesser General Public License for more details.
*
Relicense some non-MPlayer source files to LGPL 2.1 or later This covers source files which were added in mplayer2 and mpv times only, and where all code is covered by LGPL relicensing agreements. There are probably more files to which this applies, but I'm being conservative here. A file named ao_sdl.c exists in MPlayer too, but the mpv one is a complete rewrite, and was added some time after the original ao_sdl.c was removed. The same applies to vo_sdl.c, for which the SDL2 API is radically different in addition (MPlayer supports SDL 1.2 only). common.c contains only code written by me. But common.h is a strange case: although it originally was named mp_common.h and exists in MPlayer too, by now it contains only definitions written by uau and me. The exceptions are the CONTROL_ defines - thus not changing the license of common.h yet. codec_tags.c contained once large tables generated from MPlayer's codecs.conf, but all of these tables were removed. From demux_playlist.c I'm removing a code fragment from someone who was not asked; this probably could be done later (see commit 15dccc37). misc.c is a bit complicated to reason about (it was split off mplayer.c and thus contains random functions out of this file), but actually all functions have been added post-MPlayer. Except get_relative_time(), which was written by uau, but looks similar to 3 different versions of something similar in each of the Unix/win32/OSX timer source files. I'm not sure what that means in regards to copyright, so I've just moved it into another still-GPL source file for now. screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but they're all gone.
2016-01-19 17:36:06 +00:00
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MPLAYER_WAYLAND_COMMON_H
#define MPLAYER_WAYLAND_COMMON_H
#include <wayland-client.h>
wayland: add support for xx-color-management-v4 for vo_dmabuf_wayland Although this protocol isn't official yet, several compositors are known to support it to some extent and this lets users actually view HDR with less hacks/workarounds. The actual protocol here is simply copy and pasted from the upstream fork* where these are developed. There is also icc profile support in the protocol, but this is omitted for now in favor of setting colorspaces and signalling hdr metadata. However for mpv, this only actually has any practical use with vo_dmabuf_wayland so this is the only VO that will make use of the protocol. When using vulkan, this is already handled via vulkan extensions by compositors and vo_gpu_next. So actually we don't want to use the wayland protocol in that case since it will just get in the way. The only known limitation on that front is driver support for hdr vulkan surfaces but as soon as that is available it should just work with no code changes. For opengl, hdr support there is a whole other mess with a lot of unknowns but simply using this protocol isn't good enough and would require changes elsewhere. vo_wlshm is currently too stupid to pick any format besides bgr0 or 0rgb, so any color management there is meaningless at this stage. So this means that only vo_dmabuf_wayland can actually use this protocol. But that's perfectly fine. Without this, vo_dmabuf_wayland has a very bad limitation in that it cannot communicate colorspaces at all and compositors have to guess. Using xx-color-management-v4 fixes this. For the other VOs, merely having the common protocol setup stuff in the common code does no harm and later if they get smarter, it's easy for them to use the stuff since it is written generically anyway. *: https://gitlab.freedesktop.org/swick/wayland-protocols/-/tree/color-xx/staging/color-management
2024-09-26 22:28:35 +00:00
#include "input/event.h"
wayland: add support for xx-color-management-v4 for vo_dmabuf_wayland Although this protocol isn't official yet, several compositors are known to support it to some extent and this lets users actually view HDR with less hacks/workarounds. The actual protocol here is simply copy and pasted from the upstream fork* where these are developed. There is also icc profile support in the protocol, but this is omitted for now in favor of setting colorspaces and signalling hdr metadata. However for mpv, this only actually has any practical use with vo_dmabuf_wayland so this is the only VO that will make use of the protocol. When using vulkan, this is already handled via vulkan extensions by compositors and vo_gpu_next. So actually we don't want to use the wayland protocol in that case since it will just get in the way. The only known limitation on that front is driver support for hdr vulkan surfaces but as soon as that is available it should just work with no code changes. For opengl, hdr support there is a whole other mess with a lot of unknowns but simply using this protocol isn't good enough and would require changes elsewhere. vo_wlshm is currently too stupid to pick any format besides bgr0 or 0rgb, so any color management there is meaningless at this stage. So this means that only vo_dmabuf_wayland can actually use this protocol. But that's perfectly fine. Without this, vo_dmabuf_wayland has a very bad limitation in that it cannot communicate colorspaces at all and compositors have to guess. Using xx-color-management-v4 fixes this. For the other VOs, merely having the common protocol setup stuff in the common code does no harm and later if they get smarter, it's easy for them to use the stuff since it is written generically anyway. *: https://gitlab.freedesktop.org/swick/wayland-protocols/-/tree/color-xx/staging/color-management
2024-09-26 22:28:35 +00:00
#include "video/mp_image.h"
#include "vo.h"
struct compositor_format;
struct vo_wayland_seat;
struct vo_wayland_tranche;
struct drm_format {
uint32_t format;
uint64_t modifier;
};
struct vo_wayland_state {
struct m_config_cache *opts_cache;
struct mp_log *log;
struct mp_vo_opts *opts;
struct vo *vo;
struct wl_callback *frame_callback;
struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
struct wl_display *display;
struct wl_registry *registry;
struct wl_shm *shm;
struct wl_surface *surface;
struct wl_surface *osd_surface;
struct wl_subsurface *osd_subsurface;
struct wl_surface *video_surface;
struct wl_surface *callback_surface;
struct wl_subsurface *video_subsurface;
/* Geometry */
struct mp_rect geometry;
struct mp_rect window_size;
struct wl_list output_list;
struct vo_wayland_output *current_output;
int bounded_height;
int bounded_width;
int reduced_height;
int reduced_width;
/* State */
bool activated;
bool focused;
bool frame_wait;
bool geometry_configured;
bool hidden;
bool initial_size_hint;
bool locked_size;
wayland: only perform a rescale if window is on one output The mpv window overlapping multiple outputs with different scale values can result in some weird behavior when dragging it from one monitor to another one. This is due to the way some compositors implement preferred_scale or preferred_buffer_scale (integer scale equivalent). Depending on the scale values, mpv window has to be resized to match the new scaling value (due to fractional scaling requiring a viewport). This can cause the window to become smaller and no longer overlap the monitor you were just trying to drag it to. Repeat this and the window will become smaller and smaller. Depending on the layout, the reverse can also happen (the window becomes larger). This can cause additional events to fire as the preferred_scale value may change again which does more weird things. It seems kwin is not affected by this because their implementation of preferred_scale sends the event only if the window is fully on the new monitor. Honestly, this is probably more logical anyway but we should at least deal with the other implementations better. Try to deal with it by reworking scaling changes so they only occur when the mpv window is fully on one monitor. If we get a preferred_scale event and there is an overlap, save it as a pending change to be performed on the next surface_enter or surface_leave event (whichever results in there being only one monitor. Some weird rendering glitches can still happen during overlap but this makes it usable again.
2024-04-09 16:34:15 +00:00
bool need_rescale;
bool reconfigured;
wayland: fix vertical resizing Resizing in strictly the vertical direction has been broken forever on wayland. It's because of how the keepaspect calculation always resized with respect to the width. So if you moved the mouse strictly vertically with no change left/right, the mpv window would never change size since it just calculates with respect to the width that doesn't change. Fixing this is kind of weird and maybe someone should think of a better algorithm for preserving aspect ratio (we just multiply by the gcd basically), but whatever. You might naively try something like "resize with respect to what direction changes the most" at first, but this leads to very cludgy resizing since during a typical mouse dragging motion, it will flip constantly from "resize w/ respect to the width" and "resize w/ respect to the height". It "works" but it's really ugly and not worth it. The trick is to realize that we need to consider the resizing state as one continuous motion, choose a direction initially, stick to it throughout the entirety of the resize, and reset the relevant parameters after we finish the resize. This ensures the direction never unintuitively flips during a motion, but also allows for the strictly vertical case to still work. Might as well note it here in the commit, but mpv's resizing behavior technically violates xdg-shell. For the resizing event, "[t]he window geometry specified in the configure event is a maximum; the client cannot resize beyond it." Well, we do obviously go beyond the maximum in certain cases. For example consider resizing strictly horizontally. The width value increases from the compositor but not the height. Since mpv preserves aspect ratio by default, the height obviously must increase which will go over the prescribed bounds by the compositor. This happens before and after this commit, and I think everyone agrees is the desired behavior. With this commit, now vertical resizing works which violates xdg-shell in the same way. Before, it incidentally obeyed the protocol since it did not resize at all, but let's presume users expect the window to actually get bigger when they do a drag resize. *: https://wayland.app/protocols/xdg-shell#xdg_toplevel:enum:state:entry:resizing
2024-09-06 15:38:14 +00:00
bool resizing;
bool scale_configured;
bool state_change;
bool tiled;
bool toplevel_configured;
int display_fd;
int mouse_x;
int mouse_y;
int pending_vo_events;
int pending_scaling; // base 120
int scaling; // base 120
double scaling_factor; // wl->scaling divided by 120
wayland: fix vertical resizing Resizing in strictly the vertical direction has been broken forever on wayland. It's because of how the keepaspect calculation always resized with respect to the width. So if you moved the mouse strictly vertically with no change left/right, the mpv window would never change size since it just calculates with respect to the width that doesn't change. Fixing this is kind of weird and maybe someone should think of a better algorithm for preserving aspect ratio (we just multiply by the gcd basically), but whatever. You might naively try something like "resize with respect to what direction changes the most" at first, but this leads to very cludgy resizing since during a typical mouse dragging motion, it will flip constantly from "resize w/ respect to the width" and "resize w/ respect to the height". It "works" but it's really ugly and not worth it. The trick is to realize that we need to consider the resizing state as one continuous motion, choose a direction initially, stick to it throughout the entirety of the resize, and reset the relevant parameters after we finish the resize. This ensures the direction never unintuitively flips during a motion, but also allows for the strictly vertical case to still work. Might as well note it here in the commit, but mpv's resizing behavior technically violates xdg-shell. For the resizing event, "[t]he window geometry specified in the configure event is a maximum; the client cannot resize beyond it." Well, we do obviously go beyond the maximum in certain cases. For example consider resizing strictly horizontally. The width value increases from the compositor but not the height. Since mpv preserves aspect ratio by default, the height obviously must increase which will go over the prescribed bounds by the compositor. This happens before and after this commit, and I think everyone agrees is the desired behavior. With this commit, now vertical resizing works which violates xdg-shell in the same way. Before, it incidentally obeyed the protocol since it did not resize at all, but let's presume users expect the window to actually get bigger when they do a drag resize. *: https://wayland.app/protocols/xdg-shell#xdg_toplevel:enum:state:entry:resizing
2024-09-06 15:38:14 +00:00
int resizing_constraint;
int timeout_count;
int wakeup_pipe[2];
wayland: add support for xx-color-management-v4 for vo_dmabuf_wayland Although this protocol isn't official yet, several compositors are known to support it to some extent and this lets users actually view HDR with less hacks/workarounds. The actual protocol here is simply copy and pasted from the upstream fork* where these are developed. There is also icc profile support in the protocol, but this is omitted for now in favor of setting colorspaces and signalling hdr metadata. However for mpv, this only actually has any practical use with vo_dmabuf_wayland so this is the only VO that will make use of the protocol. When using vulkan, this is already handled via vulkan extensions by compositors and vo_gpu_next. So actually we don't want to use the wayland protocol in that case since it will just get in the way. The only known limitation on that front is driver support for hdr vulkan surfaces but as soon as that is available it should just work with no code changes. For opengl, hdr support there is a whole other mess with a lot of unknowns but simply using this protocol isn't good enough and would require changes elsewhere. vo_wlshm is currently too stupid to pick any format besides bgr0 or 0rgb, so any color management there is meaningless at this stage. So this means that only vo_dmabuf_wayland can actually use this protocol. But that's perfectly fine. Without this, vo_dmabuf_wayland has a very bad limitation in that it cannot communicate colorspaces at all and compositors have to guess. Using xx-color-management-v4 fixes this. For the other VOs, merely having the common protocol setup stuff in the common code does no harm and later if they get smarter, it's easy for them to use the stuff since it is written generically anyway. *: https://gitlab.freedesktop.org/swick/wayland-protocols/-/tree/color-xx/staging/color-management
2024-09-26 22:28:35 +00:00
/* color-management */
struct xx_color_manager_v4 *color_manager;
struct xx_color_management_surface_v4 *color_surface;
struct xx_image_description_v4 *image_description;
struct xx_image_description_creator_params_v4 *image_creator_params;
struct mp_image_params target_params;
bool supports_icc;
bool supports_parametric;
bool supports_primaries;
bool supports_tf_power;
bool supports_luminances;
bool supports_display_primaries;
bool unsupported_colorspace;
int primaries_map[PL_COLOR_PRIM_COUNT];
int transfer_map[PL_COLOR_TRC_COUNT];
/* content-type */
struct wp_content_type_manager_v1 *content_type_manager;
struct wp_content_type_v1 *content_type;
int current_content_type;
/* cursor-shape */
/* TODO: unvoid these if required wayland protocols is bumped to 1.32+ */
void *cursor_shape_manager;
/* fractional-scale */
struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
struct wp_fractional_scale_v1 *fractional_scale;
/* idle-inhibit */
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
/* linux-dmabuf */
struct wl_list tranche_list;
struct vo_wayland_tranche *current_tranche;
struct zwp_linux_dmabuf_v1 *dmabuf;
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback;
struct compositor_format *compositor_format_map;
uint32_t compositor_format_size;
/* presentation-time */
struct wp_presentation *presentation;
struct vo_wayland_feedback_pool *fback_pool;
struct mp_present *present;
wayland: workaround hidden state detection badness The wayland code uses a heuristic to determine whether or not the mpv window is hidden since the xdg-shell protocol does not provide a way for a client to directly know this. We don't render with the frame callback function for various, complicated reasons but the tl;dr is that it doesn't work well with mpv's core (maybe an essay should be written on this one day). Currently, the aforementioned heuristic considers a window hidden if we miss more frames in a row than the display's current refresh rate (completely arbitrary number). However, the wayland protocol does allow for the display's refresh rate to be 0 in certain cases (like a virtual output). This completely wrecks the heuristic and basically causes only every other frame to be rendered (real world example: nested sway sessions). Instead let's slightly redesign this mechanism to be a little smarter. For coming up with the vblank time (to predict when to timeout on the wait function), instead use the vsync interval calculated using presentation time. That is the most accurate measure available. If that number is not available/invalid, then we try to use the vsync interval predicted by the presentation event. If we still don't have that (i.e. no presentation time supported by the compositor), we can instead use the old way of using the expected vsync interval from the display's reported refresh rate. If somehow we still do not have a usable number, then just give up and makeup shit. Note that at this point we could technically ask the vo for the estimated vsync jitter, but that would involve locking/unlocking vo which sounds horrifying. Ideally, you never reach here. See https://github.com/swaywm/wlroots/issues/2566 for the actual target of this fix. wlroots uses presentation time so in practice we are mostly just using that calculated vsync interval number.
2021-04-16 19:55:15 +00:00
int64_t refresh_interval;
bool present_clock;
bool use_present;
/* single-pixel-buffer */
struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager;
/* xdg-decoration */
struct zxdg_decoration_manager_v1 *xdg_decoration_manager;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration;
int requested_decoration;
/* xdg-shell */
struct xdg_wm_base *wm_base;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
/* viewporter */
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct wp_viewport *cursor_viewport;
struct wp_viewport *osd_viewport;
struct wp_viewport *video_viewport;
/* Input */
struct wl_list seat_list;
struct xkb_context *xkb_context;
/* DND */
struct wl_data_device_manager *dnd_devman;
struct wl_data_offer *dnd_offer;
int dnd_action; // actually enum mp_dnd_action
char *dnd_mime_type;
int dnd_fd;
int dnd_mime_score;
/* Cursor */
struct wl_cursor_theme *cursor_theme;
struct wl_cursor *default_cursor;
struct wl_surface *cursor_surface;
bool cursor_visible;
int allocated_cursor_scale;
struct vo_wayland_seat *last_button_seat;
};
bool vo_wayland_check_visible(struct vo *vo);
bool vo_wayland_valid_format(struct vo_wayland_state *wl, uint32_t drm_format, uint64_t modifier);
bool vo_wayland_init(struct vo *vo);
bool vo_wayland_reconfig(struct vo *vo);
int vo_wayland_allocate_memfd(struct vo *vo, size_t size);
int vo_wayland_control(struct vo *vo, int *events, int request, void *arg);
wayland: add support for xx-color-management-v4 for vo_dmabuf_wayland Although this protocol isn't official yet, several compositors are known to support it to some extent and this lets users actually view HDR with less hacks/workarounds. The actual protocol here is simply copy and pasted from the upstream fork* where these are developed. There is also icc profile support in the protocol, but this is omitted for now in favor of setting colorspaces and signalling hdr metadata. However for mpv, this only actually has any practical use with vo_dmabuf_wayland so this is the only VO that will make use of the protocol. When using vulkan, this is already handled via vulkan extensions by compositors and vo_gpu_next. So actually we don't want to use the wayland protocol in that case since it will just get in the way. The only known limitation on that front is driver support for hdr vulkan surfaces but as soon as that is available it should just work with no code changes. For opengl, hdr support there is a whole other mess with a lot of unknowns but simply using this protocol isn't good enough and would require changes elsewhere. vo_wlshm is currently too stupid to pick any format besides bgr0 or 0rgb, so any color management there is meaningless at this stage. So this means that only vo_dmabuf_wayland can actually use this protocol. But that's perfectly fine. Without this, vo_dmabuf_wayland has a very bad limitation in that it cannot communicate colorspaces at all and compositors have to guess. Using xx-color-management-v4 fixes this. For the other VOs, merely having the common protocol setup stuff in the common code does no harm and later if they get smarter, it's easy for them to use the stuff since it is written generically anyway. *: https://gitlab.freedesktop.org/swick/wayland-protocols/-/tree/color-xx/staging/color-management
2024-09-26 22:28:35 +00:00
void vo_wayland_handle_color(struct vo_wayland_state *wl);
void vo_wayland_handle_scale(struct vo_wayland_state *wl);
void vo_wayland_set_opaque_region(struct vo_wayland_state *wl, bool alpha);
void vo_wayland_sync_swap(struct vo_wayland_state *wl);
void vo_wayland_uninit(struct vo *vo);
void vo_wayland_wait_events(struct vo *vo, int64_t until_time_ns);
wayland: shuffle around the render loop again Take two. f4e89dd went wrong by moving vo_wayland_wait_frame before start_frame was called. Whether or not this matters depends on the compositor, but some weird things can happen. Basically, it's a scheduling issue. vo_wayland_wait_frame queues all events and sends them to the server to process (with no blocking if presentation time is available). If mpv changes state while rendering (and this function is called before every frame is drawn), then that event also gets dispatched and sent to the compositor. This, in some cases, can cause some funny behavior because the next frame gets attached to the surface while the old buffer is getting released. It's safer to call this function after the swap already happens and well before mpv calls its next draw. There's no weird scheduling of events, and the compositor log is more normal. The second part of this is to fix some stuttering issues. This is mostly just conjecture, but probably what was happening was this thing called "composition". The easiest way to see this is to play a video on the default audio sync mode (probably easiest to see on a typical 23.976 video). Have that in a window and float it over firefox (floating windows are bloat on a tiling wm anyway). Then in firefox, do some short bursts of smooth scrolling (likely uses egl). Some stutter in video rendering could be observed, particularly in panning shots. Compositors are supposed to prevent tearing so what likely was happening was that the compositor was simply holding the buffer a wee bit longer to make sure it happened in sync with the smooth scrolling. Because the mpv code waits precisely on presentation time, the loop would timeout on occasion instead of receiving the frame callback. This would then lead to a skipped frame when rendering and thus causing stuttering. The fix is simple: just only count consecutive timeouts as not receiving frame callback. If a compositor holds the mpv buffer slightly longer to avoid tearing, then we will definitely receive frame callback on the next round of the render loop. This logic also appears to be sound for plasma (funfact: Plasma always returns frame callback even when the window is hidden. Not sure what's up with that, but luckily it doesn't matter to us.), so get rid of the goofy 1/vblank_time thing and just keep it a simple > 1 check.
2021-05-23 19:36:19 +00:00
void vo_wayland_wait_frame(struct vo_wayland_state *wl);
void vo_wayland_wakeup(struct vo *vo);
#endif /* MPLAYER_WAYLAND_COMMON_H */