6991 Commits

Author SHA1 Message Date
der richter 2d62ea664c mac/vulkan: improve Metal layer logging
instead of logging every change separately, log the the whole state of
the layer. this makes it easier to see possible problems, since the
state is visible at one place instead of being spread across several
lines in the log.
2026-10-17 13:58:07 +02:00
Kacper Michajłow dde0671072 vo_gpu_next: keep the inferred SDR black point relative to peak
The black point of an SDR hint is inferred from the peak known at that
point, before --target-peak and the reference white replace it. Derive
it again from the final peak, so that the assumed 1000:1 contrast holds
for the peak that is used.
2026-10-17 00:34:45 +02:00
Kacper Michajłow 1f7ad6d312 vo_gpu_next: map queued frames again when baked-in options change
--hdr-reference-white and the input side of --treat-srgb-as-power22 are
applied when a frame is mapped. Reset the queue when they change.

Fixes: 44ceaa6498
2026-10-17 00:34:45 +02:00
Kacper Michajłow 645d1f1d23 csputils: drop the equal energy white point adaptation for XYZ
DCDM X'Y'Z' is referenced to the RP 431-2 calibration white, whose code
values the XYZ to DCI-P3 matrix maps to RGB white. The equal energy white
of EG 432-1 only describes the encoding.
2026-10-16 19:56:44 +02:00
Kacper Michajłow 5f5c4e8ba5 vo_gpu: decode XYZ into the tagged primaries
Use the image's primaries as the target of the XYZ matrix, keep the equal
energy white point adaptation for DCDM only, and stop rewriting the image
params in pass_convert_yuv, which left XYZ in RGB formats undecoded after
the first render.
2026-10-16 19:56:44 +02:00
Lynne 25d8fa585b mp_image: support linear light XYZ
Treat RGB formats tagged with SMPTE ST 428-1 primaries as XYZ, keep
linear light XYZ linear and decode it into the tagged primaries, BT.2020
if unknown, and decode anything else as DCDM X'Y'Z' into DCI-P3. Tag XYZ
frames with ST 428-1 primaries when converting to AVFrame.

Co-authored-by: Kacper Michajłow <kasper93@gmail.com>
2026-10-16 19:56:44 +02:00
Link Mauve a2cd83c56d vo_drm: add support for RGB565
This image format is quite legacy, but uses half as much bandwidth as
the closest XRGB8888, at 16bpp instead of 32bpp, so it is useful to
support on the slowest/oldest display controllers.
2026-10-16 00:28:47 +02:00
rlauuzo b6cab8fa0c vo_gpu_next: only re-upload OSD textures when they change
update_overlays() uploaded every sub_bitmaps item to its texture on
every call, and draw_frame() calls it unconditionally, so an OSD that
was not changing got re-uploaded at the display refresh rate rather
than at the rate it actually changed.

vo_gpu already avoids this: gen_osd_cb() compares sub_bitmaps.change_id
against a cached copy and skips upload_osd() when they match.
osd_render() computes that change_id for both VOs, so vo_gpu_next had
the information and did not read it. Cache the id next to the texture
and skip pl_tex_upload() when it matches.

Also restrict pl_tex_recreate() to the cases where the size or format
has to change. The cache requires this, because pl_tex_recreate()
invalidates the texture even when it keeps it, and the cached id would
then describe contents that are no longer defined.
2026-10-16 00:26:53 +02:00
Kacper Michajłow 5757d69708 d3d11/context: resize buffers when DXGI leaves exclusive fullscreen
DXGI leaves exclusive fullscreen by itself during Present() when the window
loses the focus or a native menu covers it, and the next Present() fails
until the buffers are resized. Check the fullscreen state when Present()
doesn't return S_OK, resize the buffers if DXGI changed it, and enter
exclusive fullscreen again on focus events, which w32_common now also
sends when a menu loop ends.
2026-10-15 20:37:15 +02:00
Kacper Michajłow 2ddd0f027c select.lua: open context_menu.lua in d3d11 exclusive fullscreen
Load context_menu.lua when --d3d11-exclusive-fs is enabled and open it
instead of the native context menu. Native context menu cannot be
displayed over the exlusive window.

Fixes: #18181
2026-10-15 20:37:15 +02:00
Kacper Michajłow e9aac03ab8 vf_d3d11vpp: allocate the output after setting up the video processor
recreate_video_proc() sets the output format and colorspace for
nvidia-true-hdr. Allocate the output image and copy out_params after it,
so the first frame has correct params.
2026-10-15 16:32:40 +02:00
Kacper Michajłow 4255130de4 libmpv: add D3D11 render API backend
Adds a new render API backend that lets libmpv embedders render directly
into an application-owned ID3D11Texture2D.

