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.
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.
--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
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.
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.
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>
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.
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.
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.
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
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.
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>
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
--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.
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.
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.
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.
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
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.
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.
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.
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.
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>
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
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
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>
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.
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