Two more examples of downsampled mask size 2 mask 10:
Aperture:
Slot mask:
New Release Version (2023-06-04-r1):
Notable changes:
Download link:
https://mega.nz/file/toBGBAYR#9uljee1NWY4-9LUg09d1f3sfOROaYgeN3fXVF2hccZw
I would also kindly ask @hunterk for a repository update (this one is just copy-over also).
Edit: thanks @hunterk for the update. Newest versions are now available through the RA shader updater.
Yay! I hope we get more frequent updates on the repository.
Not only is it more convenient to update, but it’s also easier to check what changed between versions.
Nice. With this update I can remove the note in my thread about users needing to manually having to download your latest update since everyone can now get it simply by updating their slang shaders, until you drop another new update on us that is lol.
For anyone using my pack it works with my presets, I tested it and nothing is affected at all from what I see.
@guest.r, I’d like to thank you for the amazing work that you’ve done with this shader. The depth of it is incredible. I’ve been playing with it for the last couple of weeks for 10-15 minutes a day, and I still have a lot to learn. Most of what I’ve done so far is explore the masks, scanlines, and parts of bloom/glow/halation.
To my eye, 8K and a display that put out a gazillion nits would be ideal, but I’ve found the mask zoom feature particularly interesting to increase TVL perception for systems where that look is more appropriate.
I wish the shader was documented, but it’s also been fun to play with the sliders and learn what things do. Below I’ve included a screenshots which I hope do your shader some justice.
Hello Guest, I was having a look at your fast grade shaders and saw some optimization tricks.
You can multiply linear transformation matrices to create a new joint matrix, maybe the same can be applied to other shaders of your pack but in pre-shaders.slang at line 315:
color = (m_in*m_out)*color;
color = clamp(color, 0.0, 1.0);
color = pow(color, vec3(1.0/p));
if (CP == -1.0) color = c;
vec3 scolor1 = plant(pow(color, vec3(wp_saturation)), max(max(color.r,color.g),color.b));
float luma = dot(color, vec3(0.299, 0.587, 0.114));
vec3 scolor2 = mix(vec3(luma), color, wp_saturation);
color = (wp_saturation > 1.0) ? scolor1 : scolor2;
color = plant(color, contrast(max(max(color.r,color.g),color.b)));
p = 2.2;
color = clamp(color, 0.0, 1.0);
color = pow(color, vec3(p));
mat3 warm = ToSRGB*D65_to_D55;
vec3 warmer = warm*color;
mat3 cool = ToSRGB*D65_to_D93;
vec3 cooler = cool*color;
Yeah, these two (warm and cool) can be pre-calculated since there are constant values involved. Otherwise mat3x3 * mat3x3 should require 3x more ops compared with mat3x3 * vec3. Nevertheless, an optimization is possible, thanks for the hint.
‘color’ is a vec3 array variable so it’s like running mat3vec3pixels, if you precompute (not necessarily a constant) a mat3 * mat3 you save one mat3vec3pixels operation which is huge. Maybe try to profile them, not sure how though not an expert on shaders (fps?)
You still need to use resources for a mat3*mat3 multiply doing it on the fly. But you know the math…(9 dot products)
It can be done very fast due to parallelism, true, but mat3*vec3 should be simpler (3 dot products).
Moving it to the vertex shader should help indeed though, maybe it’s a good trade.
Hey, I noticed in the ReShade port the Integer Scaling
setting also scales the mask and not just the game. I’m not sure if this is an issue on my end or intended functionality, but I’d like to request that it be fixed/changed if possible.
(Also just a friendly nudge to update the port in general, please!)
For anyone interested I’ve ported CRT-Guest-Advanced, HD and NTSC to ReShade.
Some screenshots at default settings.
Advanced -
HD -
NTSC -
That’s amazing. I need to figure how to convert shaders to Reshade, I’ve gotten multiple requests to port my presets over there but don’t have the slightest idea on how to do it but your pics make me want to learn.
Great work, @DevilSingh, i will put a link to your git page in my first post also.
Good timing, lol, you can now try and use the newest versions ported to ReShade.
Thanks! This port wouldn’t be as good as it is without your help and testing.
*Says “Ive been away for awhile”… *proceeds to go away for awhile
Anyway the reason I never made that third preset I promised was a lack of ideas. I have ideas now.
Recent screenshots look great guys.
@guest.r Could it be possible also apart from negative mask bloom, you could implement negative post brightness? just a numb question
A question @guest.r about handling non-square aspect ratios in CRT shaders (I’m just asking you as you must be familiar with the concept because of your Amiga shaders that handle 640x256 and 320x512 and similar resolutions properly).
The beam illuminating the phosphors in a CRT has the shape of a perfect circle with Gaussian falloff. So far so good, and if you feed such a CRT shader 1:1 pixel aspect ratio content (e.g. 640x480 or 320x240, assuming a 4:3 DAR emulated monitor), the shape of the emulated beam will remain a perfect circle in the shaded output.
But when dealing with non-square aspect ratios, typically ~1:2 PAR “wide” or ~2:1 PAR “tall” pixels (or anything in between or much beyond that, e.g. the 1280x200 Super-HiRes Amiga mode featuring 1:4.8 PAR “super tall” pixels!), the shader effectively processes a say 640x200 image, which then gets stretched to 4:3 display aspect ratio, meaning the shape of the emulated beam effectively gets elongated.
I’ve inspected the source code of some CRT shaders, and I haven’t noticed any mechanism in any of them that would “pre-distort” the shape of the beam by the inverse of the pixel aspect ratio so when the result is stretched to the final 4:3 display aspect ratio output, the shape of the beam would come out as a perfect circle. Moreover, output resolution is not taken into account either; an accurate CRT shader should not produce a “more blurry” picture for 320x240 input vs 640x480 input, for example (the CRT does not “vary” the size of the electron beam based on what signal is fed to it).
This is a bit of a problem for me because without such pre-distortion, it’s just not possible to use a single shader with a single preset that would handle say 320x240, 640x240, 320x480 and 640x480 so that the size of the emulated beam remains a perfect circle with the exact same radius in all resolutions (I need this for my authentic CGA/EGA/VGA shader presets where such variations are common).
I’m guessing most people just don’t care about such detail? Or maybe it’s technically very hard to apply such pre-distortion at the shader level to keep the beam shape and size constant no matter the variation in input dimensions (and of the PAR, by extension)?
Thanks, and I hope I managed to explain all this slightly complicated topic clearly
Yes, this is an issue with CRT emulation and the most common way is to use a filtering approach which works properly only with low resolution input.
The main problem is that CRT emulation isn’t done on a low level, but uses HW features of an adapter (like point or bilinear filtering), a basic filtering approach (like adapted bilinear, quilez…), a standard filtering approach (like lanczos, spline, sinc, gaussian…) or something more advanced.
Currently i don’t know many CRT shaders that would consider advanced filtering, because special kernels need to be implemented which consider doubled (tripled) pixels and thus don’t skip details.
From my Retroarch repertoire the only shader capable of doing so properly is the guest-advanced-HD version, where it’s simple to change the internal resolution parameter, but it’s not automated for an input resolution for various reasons.
On the WinUAE side i needed to write special kernels to handle the hires (only hires, not superhires…) mode properly, but interlacing support (for example) is missing due to limited capabilities of the emulator’s shader environment.
There exists a ReShade version of the ‘HD’ shader, but you need to manually input the resolution every time it changes etc.
What i’m saying is that these problems aren’t addressed in general and it’s also hard to address them. A good and persisting example is the SNES game Trials of Mana (Seiken Densetsu 3), which changes the resolution to the ‘hires’ when talking and going to menues. Most common way is to ‘derez’ the game to 256x224, but here details are going missing.
So, a single preset or a single configured shader to cover every resolutional situation properly hasn’t been developed yet afaik and trends show there is much more probability that any shader will require manual tuning for special cases.
Unless there is something done from scratch especially for these.
Thanks for sharing your great insights into the matter @guest.r!
For the record, I started down this path because I wasn’t content with how an emulated 320x200 EGA image looks like when using the Hyllian shader (which is fantastic for 640x400+ content, otherwise, e.g. for double-scanned VGA). I just couldn’t get the results look like a real EGA monitor; there was always too much softness horizontally.
When I width-doubled the input of the shader to 640x200, the results were a lot closer to the output of a typical sharp EGA monitor, but then I started to think about how realistic this is. In a way, it is because the same 320x200 image displayed in 320x200 mode, or width-doubled to 640x200 and displayed in 640x200 mode yields the exact same results, just like on a real CRT. On the other hand, I have effectively squashed the circular beam shape into an oval…
I’m still vacillating whether this is the right solution or not. I have a bit of a distaste for it as literally sending a double-width image to the shader seems kind of crude. On the other hand, that’s literally what we have to do for accurate line and pixel doubled VGA emulation (e.g. low-res 320x200 gets doubled to 640x400; from the VGA monitor’s perspective, “fake 320x200” (doubled by the VGA adapter) and “real 640x400” screen modes are 100% identical down to the signal level).
So maybe that’s what I’ll do after all; at least, then it’s consistent with the VGA pixel/line-doubling emulation. Plus the beam shape will get distorted in the myriad of tweaked VGA modes anyway (320x400, 360x200, 360x480, 320x400, 360x270, 376x308 — it’s an unending list…)
Comparison screenshots for reference.
320x200 sent to the shader
640x200 sent to the shader
Closeup
Horizontal resolutions are managable with my current codebase, but i’m not this confident with vertical resolutions and scanlines.
A 4k display should be mandatory for everything above 250px or/and double scan. But i guess the ‘stranger’ the resolution the seldom it appears.