The backend is selected with MPV_RENDER_API_TYPE_D3D11. The embedder
supplies the ID3D11Device via MPV_RENDER_PARAM_D3D11_INIT_PARAMS at
context creation, and the target texture via MPV_RENDER_PARAM_D3D11_FBO
on each mpv_render_context_render() call. Swapchain creation and
presentation stay entirely on the caller side.

Co-authored-by: dragonflylee <dragonflylee@outlook.com>
2026-10-15 15:36:37 +02:00
Kacper Michajłow b1b03bd347 d3d11: move the live object report to the VO context
The VO context owns its device. ra_d3d11 also runs on devices owned by
the libmpv API user, where the report lists their objects too.
2026-10-15 15:36:37 +02:00
Kacper Michajłow 0b3d2ab525 ra_d3d11: set the rasterizer state for every draw
The immediate context is shared with the API user of the libmpv render
API, who may change its state between frames.
2026-10-15 15:36:37 +02:00
Kacper Michajłow 5deaba46b2 vo_gpu: fix dither quantization for > 31 bit depths
Compute it as UINT32_MAX >> (32 - depth) instead of (1 << depth) - 1,
which overflowed int.
2026-10-15 15:36:37 +02:00
Vasily Khoruzhick 7c4f662c08 vo_gpu: opengl: use R8/RG8 formats on GLES 2.0 and GL 2.1
GLES 2.0 contexts with GL_EXT_texture_rg never used single- and
two-component R/RG textures, because the format table only listed
them for GL 3.0/ES 3.0, or for GL 2.1 with texture_rg + texture_float
+ FBOs all present (F_GL2F). Video planes were uploaded as LUMINANCE/
LUMINANCE_ALPHA instead, which needs a swizzle hack and mismatches
the .rg layout produced by dmabuf imports of DRM_FORMAT_R8/GR88
(NV12 via drm-prime), and forced dumb mode due to the have_texrg
check.

Add format classes for ES2 with GL_EXT_texture_rg (unsized internal
formats, as ES2 requires) and for GL 2.1 with ARB/EXT_texture_rg
alone, without the float/FBO requirements of F_GL2F. The entries are
placed before the legacy LUMINANCE ones so format lookups prefer
them; F_GL2RG is suppressed when F_GL2F is active to avoid duplicate
entries.
2026-10-14 18:29:41 +02:00
Vasily Khoruzhick 37eb6a0de0 vo_gpu: opengl: support GL_EXT_framebuffer_object
Some GL 2.1 drivers (e.g. Mesa lima) expose GL_EXT_framebuffer_object
but not GL_ARB_framebuffer_object, leaving MPGL_CAP_FB unset even
though FBOs are usable. Load the EXT entrypoints as an alternative
provider of MPGL_CAP_FB; mpv's FBO usage (Gen'd names, GL_FRAMEBUFFER
target, single color attachment, runtime completeness checks) is
within the subset EXT and ARB share. The section is placed before the
ARB/core one so the latter overwrites the function pointers whenever
it is available.

Querying attachment parameters of the default framebuffer is an
ARB/GL 3.0 addition, so skip that query in ra_gl_ctx_color_depth()
when only the EXT extension is present.
2026-10-14 18:29:41 +02:00
Kacper Michajłow b3c2fde411 context_angle: enable the D3D11 debug layer with --gpu-debug
Print the debug layer messages after every swap and report live objects
after the device is released.
2026-10-14 18:04:44 +02:00
Kacper Michajłow d802fab36a d3d11: don't map fence messages by ID
Windows SDK 10.0.22621 inserted a message ID at the end of the D3D11.1
range, which moved CREATE_FENCE and DESTROY_FENCE up by one. The debug
layer uses the numbering of its Windows version, so no fixed value is
right everywhere. Avoid hardcoding them.

Fence creation and destruction are now logged at debug level, a few
messages at init.
2026-10-14 18:04:44 +02:00
Kacper Michajłow 44be29945b d3d11: move debug layer message printing to d3d11_helpers 2026-10-14 18:04:44 +02:00
Kacper Michajłow b413ad0258 context_angle: fix D3D11 device leak
Release the immediate context, which holds a reference to the device.
2026-10-14 02:30:16 +02:00
wallpap 40c998a1ca hwdec_d3d11egl: release the FFmpeg hardware device reference
init() wraps the ANGLE D3D11 device in an AVBufferRef. Removing the
hwdec entry does not release that reference, so the device survives
render-context teardown.

