I wouldnt say that about the Vulkan driver - keep up to date as that was an important fix, its probably just uncovered another bug in the text that was already there due to opacity now correctly working for the background quad - the background has been broken for a while. I suppose if you’re seeing much worse text corruption than I am then that is another story. Im seeing the opacity a bit out of whack on the fringes of the text at the moment - its still perfectly readable though right?
Just fixed the text issue - not corruption per se just an incorrect blend function being used.
@MajorPainTheCactus What are your views on using Floating Point Frame Buffers for the entire shader stack? Is there any benefit in doing that for additional or improved image quality?
I keep my UI set to 100 nits using that trick I mentioned upthread, with Opacity set to full 0.000, and I think that combination made the text bug way worse for me experientially. Bits of the menu overlay UI randomly shifting from 100 nits to nearly 900 nits was quite unpleasant. Pleased to hear it should be resolved properly soon.
Now there’s a question. Depends what you’re doing and what floating point type youre talking about. Im going to assume you’re talking about R16G16B16A16_FLOAT rather than the normal R8G8B8A8_UNORM. Basically if you do anything at the intermediate point between shader stages where you need the precision passed onto the next stage then you should use 16 bit float buffer. Usually in CRT shaders you dont as youre keeping the colours the same and well 24bits for a colour is more than enough to represent the 256 or whatever colours the console of choice kicks out and blurs of those colours etc are fine.
Where an rgba 8bit unorm falls down typically is in HDR circumstances: its a UNORM so it only has colour values between 0 and 1 and a high dynamic range allows you to go over that up to max nits/paper white nits so say 5.0 for 1000 nits / 200 nits. But how do you get into that higher range if the console only outputs values from 0.0 to 1.0 (or 0 to 255)? You need to inverse tonemap it and expand it out to the full range.
But the final display will never normally be RGBA16 float (64bit back buffer) because of bandwidth limitations (high framerates at high resolutions) and so we remap back down to 0-1.0 using the hdr PQ curve to allow us to use a 32bit back buffer: R10G10B10A10 UNORM.
There are many other scenarios where you need 16 bit intermediate buffers but be aware that youre just wasting bandwidth if you dont need it for no benefit. 24bit colour (R8G8B8) at over 16 million colours is still a lot of colours to play with.
“Vulkan: Fix HDR pipeline blend factor for correct text rendering (#18697)” has been merged, and i am pleased to confirm that it resolved the menu text corruption issues as expected.
Unfortunately, this also caused a regression: anamorphic.slangp is now broken again, just as it was before “Vulkan: Fix HDR pipeline blend factors and quad vertex buffer handling (#18678)” was merged (presumably other shaders are also effected, anamorphic.slangp is just the test case i randomly found was broken while stress testing previously, and so i’ve continued using it as a test case).
My instinct is that it would be best to wait and see if @warmenhoven’s vulkan: minor hdr fix changes anything on this front.
@MajorPainTheCactus Also, i’m wary of putting this in your lap since i know you have limited time, but i suspect you would want to be aware that d3d12 crashes in different ways with 22+ and 33+ playlists might be related to changes made during the HDR revamp. I don’t have access to any 1.22.2 nightly builds from before the revamp (an oversight on my part in retrospect…), so i can’t bisect far enough back to verify or rule it out.
All i know for sure is that the issue didn’t occur in 1.22.2 stable (2025.11.19 21:44 EST), but does occur in the oldest 1.22.2 nightly i have, which is immediately post-revamp (2026.01.17 22:13 EST).
Float framebuffers are needed if you need to keep values outside of [0, 1] across shader stages or if color data is linear instead of gamma corrected.
Would prepending an upscaling/smoothing shader like XBR-LEVEL-2 to Sony Megatron Colour Video Monitor create such a scenario?
What about in NTSC signal/artifact emulation? We know that for the raw output from the SNES for example 24 bit should be fine, but what about the analog artifacts, interference and signal itself that occurs outside of the console’s video encoder? Wouldn’t that benefit from the higher precision? Or things like the gradations produce by the energy decay on the edges of scanlines and phosphors?
I’m just asking this because everytime I load my experimental floating point frame buffer preset, it seems like it looks more “analog”, has smoother gradations and before and after screenshots always end up being different filesizes by a significant amount.
That fix to text is only a blend function change , its perfectly valid vulkan code before and after so it wont have fixed or broken that shader. Its more likely a driver issue i.e us feeding bad things to the driver and it not coping. Sadly warmenhoven changes bring in a performance bug that makes games unplayable on android devices that have high resolutions. We are working towards a proper fix so hang tight.
No its good to hear about any issues. Ive made a huge number of fixes to d3d12 this week so Id hope these are fixed now
In the meantime if you’re using windows try the d3d12 or d3d11 drivers
I don’t know about xBR, but you almost always need float framebuffers for NTSC shaders.
ScaleFX first two passes contain per-channel calculated non-color data which require float framebuffers. xBR multipass is cool with normal buffers. Almost any normal scenario with regular RGB non-linearized color images is otherwise good with standard buffers also.
Phosphor simulation needs a float framebuffer because the stored framebuffer needs to be in high-precision. At 8-bits, the low end doesn’t have enough precision and the phosphor tail doesn’t decay properly.
Most things only need it when there are multiple shader chains involved. For something like a common upscaler you are supposed to do it in linear space. If this upscaler is part of a chain than it may be more efficient to not gamma correct at the end and instead keep it in a float framebuffer and only do a single gamma correction at the end of all your chains.
On some systems I do find after doing composite video simulation that there are hot colors and these would get clipped if they were not stored in float framebuffers. There is a shader I made called limiter.slang. It has a lot of irrelevant code to the actual limiting function which is really simple: it compresses inputs greater than 1 with a soft knee. There is a zebra pattern generator that I use to identify if there are hot colors.
My shader has essentially four different pipeline categories meant to model physical properties. This is why I call it HDRR: because dynamic range is preserved from shader to shader until the final color conversion stage:
-
Digital: models digital signal processing chips, 10-bit framebuffers are used. Values are quantized to a simulated bit depth. Values are limited to 0…1, but YUV processing is done in a limited space with headroom (this is how YUV processing is actually done on fixed-point DSPs). The only preset of mine that uses this pipeline is 3DO.
-
Analog: simulates analog DSP where signals are gamma correct. Converting gamma correct signals back to linear is virtually non-existent on analog hardware, so everything was done on gamma correct voltages even though that’s technically wrong. Basic filtering could use 8-bit framebuffers, but since I include amplification and modulation that can make values outside of 0…1 present, I use 16-bit floats. I also pass YPbPr data across shader stages, and that has a domain of -0.5…0.5.
-
Light: This is where the RGB voltage gets converted to the electron beam and then emitted as light from a phosphor. It covers the beam geometry/upscaling, mask simulation, phosphor decay effect, and curvature. The input voltages are mapped to luminance values based on a 1:1 ratio (where 1 on the output represents 100 nits). It’s all done in linear space, and values can be greater than 1, so for those reasons floating point framebuffers are used.
-
Output: the colorspace of the phosphors is converted to either sRGB or BT.2020 and gamma corrected. If HDR was supported that would be handled here with a tonemapper. The result is stored in either an 8-bit framebuffer for sRGB or a 10-bit one for BT.2020.
I hope that sheds some light for how I decided on what framebuffer type to use.
Unfortunately, d3d12 still crashes on startup if you have 33 or more playlists as of the most recent nightly (time stamp 2026-02-07 14:21 EST).
That makes perfect logical sense, but it doesn’t change what i am seeing in actual testing.
Using vulkan with the nightly build time stamped 2026-02-05 14:13 EST, anamorphic.slangp loads and displays identically to d3d11
With the nightly builds with time stamps 2026-02-06 14:12 EST and 2026-02-07 14:21 EST, vulkan instead shows a black screen when anamorphic.slangp is loaded.
There was a regression here in between build 2026-02-05 14:13 EST and build 2026-02-06 14:12 EST, whether that actually makes intuitive sense or not.
anamorphic.slangp isn’t a shader i actually use, just a test case i found, so i feel no need to switch over this, but it is clearly revealing some sort of bug in the way vulkan is handling at least some shaders.
That said, i originally switched to vulkan from d3d11 due to Retroarch’s Black Frame Insertion/subframe not working with d3d11, and that is no longer the case, so i should probably explore if i want to switch back anyway.
Yeah the bug you’re probably seeing is due to undefined/uninitialised code - one build it maybe fine the next it wont be thats just the nature of those types of bugs. We’re working on d3d12 and vulkan driver validation stuff right now so hopefully one of those bugs fixes, will fix the anamorphic shader. If not we’ll have to look into it more deeply.
33 is one more than 32
Does something visually change after 32 playlists are added?
Not as far as i can tell.
And it gets weirder.
Cores with autoloaded/saved shaders silently crash on load with 22 or more playlists present, regardless of what the shaders are.
It doesn’t matter how long the playlists are, or what the contents of the playlists are, or what icons they use. It’s just how many are present.
If vulkan or d3d11 develop similar issues at some point, i’ve not seen it. My actual install runs 53 playlists atm, and it’s just d3d12 that has issue with that.
Trying using massive numbers of dummy playlists just to see what happens, d3d11 and vulkan both load without issue with 1024 playlists, but d3d11 starts having some graphics corruption on the mouse cursor at some point. Narrowing down the exact number for that now.
Edit: looks like the d3d11 mouse cursor graphics corruption starts to appear with 714 or more playlists, and appears more consistently the more playlists there are.
That is an absurd number of playlists xD
Vulkan still loads without complaint with 2048 playlists, but it does take longer to load. I don’t really feel like pushing vulkan any further than that using my personal desktop tbh.
Right OK
playlists it is then. So how do I test this easily?