Repository navigation
Releases: HumbleUser33/MPCVR-Plus
Release list
MPCVR-Plus 2.2
MPCVR-Plus 2.2
Since 2.1 (f9ed450).
Fixed
- DLSS SR: no more dark shadow after a cut. After a cut from a dark shot to a bright one, the bright parts of the first two or three pictures came out darkened, and a flash did the same. The cut is now recognised on the GPU and DLSS SR starts the new shot afresh, for 0.06 ms a picture at 1080p. DLSS 5 NR never had the trail.
- The display peak brightness (HDR tab) accepts 100 nits, as its message says.
Improved
- The settings page says what each option does. Every label, list entry and tooltip is rewritten to say what the option does, when it applies and what it needs; the measurements are in the manual. Some options have clearer names: Video Super Resolution (was Request Super Resolution), Detail and Skin detail (Local struct., Skin struct.), Optical Flow resolution as 1/4, 1/3, 1/2, Full or Auto (Optical Flow Resolution Divider), HDR output (HDR10/DV), Use this method instead of the video processor's chroma upsampling (Replace VP chroma upsampling). Saved settings and presets are unchanged.
- Auto mask explained. It is the network's own detection of skin (faces, hands): with it, Skin detail applies on skin and Detail everywhere else; without it, Skin detail has no effect. Keep it on.
- The statistics (Ctrl+J) follow the picture. Source, then each step of the pipeline in the order it runs, each with its own GPU time and a total against the duration of a frame, then the timing: render ahead, the CPU, the swap chain, the offsets and the frames.
- DLSS SR's time is on the Scaling line, and an mpv prescaler's on the step it serves.
- The video processor's own time is now measured, Super Resolution and RTX Video HDR included.
- The wait for the screen refresh is shown apart from Present.
- Every figure keeps its width, so the lines no longer jump while the film plays.
- Tools that read the statistics as text (
Flt_GetString("statsText")) see the new layout.
- The manual goes through the settings tab by tab, and has a section on reading the statistics.
Known
- A picture taken for a cut that is not one, such as a flash or a flickering light, loses DLSS SR's history: that picture is a little softer.
- A film loses two to five pictures when it starts, after a seek and after a pause.
x64 and Win32, zero warnings.
MPCVR-Plus 2.1
MPCVR-Plus 2.1
Since 2.0 (19c5a62).
New
- Working size for DLSS 5 NR (DLSS 5 NR tab, 50 to 100 %): the network runs on a reduced picture and its change is carried back at full size, so a 4K film plays on an RTX 4060 (55 % for 3840x2160, 75 % for 3840x1600).
- Optical Flow Resolution Divider (4, 3, 2, Full or Auto): the size at which the stabilizer measures motion. Auto, the default, keeps the previous behaviour.
- Video delay (Presentation tab, -200 to +500 ms): delays the picture when the sound arrives late, for example through an amplifier behind the TV. It is not part of the presets.
- Ten presets instead of eight.
Improved
- DLSS SR: still backgrounds no longer shimmer on film. The slight movement of the whole film picture is now followed precisely, and moving pictures gain 1 to 2 dB.
- DLSS 5 NR always receives motion vectors from the stabilizer's Optical Flow: steadier, moving objects included, and with a little more of its effect. Lower Intensity if it is too strong.
Removed
- "Send the motion vectors to DLSS": the vectors are now always sent while the stabilizer is on.
- The shader motion detector and "Disable temporal history", which did no better than Optical Flow and the network's own history.
Known
- A film loses two to five pictures when it starts, after a seek and after a pause.
x64 and Win32, zero warnings.
MPCVR-Plus 2.0
MPCVR-Plus 2.0
A big update for stability, frame pacing and performance. Since 1.9.1 (658071e).
Frame pacing
- A refresh chosen for every picture: with Render ahead on, each picture is presented for the refresh nearest its own time, which ends the picture shown 80 ms late, the sync offset that changed at every start and the stutter after a seek or a change of sound track or subtitles.
- A chain too heavy for the film's rate no longer freezes the picture: a picture that took most of a frame to draw is shown and the next one is left out before it is drawn, so the film plays what it can and stays with its sound.
- The statistics say how each picture was timed:
Frame syncnames the method, andOn screencounts the pictures repeated, dropped and late.
Performance
- An SDR picture is presented through three buffers instead of two, so a heavy chain no longer waits for the next refresh before every picture: 19 ms a picture with DLSS 5 NR at 25 Hz, where it took 39.
- RTX Video Super Resolution no longer runs before DLSS 5 NR on a picture it has nothing to enlarge, which cost 16 ms a picture at 1080p.
Stability
- A crash of DLSS Super Resolution when a second film was opened in the same player session is fixed.
- DLSS 5 NR comes back by itself two seconds after an evaluation the GPU did not answer, and again after a seek, instead of staying off for the rest of the film.
- DLSS 5 NR with Apply after upscaling stays on after leaving fullscreen and coming back.
- DLSS 5 NR and DLSS SR load the NGX runtime of the installed driver, where DLSS 5 NR took the oldest one left in the driver store.
- DLSS 5 NR lets go of its textures when it is switched off, where they stayed allocated.
Changed
- "Use the video processor for resizing" now holds with DLSS 5 NR: the processor enlarges what the network leaves, with RTX Video Super Resolution if it is requested, and the Upscaling and Downscaling lists grey as the box says.
- The tooltip of Request Super Resolution says what it costs after DLSS 5 NR: the driver only takes 4:2:0, so colour fidelity drops by 2.2 to 3.1 dB, and Disable keeps the colour whole.
- The statistics name what really enlarged the picture, and give the processor's resize after DLSS 5 NR a time of its own.
Diagnostics
- A pacing trace: with
MPCVR_PACING_TRACE=<file>in the player's environment the renderer writes a line a picture, andpacing_report.pysays on which refresh each one was shown and whether DLSS ran on it.
Known
- A film loses two to five pictures when it starts, after a seek and after a pause.
- DLSS 5 NR followed by RTX Video Super Resolution to 4K is at the limit of an RTX 4060 at 25 fps, and Apply after upscaling at 4K is beyond it: pictures are then left out, and the sound stays in step.
x64 and Win32, zero warnings.
MPCVR-Plus 1.9.1
MPCVR-Plus 1.9.1
Since 1.9 (6294e94).
New
- Presets tab: eight sets of settings, each with a name, saved and loaded from the options.
- Preset keys: each preset can be recalled during playback by a key or a combination (Ctrl, Shift, Alt with F1-F12, digits, letters, numeric pad and more), without opening the options.
- Preset name on screen: the recalled preset's name is shown for two seconds, large and on a dark box, playing or paused.
On screenline in the statistics: when the picture is due on the screen and how many pictures are waiting, next to the Sync offset.
Fixed
- Mouse pointer stuck over the film in MPC-HC after changing HDR10/DV or the swap effect in fullscreen (a fault upstream has too).
- Film running a refresh or more late at 24 fps on 24 Hz and 25 on 25: the present queue is bounded and one picture is left out to catch up, shown as
caught up N. - Render ahead no longer holds pictures for a prescaler that is loaded and has nothing to do, as on a film shown at its own size.
- The lighter filter for small enlargements was not saved by the 32-bit build.
Known
- On some screens at 25 Hz a rare short stutter can still happen at the start of playback; it settles within seconds.
x64 and Win32, zero warnings.
MPCVR-Plus 1.9
MPCVR-Plus 1.9
Since 1.8 (865a7c4). Measured with the tools in tools/dlssnr_probe, on an RTX 3050.
Fixed: the Upscaling network ran on pictures it had nothing to enlarge
1.8 has this bug; please replace it. With FSRCNNX, RAVU-zoom or ArtCNN chosen, the network
ran on a film shown at its own size — 4K on a 4K screen — and on a film being reduced. In both
it doubled the picture for the resize shaders to bring straight back down: its whole cost, and
a worse picture than leaving it alone. The Scaling line did not name it; the prescale line gave
it away.
It came from lifting mpv's 1.3x threshold in 1.8, which lifted the direction along with it.
An enlarger now runs only where there is something to enlarge:
| picture | what runs |
|---|---|
| shown at its own size | nothing |
| grows on one axis or both, however little | the Upscaling method you chose |
| shrinks | the Downscaling method |
| grows on one axis, shrinks on the other | one classic kernel an axis |
One axis is enough: a PAL film is 720x576 shown at 768x576, enlarged in width alone, and it
gets the chosen method.
A lighter filter for small enlargements
That rule makes one case expensive. A 4K film cropped to 3838 across on a 3840 screen is an
enlargement, by a twentieth of one per cent, and a network doubles its source whatever the
target is: at 3836x2160 to 3840x2160, FSRCNNX 16 AR worked at 7672x4320 for about a second a
frame and skipped half of them.
Use a lighter filter for small enlargements, under Upscaling, with the same list of
filters. Ticked, that list is used whenever the picture grows by less than 5 % on both axes,
and the method above it everywhere else. In the same place RAVU-zoom took 21.4 ms and skipped
nothing, and Jinc2m cost nothing worth measuring. It goes by the ratio and not by the size, so
it holds on any screen. Off by default; the statistics name the method really in use.
The Downscaling list, ranked by measurement
Each downscaler was asked the two questions it exists to answer, on the shaders that ship: how
much of the detail that still fits does it keep, and how much of the detail that no longer
fits does it let fold back as aliasing — which is what crawls when the picture moves. The test
pictures are sinusoids whose correct reduction is known in closed form, so no reference
resizer is involved. 4K reduced by two; error is the root mean square of all six.
| kept 0.125 | kept 0.250 | kept 0.375 | folded 0.60 | folded 0.75 | folded 0.90 | halo | error | |
|---|---|---|---|---|---|---|---|---|
| Lanczos | 1.003 | 1.010 | 0.881 | 0.178 | 0.010 | 0.004 | 0.045 | 0.087 |
| Bicubic sharp | 1.063 | 1.118 | 0.936 | 0.136 | 0.118 | 0.044 | 0.075 | 0.097 |
| Spline36 | 1.000 | 0.993 | 0.856 | 0.200 | 0.007 | 0.004 | 0.040 | 0.101 |
| Bicubic | 0.995 | 0.941 | 0.772 | 0.276 | 0.058 | 0.004 | 0.025 | 0.150 |
| Bilinear | 0.962 | 0.853 | 0.691 | 0.346 | 0.146 | 0.024 | 0.000 | 0.208 |
| Hamming (default) | 0.968 | 0.880 | 0.748 | 0.467 | 0.303 | 0.204 | 0.000 | 0.268 |
| Box | 0.981 | 0.924 | 0.831 | 0.588 | 0.382 | 0.153 | 0.000 | 0.303 |
The list is in that order now. The top three are within fifteen per cent of each other and
differ in taste: Spline36 is the flattest and rings least, Bicubic sharp folds least and adds
contrast the source did not have, Lanczos sits between them. The four below are not close.
This corrects 1.8, which called Spline36 the best from the shape of the kernels alone; that
reading did not count what each lets fold back.
Hamming, the default, is sixth of seven. It is upstream's default and is left where it is;
if you reduce often, pick one of the top three.
Your saved choice is kept: the list used to save the position it sat on and now carries its
value, which is what let it be sorted.
Also
dlssnr_harness --tdownportchecks that the downscaling shaders that ship are the kernels
they are written from: the compiled objects the filter embeds, on the GPU, against the same
convolution in double on the CPU. All seven agree to about one step of half float.dlssnr_harness --tdownscaleis the ranking above;playback_test --small Nexercises the
lighter filter.
x64 and Win32, zero warnings.
MPCVR-Plus 1.8
MPCVR-Plus 1.8
Since 1.7 (0115c41). Two things about scaling, both of them cases where the page named one
method and another one ran.
The upscaler named in the list is the upscaler that runs
A film at 1920x1038 shown at 2496x1349 was enlarged by Catmull-Rom while the list went on
saying FSRCNNX 16 AR, and the chosen method only took over at 2497x1350.
Every one of these networks carries mpv's //!WHEN clause, which asks whether it is worth
starting at the size the window happens to want: FSRCNNX and ArtCNN want 1.3x, RAVU-zoom
wants the picture to be growing at all. 1920 x 1.3 is 2496 — the reported number exactly.
Below it the network stood aside and the fallback took the picture, and that fallback is
Catmull-Rom for every one of them.
The question is now put at the network's own scale rather than at the window's, so the method
named in the list is the method that runs, at any enlargement however small. Nothing
structural is bypassed: both conditions these shaders carry are "is it worth it", never "can
it". At the reported sizes, per frame on an RTX 3050 — FSRCNNX 8 10.0 ms, RAVU-zoom 6.6,
ArtCNN 19.5, FSRCNNX 16 AR 22.1. It costs the same at every ratio, because the work is the
same: the network doubles the source whatever the target is.
The Downscaling method reduces at every ratio
Use the "Upscaling" method to reduce the frame to 50% is removed. A 2x network asked to
reduce has to double the source first and bring the picture down from that: on a 4K film in a
1080p window that had FSRCNNX 16 working at 7680x4320 for 93.4 ms a frame, with the sync
offset out to +5 s and 18 frames late. The option could not be made to mean what it says
without being unusable exactly where it was meant to help.
So the Downscaling list now reduces at every ratio, which is the one thing it can be relied
on to say. Nothing is lost for the classic kernels, which is what that option really chose
between.
Spline36 for downscaling
New in the Downscaling list: the piecewise cubic of Avisynth's Spline36Resize, which mpv
carries as its spline36 kernel. It sits at the end of the list rather than in quality order,
because that list saves the position it is sitting on.
A downscaler is judged on how much of what it may keep it keeps, and how much of what it must
throw away folds back as aliasing. Frequency response in cycles per output pixel, passband to
0.5, where 1.000 is "kept whole" and anything above it is overshoot — ringing, not detail:
| kernel | 0.125 | 0.250 | 0.400 | worst above 0.5 |
|---|---|---|---|---|
| Box | 0.974 | 0.900 | 0.757 | 0.624 |
| Bilinear | 0.950 | 0.811 | 0.573 | 0.389 |
| Hamming (default) | 0.969 | 0.881 | 0.720 | 0.582 |
| Bicubic | 0.996 | 0.939 | 0.716 | 0.470 |
| Bicubic sharp | 1.067 | 1.125 | 0.861 | 0.453 |
| Lanczos | 1.004 | 1.011 | 0.823 | 0.466 |
| Spline36 | 1.000 | 0.995 | 0.792 | 0.452 |
Spline36 is the only one flat where it matters. It does not soften the way Hamming and Bicubic
do, it does not invent contrast the way Bicubic sharp and Lanczos do, and it still rejects more
of what folds back than either. Bilinear rejects most of all and gives away a fifth of the
detail at a quarter of Nyquist for it.
Said plainly: those numbers are computed from the kernel definitions by numeric integration,
not measured through the shipped shader. The shaders are a direct transcription of them. What
is measured is that it loads and runs — 2560x1440 -> 1920x1080 Spline36, nothing skipped.
Hamming stays the default, because it is upstream's.
Also
playback_test --scalers --size WxH --window WxHsweeps every upscaler at a ratio you pick,
which is how the 1.3 threshold was caught.--tmpvportstill passes, 0 checks failed: the gate moved, the arithmetic did not.
x64 and Win32, zero warnings.
MPCVR-Plus 1.7
MPCVR-Plus 1.7
Since 1.6 (764c4d1). Measured with the tools in tools/dlssnr_probe, on an RTX 3050.
The fork is now MPCVR-Plus
DLSS 5 was the first thing this fork added and it stopped being the main one a while ago —
the upscalers, the chroma pre-pass, the sharpening and render ahead all stand on their own.
So the repository is MPCVR-Plus.
GitHub redirects the old address, so nothing you have bookmarked or cloned breaks. The branch
is unchanged, so the filter still reports itself as 0.10.8.xxxx.dlss5.
One settings page, seven tabs
The two pages — Settings and DLSS — are now one, laid out in the order the picture travels:
Source, Chroma, Scaling, Detail, DLSS 5 NR, HDR, Presentation. Things that belong together
are together at last: sharpening sits with detail instead of among the presentation options,
and DLSS Super Resolution sits with the other enlargers instead of on a page of its own.
Tabs across the top rather than a list down the side, so each tab spreads across the width:
720x371 pixels where the old page was 720x562. Drawn with the system's own group boxes and
check boxes, so a player that themes its dialogs themes this one too.
Upstream's page is left in the tree untouched and simply not listed, so a merge from upstream
still costs nothing.
Every option has a tooltip, and a greyed option shows its own — which is the one worth
reading, since it says why the option is greyed.
Greying that follows the settings, not the film
Request Super Resolution could not be brought back by the box it is supposed to answer. The
page asked the renderer what the video processor was doing with the picture at hand, and a 4K
film on a 4K screen leaves it nothing to resize, so the line greyed whatever the chroma
pre-pass said. A Dolby Vision film did the same for another reason.
These are settings for every film there will ever be, so the film playing now no longer gets a
vote — with one exception, which is spelled out on the page:
Dolby Vision carries its own colour and its own reshaping, which a fixed-function video
processor cannot convert, so the renderer hands the whole chain to the shaders and the
processor is not in it at all. RTX Video Super Resolution lives inside that processor and has
nowhere to run. Use the video processor for resizing now greys while that is playing, with a
line saying why, and the chroma and scaling lists go live, because there the shaders really are
doing all of it.
There is a way round it for a file carrying an HDR10 layer under the Dolby Vision one — profile
8.1, AV1 profile 10.1, which is most of what is released: leaving Prefer Dolby Vision over PQ
and HLG off plays that layer, keeps the processor, and Super Resolution with it.
DLAA: DLSS SR with nothing to enlarge
DLSS only enlarged, so a film already at the screen's size never reached it. Also run when no
enlarging is needed (DLAA) lets it run there too, rebuilding the picture without changing its
scale — the mode games call DLAA. The statistics line says
DLSS SR : 3840x2160->3840x2160 DLAA/M.
It is a whole DLSS pass at the output size, which is the most expensive place to put one. Per
frame on an RTX 3050:
| picture | DLSS SR | optical flow | fits a 24 fps frame (41.7 ms)? |
|---|---|---|---|
| 1280x720 | 12.6 ms | 3.3 ms | yes |
| 1920x1080 | 14.0 ms | 2.7 ms | yes |
| 3840x2160 | 70.0 ms | 4.5 ms | no |
So on that card it is for 1080p and below, and native 4K needs a high-end RTX. Render ahead
cannot rescue it: it hides latency, not a pass longer than a frame. Watch skipped and the
sync offset in the statistics box.
Fixes
- No tooltip ever appeared where comctl32 v6 was not active for the host process:
TTM_ADDTOOLwas handed a structure size it refuses outright, and refuses in silence. - Ticking DLSS 5 NR could untick itself a moment later: the half-second refresh compared the
renderer against the page's own copy, so a tick not yet applied looked like the toggle key
turning it off. - The Apply button no longer lights while the page is filling itself in.
x64 and Win32, zero warnings.
MpcVideoRenderer-DLSS5-1.6
MPCVR-DLSS5 1.6
Since 1.5 (726377e). Everything below was measured with the tools in tools/dlssnr_probe,
on an RTX 3050, and the numbers are theirs.
Sharpening
The filter could enlarge finely and could not sharpen at all. A film already at the screen's
size, or enlarged by the hardware video processor, had no way to gain definition here. There is
now a Sharpening list on the Settings page with two methods and five levels, run after the
resize so it reaches a film at any size. Subtitles are drawn after it and are never sharpened.
Adaptive-Sharpen is bacondither's mpv shader (2021-10-17, BSD 2-clause) ported to HLSL: it
weighs each of 25 neighbours by how active its own area is, sharpens blurred edges most and
steep ones least, and limits the result with a tanh rather than a hard clip.
Unsharp + Clamp is a 3x3 high pass pulled back towards the range the four neighbours really
cover — the principle of AviSynth's LimitedSharpenFaster, and the same clamp the anti-ringing
upscalers already use here.
What each one is worth
Ten 4K frames halved, degraded the way a source is, enlarged again, sharpened, and scored
against a reference none of them saw (dlssnr_harness --tsharpen). Every method is read at
the strength that brings it to the same edge gradient: comparing each at its own best
compares six different amounts of sharpening and says nothing about the sharpeners. halo is
the mean overshoot past the range the reference really covers along its edges, x1000; grain
is the fine detail left in flat areas, output over reference.
| Method | psnr-d | halo | grain | grain source | compressed source | time, 4K |
|---|---|---|---|---|---|---|
| no sharpening | 43.93 | 0.048 | 3.698 | 39.53 | 37.97 | — |
| Adaptive-Sharpen | 44.93 | 0.076 | 3.597 | 39.37 | 37.92 | 3.05 ms |
| Unsharp + Clamp | 44.91 | 0.051 | 3.926 | 39.15 | 37.81 | 0.57 ms |
| unsharp, no clamp | 44.94 | 0.098 | 4.705 | 39.10 | 37.79 | 0.57 ms |
| CAS | 44.86 | 0.055 | 3.842 | 38.64 | 37.62 | 0.64 ms |
| CAS + the same clamp | 44.75 | 0.052 | 3.824 | 38.77 | 37.64 | 0.83 ms |
| RCAS (FSR 1) | 44.73 | 0.055 | 3.901 | 38.63 | 37.62 | 0.51 ms |
The two that ship are the two ends of one trade. Adaptive-Sharpen is the only one that does
not amplify grain — on a clean master it leaves less fine detail in flat areas than doing
nothing — and on the two sources that matter, grain and compression, it costs almost nothing:
0.16 dB and 0.05 dB, where the next best costs 0.38 and 0.16. It is also five times the price
and rings half again as much on a clean picture. Unsharp + Clamp has the lowest ringing of
all, at the level of the unsharpened picture itself, and is second everywhere for a fifth of
the time.
Sharpening the colour as well as the luma was measured and dropped: it moves the result by less
than 0.3 dB and the sign turns with the source. Both passes move the luma only, by adding one
number to R, G and B alike, which leaves B−Y and R−Y exactly as they were.
The five levels
A level means the same amount of sharpening whichever method is chosen. The two are not on the
same scale, and neither is on the scale of the comparison above — a picture halved and enlarged
again is far softer than anything this renderer produces. The levels are calibrated through the
filter itself, on a 1080p film enlarged to 3200x1334, as the gain in mean gradient each one
really buys:
| Level | gain in detail | Adaptive-Sharpen | Unsharp + Clamp |
|---|---|---|---|
| 1 | +4 % | 0.22 | 0.45 |
| 2 | +8 % | 0.33 | 0.62 |
| 3 (default) | +13 % | 0.46 | 0.83 |
| 4 | +20 % | 0.68 | 1.17 |
| 5 | +28 % | 0.99 | 1.49 |
Measured back through the filter, level 1 gives +3.7 % and +2.8 %, level 3 +13.2 % and +13.0 %,
level 5 +28.3 % and +27.9 %. Level 3 is the +13 the quality measurements settle on; 4 and 5 are
past it, for a taste rather than for fidelity.
Super Resolution asked the same way in both places
Ticking Use for resizing did not turn RTX Video Super Resolution on, while picking the same
value again from the list did. Two code paths were asking different questions:
InitializeD3D11VP refused the extension unless the picture was on its way to an 8-bit target
or RTX Video HDR was making the HDR, while Configure() asked without that test. So every HDR
film and every 10-bit source got it only by way of the list.
The refusal cost something real: on a PQ BT.2020 source in P010 the driver changes the picture
by 3.928 when the extension is enabled, against 3.903 on the same frame in SDR — it does the
work there as well as anywhere. Both places ask the same question now, and it is that one.
A picture that stops while the sound plays on
Reported on a 24 Hz TV: a very fast pause and play, and the picture stops while everything else
carries on. It took a bench that drives MPC-HC itself to see it — the renderer's own graph never
shows it — and the stacks of the frozen player to place it.
The fault turned out to be the audio renderer's clock, not this one. Every picture is
scheduled against the reference clock the graph gets from one of its filters; with one
third-party audio renderer that clock stops while the sound goes on playing, so each picture
looks one frame further into the future than the last and playback slows to a crawl. Swapped
for MPC-HC's own audio renderer the incident does not happen at all, and the sync offset stops
wandering — it sits between −19 and −5 ms instead of reaching +30.
The renderer is no longer dragged down with it:
-
a picture's turn is waited for with a bound. A turn cancelled after it was given used to leave
the streaming thread waiting for ever, ten seconds at a time; it is now taken instead. -
a clock caught not moving between two such turns is treated as stopped, and the pictures are
paced by the stream's own frame duration until a turn arrives again. Render ahead's hold is
skipped meanwhile, since the pacing is already the renderer's. -
the statistics name the clock, and say when it has stopped:
Frames : 101, skipped: 0/0, failed: 0, turns late: 27 (turn +254 ms, clock +636 ms, base +0 ms) Clock : MPC Audio Rendererturns lateandturns loststay at zero on a clock that keeps time. When they move, the
first thing to try is another audio renderer. The manual has the detail.
A refused swap-chain resize is also answered now instead of ignored: a flip model swap chain
that does not match its window presents every picture without any of them reaching the screen,
which from inside the renderer looks like nothing at all. It is rebuilt, and the statistics
count how often that was needed.
None of it costs anything while the clock runs: sync offset −6.5 ms with render ahead and −7.0
without, no pictures skipped, state changes instant, across the whole playback battery.
Also
- the bench can drive the installed MPC-HC, tap the space bar twice with a chosen gap, and read
the screen by duplicating the desktop — the only way to see what a flip model swap chain
really put there. It checks that it can tell a stopped picture from a running one before it
claims anything. - a frozen player's threads now say what they are waiting for, in their own descriptions, which
a report reads across processes.
x64 and Win32, zero warnings.
MpcVideoRenderer-DLSS5-1.5
MPCVR-DLSS5 1.5
Since 1.45. This release fixes what 1.45 broke, corrects what it told you, and puts the fork
back on upstream's own behaviour wherever it had quietly drifted off it. It also carries
upstream's development up to 0.10.8. Everything below was measured on an RTX 3050 with the
tools in tools/dlssnr_probe, and the numbers are theirs.
RTX Video HDR and RTX Video Super Resolution work together on a 10-bit source
The stock renderer does both at once on a 10-bit film. 1.45 did not, and its colours were
flatter. Both were the same fault, and it was ours.
Upstream keeps the video processor out of PQ passthrough unless the source is 8-bit.
Passthrough tells the processor that its input and its output are PQ BT.2020, which only holds
once the driver's extension has taken the picture over; where it has not, the processor reads
an SDR picture as PQ, and that is the flat colour. Upstream's commit that fixed this says so
in its title -- "RTX Video HDR now works with 10-bit SDR video too" -- and 1.45 removed the
line it added.
Measured on the current driver, how much enabling RTX Video HDR changes the picture, in 8-bit
levels:
| Input | processor in PQ passthrough | processor left in G22/P709 |
|---|---|---|
| NV12 (4:2:0, 8-bit) | 37.1 | 36.9 |
| P010 (4:2:0, 10-bit) | 0.000 | 36.7 |
| AYUV (4:4:4, 8-bit) | 37.9 | 37.7 |
| Y410 (4:4:4, 10-bit) | 37.7 | 37.5 |
The depth was never the reason. The line is upstream's again, word for word.
End to end on a 10-bit AV1 film, decoded in D3D11 and arriving as P010 1920x800 into a
3200x1334 window, against a build of upstream's own current master driven with the same
settings:
| every option off | byte-identical to upstream (99 dB) |
| Super Resolution alone | byte-identical to upstream; upstream leaves it off on a 10-bit source unless RTX Video HDR is on, and so do we |
| RTX Video HDR | the displayed picture moves 19.91 dB, and the statistics read D3D11 SuperResolution* and RTX Video HDR* together |
| Super Resolution beside it | 49.35 dB, and the detail 0.4095 → 0.5272 |
Upstream's own master does not survive that case at all: a 10-bit source on an HDR display
with RTX Video HDR on dies with 0xC00000FD, a stack overflow in an unbounded recursion
between the video processor's set-up and the swap chain's. The bound added in 1.45 is what
carries this fork through it.
What 1.45 told you, and what is true
1.45's statistics, tooltips and manual said the driver leaves a 10-bit 4:2:0 picture untouched,
and that ticking Replace VP chroma upsampling was what gave RTX Video HDR something to work
on. Both were wrong, and so were the figures that went with them.
The measurement behind them had put the processor into PQ passthrough before asking -- the one
arrangement in which the extension does nothing. And the end-to-end figures came from a bench
whose --file named a film but never built its graph: every "film" run played the bench's own
800x450 RGB32 pattern, which the renderer converts with shaders and which never brings the
hardware processor into the chain at all. Neither extension could have shown.
So:
- the statistic RTX Video HDR (no tone mapping on 10-bit 4:2:0) is gone; the star is
unconditional, because the driver really does tone map every picture the renderer gives it; - the figures 52.25 → 30.19 and 49.60 → 51.61 are void. Measured again on a real
10-bit film, the same configuration moves 51.61 → 30.38 -- the 8-bit signature; - every tooltip on the Settings page was rewritten: what the box does, what it needs, when it
greys, and the one measured number that decides the choice. They run 2 to 9 lines against 2
to 18, and the three that described the behaviour of two versions ago are correct now; - the manual carries a Corrections section listing all of this rather than quietly dropping
it.
A silent incompatibility with any host built against upstream's header
This fork had put a method of its own in the middle of IVideoRenderer, and a field of its own
in the middle of Settings_t, while keeping upstream's interface identifier. Everything after
them moves: a player or a tool built against upstream's header reached SetSettings when it
asked for GetSettings, and SaveSettings when it set them -- so driving this filter did
nothing at all, and quietly wrote its defaults to the registry.
Both now come after everything of upstream's. Nothing you have saved moves: the settings are
stored by name.
Super Resolution and the 4:4:4 pre-pass
The driver does nothing with a 4:4:4 picture -- 0.000, against 4.011 on NV12 and 3.903 on P010,
with or without RTX Video HDR. 1.45 answered that by not asking for the extension at all; this
release asks for it exactly as upstream asks, and answers in the interface instead:
- Request Super Resolution greys while Use for resizing and Replace VP chroma upsampling
are both in service, because a control that cannot change the picture should say so; - the scaling line reads
D3D11 (No Super Resolution when chroma by shaders)instead of
starring work nobody did; - an interlaced source keeps the processor's own chroma, so there the pre-pass stands aside and
the control stays live.
Upstream 0.10.8
The fork now carries upstream's development up to 0.10.8, merged with the procedure in
MERGING-UPSTREAM.md: the pre-flight check tools/upstream_check.py, reserved resource-id
ranges so a merge can never give two resources the same number, the one-command battery
tools/dlssnr_probe/run_all.cmd, and a set of reference numbers to compare against.
Measuring
playback_test --file now decodes the real film instead of the bench's pattern, takes its
picture on a frame it seeks back to so two builds can be compared frame for frame, reads any
build's own statistics off the window, and prints back the settings the filter kept -- which is
what caught the interface fault. vp444_probe can ask for an HDR output without the
passthrough, which is the measurement this whole release turned on.
The full battery: 17 steps, 0 failures, 2443 rows compared against the reference, 4 moved.
Built with Visual Studio 2022, x64 and x86, without a warning.
MpcVideoRenderer-DLSS5-1.4
MPCVR-DLSS5 1.4
Since 1.3 (3eb706e). Everything below was measured on an RTX 3050 with the tools in
tools/dlssnr_probe, and the numbers are theirs.
The two scaling lists grew, and are now ordered by what they measured
Upscaling and Chroma upsampling on the Settings page are shown best first, as measured
on 1080p film brought to 4K — not in the order the code happens to declare them. Each entry
carries its own number, so no setting already saved has moved.
Three entries join Upscaling:
| Entry | What it is | 1080p→4K luma, RTX 3050 |
|---|---|---|
| ArtCNN C4F16 DS | four convolution layers in compute passes, doubles; cleans grain and compression as it enlarges | 14.5 ms, 63 MB |
| FSRCNNX 16 AR | FSRCNNX_x2_16-0-4-1 with anti-ringing | 18.0 ms, 190 MB |
| FSRCNNX 8 AR | FSRCNNX_x2_8-0-4-1 with anti-ringing | 5.9 ms, 95 MB |
Two join Chroma upsampling: Jinc (EWA), the polar kernel madVR and mpv call Jinc —
jinc(d) windowed by a jinc, cut at its third zero — and FSRCNNX 8 AR on Cb and Cr.
Nothing was taken away: every method that was there is still there.
Anti-ringing
A network asked to double a picture invents an edge steeper than the one it was given and
overshoots past it — the bright fringe along a dark line, which is what FSRCNNX is known for.
AR takes it back the way libplacebo does inside its own kernels: the value is pulled
towards the range the four source samples around that point really cover, four fifths of the
way. RAVU-zoom already carries this inside its kernel; FSRCNNX and ArtCNN do not.
| detail | overshoot | sharpness | |
|---|---|---|---|
| FSRCNNX 8, line art | 20.06 → 21.03 dB | 0.00692 → 0.00189 | 0.911 → 0.821 |
| FSRCNNX 16, line art | 20.81 → 21.48 dB | 0.01043 → 0.00248 | 0.931 → 0.835 |
| FSRCNNX 8, clean film | 48.13 → 47.99 dB | 0.00015 → 0.00001 | 0.967 → 0.948 |
It costs nothing measurable in time.
Luma, ten 4K film frames reduced and enlarged again
PSNR on the most detailed quarter of the picture, against Catmull-Rom; halo is how far the
output overshoots the range the reference really covers along its edges.
| Method | 1080p→4K | grain | compressed | 720p→4K | line art | halo | time |
|---|---|---|---|---|---|---|---|
| ArtCNN C4F16 DS | −1.36 dB | +1.37 dB | +0.38 dB | +0.20 dB | +2.92 dB | 0.00028 | 14.5 ms |
| RAVU-zoom | +1.56 dB | +0.58 dB | +0.20 dB | +1.58 dB | +0.65 dB | 0.00002 | 3.9 ms |
| FSRCNNX 16 AR | +2.02 dB | +0.31 dB | −0.02 dB | +2.27 dB | +2.43 dB | 0.00005 | 18.0 ms |
| FSRCNNX 8 AR | +1.58 dB | +0.15 dB | −0.11 dB | +1.96 dB | +1.98 dB | 0.00005 | 5.9 ms |
| FSRCNNX 16 | +2.18 dB | +0.23 dB | −0.12 dB | +2.65 dB | +1.76 dB | 0.00023 | 18.0 ms |
| FSRCNNX 8 | +1.72 dB | +0.03 dB | −0.22 dB | +2.28 dB | +1.01 dB | 0.00020 | 5.9 ms |
| Catmull-Rom | 0 | 0 | 0 | 0 | 0 | 0.00000 | 0.9 ms |
| Jinc2m | −3.48 dB | −2.65 dB | −1.75 dB | −1.02 dB | +1.61 dB | 0.00039 | 2.6 ms |
A clean master is where FSRCNNX 16 wins and ArtCNN DS loses — ArtCNN is a denoiser as much as
an upscaler, and a clean reference has nothing to clean. A real film, grain and compression on
top, is the other way round: ArtCNN DS gains a decibel on everyone else, because it is the only
one that does not amplify what the encoder left behind. If you would rather keep the grain than
have it cleaned, take FSRCNNX or RAVU-zoom.
Chroma, six 1080p film frames through the filter itself
PSNR of Cb and Cr over the picture, then along the luma's edges where bleeding shows, against
Catmull-Rom. Measured with the chroma sited where video puts it, which is what decides this.
| Method | Cb/Cr | at luma edges | line art, at edges | what it costs |
|---|---|---|---|---|
| Jinc (EWA) | +0.22 dB | +0.61 dB | +0.25 dB | about 32 texels a pixel, inside the conversion shader |
| RAVU-zoom | −0.05 dB | +0.47 dB | +1.89 dB | a pass of its own, 2.4 ms at 1080p |
| Catmull-Rom | 0 | 0 | 0 | 16 texels a pixel |
| FSRCNNX 8 AR | −0.32 dB | −0.21 dB | +2.28 dB | a pass of its own, 4.0 ms at 1080p |
| Bilinear | −0.29 dB | −0.73 dB | −1.55 dB | one bilinear fetch |
Jinc is the one to take on film: the only method above Catmull-Rom on both the colour and
the colour along edges, and it shifts nothing. On a 10-bit source it gains more still, +1.6 and
+2.0 dB. FSRCNNX on chroma is below Catmull-Rom on a photograph — a network trained on luma
has no business guessing colour from one — and the best of all of them on drawn lines by a wide
margin, which is the case it is there for. The list is ordered for film.
Defaults are unchanged: Upscaling is Jinc2m and Chroma upsampling Catmull-Rom for a fresh
installation.
Chroma rebuilt in 4:4:4 before the video processor
A new box, Replace VP chroma upsampling, sits under Chroma upsampling. With it on, a
compute shader rebuilds Cb and Cr with the chosen method and hands the D3D11 video processor a
4:4:4 picture — AYUV on an 8-bit source, Y410 on a 10-bit one — which the processor then
converts and resizes exactly as before.
The processor's own chroma measures about bilinear, and on a 10-bit source its driver reads the
studio range as 16/255 to 235/255 whatever the depth, which shifts the colour by about seven
tenths of a level:
| Source | Chroma | Cb/Cr | At luma edges | Colour shift |
|---|---|---|---|---|
| 8-bit (NV12) | the video processor | 52.25 | 48.69 | 0.07 level |
| Catmull-Rom before it | 52.86 | 49.60 | 0.07 | |
| 10-bit (P010) | the video processor | 49.60 | 47.76 | 0.68 level |
| Catmull-Rom before it | 55.24 | 51.68 | 0.05 | |
| Jinc before it | 56.61 | 53.51 | 0.06 |
On a 10-bit film that is 5.6 to 7.0 dB on the colour, 3.9 to 5.8 dB along the edges, and the
driver's colour shift gone.
The processor keeps the picture, so what only it can do keeps applying:
- RTX Video HDR goes on working, and on a 10-bit source it starts working: the driver
leaves a 10-bit 4:2:0 picture untouched (0.000 change) and tone maps the same frame in 4:4:4
as it does an 8-bit one (37.7 against 37.9). It is no longer asked for on a 10-bit 4:2:0
picture, where it never did anything, so the statistics stop claiming it there. - Super Resolution does nothing to a 4:4:4 picture (0.000, against 4.0 on 4:2:0), so it is
not requested for the pictures this moves, and the statistics do not claim it either. - HDR passthrough is unaffected: the processor converts PQ from AYUV, Y410 and Y416 as it
does from NV12 and P010. - Interlaced video keeps the processor's own chroma: it alone deinterlaces, and only 4:2:0.
A setting changed while the film plays no longer freezes the picture
Ticking or unticking anything that stopped HDR output — RTX Video HDR first among them, or any
format change that took it away — froze the picture while the sound kept playing, and only
restarting the player brought it back. It was not what it looked like: HDR output needs the
flip presentation model, Swap effect: Discard asks for the older one, and Windows never takes
a window back to it. The swap chain then presented every picture, in time and without error,
while the screen kept the last one.
A window that has carried the flip model now keeps it — it shows everything the old model
showed. Reset() also took the HDR toggle lock before the renderer lock, the order every other
path takes them the other way round; that is fixed too.
Every setting now takes effect on the following picture, with no restart: the formats the
processor may take, RTX Video HDR, Super Resolution, the chroma and upscaling methods, and the
new box.
DLSS Super Resolution follows moving subjects
DLSS SR is fed motion vectors of its own instead of DLSS 5 NR's raw ones, which left still
backgrounds shimmering and grain along the frame's edges. Each block is drawn to the picture's
global motion where it lies within the noise of it, and a mean shift over the trusted blocks of
a 7×7 window, a sub-pixel search on the flow frames and a temporal blend follow the subjects in
the foreground. The option is marked (Experimental) in the page.
Under the hood
ArtCNN is made of compute passes, which the prescaler runner could not do: it now creates and
dispatches them, writing through unordered access slot 0 — the one slot feature level 11.0
always gives a compute shader. A compute pass sets no render target of its own, so a plane the
pass above had just drawn into stayed bound as one and Direct3D dropped its shader resource
view: the pass read zeros. It cost a black picture with ArtCNN and a green wash with FSRCNNX 8
AR on chroma before both ends were made to unbind. --tmpvport now checks ArtCNN as well, and
gives the harness's picture to the last half float.
Tools
playback_test --toggle changes each setting while the film plays, as the player does, and
watches the desktop itself — a renderer that draws every picture says nothing about what
reaches the screen. --gpu feeds it D3D11 textures the way a hardware decoder does, --hdr
runs it with HDR passthrough, --switch walks the processor's extras, and
--file <mkv> [--seek <s>] plays a real film through LAV. --chroma and --chroma10 now cover
every chroma method, each of them again through the video processor with the new box on.
--mainpage prints both scaling lists with the number each entry carries. shader444_test
compiles the generated chroma pass for every source format and chroma method. freeze_dump
reads what a frozen player is waiting for, with the filter's own names.