Unref it before releasing the driver's own device reference, matching
the native D3D11 interop and the fix in 3447463008.
2026-10-14 02:30:16 +02:00
Kacper Michajłow 88eb9f2e73 vo_tct: take the cell aspect from the terminal
The cells were taken as twice as tall as wide. Fit the video to the cell
size the terminal reports instead, and keep 2:1 for a terminal that
reports none.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 197fa00448 vo_tct: place the image from row 1 and park the cursor below it
The indexing suppose to be from 1,1, not 0,0. So we were off by one and
clamped by the terminal to the edge, but that left empty row and column,
and also cleared status line.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 4ffe099190 vo_sixel: park the cursor on the bottom row after a frame
The canvas leaves the bottom row free, ensure that we write status line
there. Some terminal emulators does not move cursor after the sixel
image.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 5ce308b573 sws_utils,zimg: keep the scalers across frames with dynamic HDR metadata
mp_sws and mp_zimg compared the whole image parameters to decide whether
the scaler could be kept, so dynamic HDR metadata were invalidating the
scaler. This metadata is not used by SWS or ZIMG, except for peak
luminance by the later.

Fixes playback performance of HDR video with software scaling.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 30a31b77d1 terminal: redraw the terminal VOs when the terminal is resized
The terminal VOs only noticed a resize when they drew the next frame, so
a paused image kept its old size. The terminal input thread already
receives resizes, as a window buffer size event on Windows, which the
console reports with ENABLE_WINDOW_INPUT set, and as SIGWINCH on POSIX,
which now goes through the signal pipe like SIGTSTP. It passes them to a
callback the terminal swapchain registers, which wakes the VO thread. VO
then can react to size changes and redraw the image.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 8e566099cb vo_kitty: present frames through the terminal swapchain
Build the command of each frame in a buffer acquired from the terminal
swapchain and present it, so it is written while the next frame is
rendered.
2026-10-11 16:45:32 +02:00
Kacper Michajłow ad69233d93 vo_tct: present frames through the terminal swapchain
Build the whole frame, including the synchronized update sequences, in
a buffer acquired from the terminal swapchain and present it, so it is
written while the next frame is rendered.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 2c98919b66 vo_sixel: present frames through the terminal swapchain
The console write of a frame blocks until the terminal has consumed it,
which at large sizes takes as long as encoding the next frame. Present
each frame through the terminal swapchain instead, so the write overlaps
with scaling and encoding the next one.
2026-10-11 16:45:32 +02:00
Kacper Michajłow d8b06f94a1 video/out: add a swapchain for terminal VOs
The terminal VOs write each frame to the terminal from the VO thread,
and the write blocks until the terminal has taken the data, so nothing
is rendered meanwhile. The terminal swapchain writes from a thread of
its own, out of a ring of buffers. A VO acquires the next one, builds
the frame in it and presents it, and the swapchain queues it and writes
it under the terminal output lock, in order, with up to
--swapchain-depth frames in flight before acquiring waits.

Output that belongs with the next frame rather than in a write of its
own, such as clearing the screen after a reconfig, goes into a buffer
that the next acquire prepends.
2026-10-11 16:45:32 +02:00
Kacper Michajłow ee2e920963 vo_sixel: encode the canvas as slices on the thread pool
libsixel encodes on one thread, and a 3810x1020 canvas took about 150 ms
per frame. Split the canvas into slices that start on a cell row and
hold whole sixel bands, encode them on the thread pool with an output
and a dither each, and place every slice with its own cursor move.

The slices take their rows from the scaled image, and a packed copy of
the frame is only kept for the dynamic palette, whose histogram wants
the whole frame in one piece. Its median cut runs once, on the frame:
libsixel sorts the colours with a static variable in its comparator, so
the slices cannot run it at the same time.

A slice's dither is initialized from an image with one pixel per colour
in distinct 5-bit histogram buckets, which libsixel keeps as it is and
which gives the dither the colour cache of its fast lookup, and then
gets the frame's palette set.

