vf_d3d11vpp: create own device if the VO provides none - #18301
Conversation
|
The proper solution here is device derivation, which you need anyway to do proper interop. |
|
Good idea, so here is what it looks like implemented. It reads With that in place this filter derives from the VO's device instead of creating a standalone one. Based on Claude investigation, that turns out to fix a real cross-GPU bug rather than just being tidier. Forcing the VO onto the iGPU with So as it stands d3d11vpp runs the video processor on the discrete GPU while the VO renders on the integrated one. It happens to pick the right adapter whenever the discrete GPU enumerates first, which is why I did not catch this when I opened the PR. To be clear on the scope: this only changes which GPU the filter runs on. The copies are unchanged, frames still go through system memory. Being on the same adapter is a prerequisite for frame sharing, not the sharing itself. The standalone path stays as a fallback, since derivation needs a vulkan source to take the LUID from. Under Tested with 2x and 3x The derivation is a separate commit on top, so dropping it leaves the original standalone-device patch intact. The open question is sequencing, and that one is yours: would you rather the FFmpeg side land first and this wait on it, or keep the standalone fallback as the committed behaviour and switch over once it does? |
The filter took its D3D11 device from the video output, so it failed to initialize on any other output, most notably --gpu-api=vulkan, where mpv then dropped the video track entirely. RTX Video HDR and RTX Video Super Resolution were unreachable outside of --gpu-api=d3d11. The video processor does not need to run on the VO's device. Fall back to a standalone device from hwcontext_fns_d3d11 and advertise it with hwdec_devices_add(), which lets the generic upload and download filters move frames in and out of it. That costs an upload and a download per frame, so the filter warns, and it still prefers the VO's device when there is one. Every instance registers its own mp_hwdec_ctx even when it shares another instance's device. Filters are created before the old ones are destroyed, so an instance that merely borrowed a peer's device is left with nothing registered once the peer deregisters, and the next upload probe fails. Sharing the device instead of creating one per instance keeps a chain of several d3d11vpp filters working, because an input view cannot be created from another device's texture.
cd25cad to
4d17121
Compare
In short:
d3d11vpptakes its D3D11 device from the video output, so with--gpu-api=vulkanit cannot initialise at all and mpv drops the video track. RTX Video HDR and RTX Video Super Resolution are therefore unreachable unless you also switch renderer. This falls back to a standalone D3D11 device when the VO has none.Background
People enable RTX Video HDR, get nothing, and have no way to tell why. The prompt for this was someone asking exactly that: https://www.reddit.com/r/mpv/comments/1v6msec/do_i_need_to_change_config_to_enable_rtxhdr_in_mpv/
That is a single report, not evidence of wide demand, and
--gpu-api=d3d11remains the better answer on merit. But the current behaviour gives no signal at all: the filter fails to construct and the video track disappears, with nothing pointing at the video output as the cause. Either it should work or it should say why, and working turned out to be the smaller change.Problem
The lazy loader does run, but
hwdec_d3d11va's init starts withso with a Vulkan rendering abstraction it declines immediately, no D3D11 device is ever registered in
hwdec_devs, andvf_d3d11vpp_create()bails. The driver loads, refuses, and leaves the list empty, which is why the log looks like it should have worked.Fix
The video processor does not have to run on the VO's device. When the VO provides none, create a standalone one via
hwcontext_fns_d3d11, the same helper the copy hwdecs use, and advertise it withhwdec_devices_add()so the generic upload and download filters can move frames in and out of it.This costs an upload and a download per frame, so the filter warns, and it still prefers the VO's device whenever there is one.
--gpu-api=d3d11is unaffected.Two details that are not obvious:
mp_hwdec_ctx, even when sharing a device.mp_output_chain_update_filters()creates new filters before freeing the old ones, so an instance that merely borrowed a peer's device is left with nothing registered once that peer deregisters, and the next upload probe fails. Symptom was that any runtimevfchange silently disabled the filter.ID3D11VideoProcessorInputViewcannot be created from another device's texture, so a chain of twod3d11vppfilters breaks if they disagree on a device.Known limitations, documented in vf.rst
--hwdec=d3d11vastill cannot be used with a non-D3D11 VO, becauseinit_video_decoder()runs beforerecreate_video_filters(), so the device is registered too late for the decoder. It falls back to software decoding.d3d11_create_standalone()passes a NULL DXGI adapter, so on a hybrid system the device lands on whatever enumerates first. That is the discrete GPU on my machine, but it is not guaranteed.--hwdec=noand with every copy-back mode (auto-copy,nvdec-copy,d3d11va-copy, all verified), but--hwdec=autoselecting nvdec fails, because its CUDA frames cannot be uploaded into D3D11.Testing
Windows 11, RTX 5090, driver 610.74,
--vo=gpu-next.RTX Video HDR and RTX VSR both engage under
--gpu-api=vulkan, output is correctly taggedrgb/bt.2020/pq/full, and libplacebo picks anHDR10_ST2084swapchain. Pixel output matches the--gpu-api=d3d11reference at SSIM 1.000000 and PSNR 95 dB, against PSNR 28 dB for a no-filter control.Also covered: playlist advance, seeking, runtime
vfchanges, twod3d11vppfilters chained, already-HDR sources (correctly a no-op), and 60 filter create/destroy cycles with a threaded decoder (--vd-queue-enable=yes) showing no failures and no handle or memory growth against a--gpu-api=d3d11control. Confirmed the d3d11 path still takes the VO's device and stays zero-copy.Cost of the fallback, over 600 frames at 1080p: about +6.5 ms/frame CPU versus +3.5 ms/frame on the native d3d11 path, and roughly double the steady-state memory, 640 MB against 346 MB.
Not tested: non-NVIDIA hardware, so the Intel VSR path is unexercised, and hybrid systems where the integrated GPU enumerates first.
I do not know this codebase's conventions well, so if you would prefer a different approach, a narrower fix, or this split differently across commits, say so and I will rework it.
cc @kasper93
AI disclosure
Disclosure: this patch was written with AI assistance (Claude Code), which diagnosed the bug, wrote the change, and ran the testing described above on my machine. I have reviewed it and understand what it changes and why, I take responsibility for it, and review responses will be written by me. video/filter/vf_d3d11vpp.c is LGPLv2.1+ per its header; I submit the change under that licence.