A slice dithered on its own would not have a context, so each slice is
dithered together with twelve rows above it and one band below it, taken
from a copy since the diffusion writes into the image, with
sixel_dither_apply_palette(), and only its own rows of the indices are
encoded, through a second dither that takes the indices as they are. A
slice is at least three times as tall as the rows around it.
2026-10-11 16:45:32 +02:00
Kacper Michajłow ce2fe8d678 vo_sixel: size the canvas from the terminal's cells
--vo-sixel-rows and --vo-sixel-cols replaced the terminal's cell counts
while the canvas kept the terminal's pixel size, and --vo-sixel-top and
--vo-sixel-left kept it too, so the image ran past the bottom and
scrolled the terminal. Take the cell size from what the terminal
reports, and size the canvas in those cells from where the image
starts, or as the options say.
2026-10-11 16:45:32 +02:00
Kacper Michajłow ebf3c145f9 vo_{sixel,kitty}: draw the video into a frame the size of the canvas
Both VOs scaled the video into a frame of its own size, placed it with
the cursor and drew the OSD into it, so the OSD coordinates started at
the video while the mouse position starts at the terminal. Compose the
frame like the other software VOs. The size of the canvas, the video in
its rectangle and the OSD drawn with the margins.
2026-10-11 16:45:32 +02:00
Kacper Michajłow 12d630d819 terminal: serialize terminal output between the status line and the VOs
The status line is written from the main thread while vo_sixel, vo_kitty
and vo_tct write frames from the VO thread, so it could land inside a
frame. Add a lock that the status line holds for a write and the VOs for
a frame.
2026-10-11 16:45:32 +02:00
Dmitriy Gorokh f05190b414 vo_drm: fix hang when routine wakeups fill VT pipe
The DRM VT switcher shares a blocking pipe between VT signals and
routine video output wakeups. It consumes only one byte per poll, so
routine wakeups can fill the pipe during playback. On a running player,
the pipe held 65536 wakeup bytes and the main thread blocked in
anon_pipe_write.

Use a separate nonblocking wakeup pipe owned by the DRM backend, created
and cleaned up independently of VT switching, and write to it directly
from vo_drm_wakeup. Flush it with the bounded helper so continuous
wakeups cannot keep the VO thread draining. Keep the existing pipe for
VT release and acquire signals only.

The VO thread can skip wait_events while continuously rendering frames,
which would delay a terminal switch until playback pauses. Poll the VT
pipe from VOCTRL_CHECK_EVENTS as well. Leave routine wakeups pending
there: consuming one would let the following wait_events sleep through
a dispatch request that arrived after the queue was processed.
2026-10-11 13:32:36 +00:00
Lynne d94d095814 vulkan/context: remove shader object support
FFmpeg doesn't use it anymore, since Mesa doesn't cache shader objects.
2026-10-10 19:19:19 -07:00
Lynne c1a7e4b42c vulkan/context: add VK_KHR_maintenance11
This is one of the extensions and features that the libavutil Vulkan
hwcontext enables, so FFmpeg can make full use of the device we give it.

We have split it into a separate commit to make it easier to revert if
necessary. We've had reports of it causing performance regressions when it is
enabled on AMD Windows drivers.

See: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24816
2026-10-10 19:16:53 -07:00
Lynne a8ed387b49 vulkan/context: synchronize with lavu
Bring the extensions and features we request in line with what the libavutil
Vulkan hwcontext enables, so FFmpeg can make full use of the device we give it.

New extensions, along with their matching features:
* VK_KHR_workgroup_memory_explicit_layout
* VK_KHR_shader_maximal_reconvergence (1.3.276)
* VK_EXT_shader_replicated_composites (1.3.286)
* VK_EXT_zero_initialize_device_memory (1.4.315)
* VK_KHR_unified_image_layouts (1.4.317)
* VK_EXT_shader_long_vector (1.4.337)

The core 1.0-1.3 features now match lavu's device_features_copy_needed(),
minus the ones libplacebo already requests. Dynamic rendering is now
requested through VkPhysicalDeviceVulkan13Features, which libplacebo maps
back onto the extension structs for older devices.

Not mirrored from lavu:
* Video encode extensions, as we only decode.
* VK_KHR_internally_synchronized_queues. libplacebo creates the queues, and
  newer versions enable it on their own. Enabling the feature with a libplacebo
  that doesn't create its queues with the flag would make lavu request queues
  with a flag they were never created with.
* VK_EXT_physical_device_drm, which lavu only uses when creating its own device.
* VK_KHR_maintenance11, which we will handle separately due to reports of
  performance regressions.
2026-10-10 17:01:04 -07:00
Philip Langdale 917ac00964 vulkan/context: drop feature enabled by libplacebo
Our general principle is that if libplacebo requests a Vulkan extension or
feature that we want, we don't redundantly request it ourselves. Both mpv and
libplacebo have resynced their extension lists based on what ffmpeg wants,
and in the process, `shaderZeroInitializeWorkgroupMemory` ended up in both
lists. So we should remove it from mpv.

In the process of doing this audit, I noted that the video maintenance
extensions we request are also in libplacebo, but not in our minimum version
(7.360.1), so we should keep the explicit requests for now.
2026-10-10 17:01:04 -07:00
Philip Langdale 598cb2e117 vulkan: bump minimum required Vulkan headers to 1.4.309
Debian stable is on 1.4.309, and Ubuntu LTS is brand new this year, so we have
an opportunity to bump our minimum headers up.

This lets us drop the #ifdef checks that guard the extension entries and
feature structs for extensions older than that release, and reference
VK_KHR_video_decode_av1 through its define rather than as a string
literal.
2026-10-10 17:01:04 -07:00
der richter d52253adcf mac/input: rename open file function to handleDnd
rename this function to represent better what it does. dnd events should
be handled by this one. generic open file events should be handled by
the new function, with the same old name, added in a follow up commit.
2026-10-10 14:01:14 +02:00
llyyr b2c255c13e wayland: use configure bounds in window geometry
Pass configure_bounds to vo_calc_window_geometry instead of applying
them afterwards through apply_keepaspect.

Fixes: https://github.com/mpv-player/mpv/issues/18533
2026-10-09 16:02:30 +00:00
Julius Bairaktaris fd9265a905 context_angle: remove the D3D9 renderer
ANGLE removed its D3D9 backend along with
EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, so context_angle.c no longer builds
against current ANGLE headers.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
2026-10-09 13:01:09 +02:00
Dmitriy Gorokh 7b3a22a154 context_drm_egl: keep allow_modeset until the color commit is submitted
Changing colorspace adds the connector Colorspace and
HDR_OUTPUT_METADATA properties to the pending atomic request, and that
commit must carry DRM_MODE_ATOMIC_ALLOW_MODESET: the driver rejects it
with EINVAL otherwise and the colorspace is never signalled.

allow_modeset was assigned from vo_drm_set_color() on every set_color()
call, so a repeated call that reported no change cleared the flag while
the request holding those properties was still pending. Only ever set it
on a change, and clear it in queue_flip() once that request is
submitted. A failed commit leaves it set for the retry, mirroring
waiting_for_flip.

Fixes: baad29c1f4
2026-10-09 11:54:49 +02:00
Dmitriy Gorokh 1eb51ef98e context_drm_egl: handle set_color() with a NULL hint
vo_gpu_next calls set_color() with a NULL hint when
--target-colorspace-hint is disabled. The DRM/EGL callback dereferenced
params unconditionally, which crashes on the first frame of playback.
Treat an absent hint as SDR and reset the connector colorimetry, the
same as the Wayland backends already do for NULL.

The hint is passed on every frame in that mode, but a repeated SDR hint
is cheap: vo_drm_set_color() returns early when nothing changed.
Ignoring the call would also leave the connector on BT2020 when profiles
switch colorspace, e.g. an [HDR] profile that enables
--target-colorspace-hint followed by SDR playback.

Fixes: baad29c1f4
2026-10-09 11:54:49 +02:00
Markus Volk 51ab8044cb hwdec_drmprime_overlay: make the framebuffer the whole frame
The framebuffer for the video plane was created with the size of the
source rect, while SRC_X and SRC_Y place that rect inside the frame.
When the source rect does not start at 0,0, as with panscan or
video-crop, it reaches past the framebuffer. The DRM core rejects such
a plane state with ENOSPC (drm_atomic_plane_check(), and
drm_framebuffer_check_src_coords() for the SetPlane path), so the
commit fails and the video plane stays dark.

Create the framebuffer with the size of the decoded frame and let the
SRC_* properties select the shown part.

Signed-off-by: Markus Volk <f_l_k@t-online.de>
2026-10-07 16:38:46 +02:00
Kacper Michajłow 3186d369f9 vo_gpu_next: defer the queue reset until a new frame arrives
VOCTRL_RESET resets the frame queue when the first frame that was not
pushed before arrives. Redraws of the frames from before the seek keep
the queue as it is instead of resetting it and pushing those frames
again, where they stayed between the frames of the next file and were
shown with interpolation.
2026-09-30 00:34:43 +02:00
Kacper Michajłow a1f50f2c38 video/gpu/lcms: initialize the unused component of the 3DLUT
lcms does not write the extra channel of the RGBA output, so the 4th
component of every texel was uninitialized memory that went to the GPU
and into the cache file. Set it to zero.

Fixes: 62f0677614
2026-09-30 00:33:35 +02:00
Kacper Michajłow 72d43dc9c9 vo_gpu: fill the padding of the scaler LUT
Rows of 6 weights are padded to two RGBA texels and the padding was left
uninitialized.

Fixes: #18540
Fixes: 8cf5799ab1
2026-09-30 00:33:35 +02:00