Please show off what crt shaders can do!

Thanks, but I’m not happy with how it looks IRL. The staggered crossbars are really obscured by the LCD’s own pixel structure. Jacking up the brightness doesn’t help, either. Here’s the same thing but with an aperture grille, which I feel translates to full screen mode much better. Maybe brightness needs a bit of a boost.

Whatever Blargg is doing, it just looks right. Black lines are bold via composite. High contrast edges are always weird with the NTSC shaders, either too blurry or too harsh with no happy medium. I just wish that Blargg’s filter could be translated directly into slang so we could use it with those cores that don’t have support for video filters. @hunterk what’s easier, adding support for video filters to those cores that currently lack it, or translating Blargg’s filter into a slang shader?

Performance-wise, the shader is definitely better.

shaders = "12"
shader0 = "shaders_slang/misc/grade.slang"
filter_linear0 = "false"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders_slang/crt/shaders/guest/advanced/stock.slang"
filter_linear1 = "false"
wrap_mode1 = "clamp_to_border"
mipmap_input1 = "false"
alias1 = "StockPass"
float_framebuffer1 = "false"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders_slang/crt/shaders/guest/advanced/afterglow0.slang"
filter_linear2 = "false"
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
alias2 = "AfterglowPass"
float_framebuffer2 = "false"
srgb_framebuffer2 = "false"
scale_type_x2 = "source"
scale_x2 = "1.000000"
scale_type_y2 = "source"
scale_y2 = "1.000000"
shader3 = "shaders_slang/crt/shaders/guest/advanced/pre-shaders-afterglow.slang"
filter_linear3 = "false"
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "true"
alias3 = "PrePass"
float_framebuffer3 = "false"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "shaders_slang/crt/shaders/guest/advanced/avg-lum.slang"
filter_linear4 = "true"
wrap_mode4 = "clamp_to_border"
mipmap_input4 = "true"
alias4 = "AvgLumPass"
float_framebuffer4 = "false"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "shaders_slang/crt/shaders/guest/advanced/linearize.slang"
filter_linear5 = "true"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
alias5 = "LinearizePass"
float_framebuffer5 = "true"
srgb_framebuffer5 = "false"
scale_type_x5 = "source"
scale_x5 = "1.000000"
scale_type_y5 = "source"
scale_y5 = "1.000000"
shader6 = "shaders_slang/crt/shaders/guest/advanced/gaussian_horizontal.slang"
filter_linear6 = "true"
wrap_mode6 = "clamp_to_border"
mipmap_input6 = "false"
alias6 = ""
float_framebuffer6 = "true"
srgb_framebuffer6 = "false"
scale_type_x6 = "absolute"
scale_x6 = "800"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "shaders_slang/crt/shaders/guest/advanced/gaussian_vertical.slang"
filter_linear7 = "true"
wrap_mode7 = "clamp_to_border"
mipmap_input7 = "false"
alias7 = "GlowPass"
float_framebuffer7 = "true"
srgb_framebuffer7 = "false"
scale_type_x7 = "absolute"
scale_x7 = "800"
scale_type_y7 = "absolute"
scale_y7 = "600"
shader8 = "shaders_slang/crt/shaders/guest/advanced/bloom_horizontal.slang"
filter_linear8 = "true"
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "false"
alias8 = ""
float_framebuffer8 = "true"
srgb_framebuffer8 = "false"
scale_type_x8 = "absolute"
scale_x8 = "800"
scale_type_y8 = "absolute"
scale_y8 = "600"
shader9 = "shaders_slang/crt/shaders/guest/advanced/bloom_vertical.slang"
filter_linear9 = "true"
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "false"
alias9 = "BloomPass"
float_framebuffer9 = "true"
srgb_framebuffer9 = "false"
scale_type_x9 = "source"
scale_x9 = "1.000000"
scale_type_y9 = "source"
scale_y9 = "1.000000"
shader10 = "shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced.slang"
filter_linear10 = "true"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
alias10 = ""
float_framebuffer10 = "true"
srgb_framebuffer10 = "false"
scale_type_x10 = "viewport"
scale_x10 = "1.000000"
scale_type_y10 = "viewport"
scale_y10 = "1.000000"
shader11 = "shaders_slang/crt/shaders/guest/advanced/deconvergence.slang"
filter_linear11 = "true"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "false"
alias11 = ""
float_framebuffer11 = "false"
srgb_framebuffer11 = "false"
scale_type_x11 = "viewport"
scale_x11 = "1.000000"
scale_type_y11 = "viewport"
scale_y11 = "1.000000"
g_signal_type = "0.000000"
g_crtgamut = "0.000000"
g_vignette = "0.000000"
g_mid = "0.500000"
g_sat = "0.100000"
WP = "-100.000000"
wp_saturation = "1.100000"
glow = "0.000000"
brightboost = "1.500000"
brightboost1 = "1.999999"
beam_min = "1.500000"
beam_max = "1.100000"
beam_size = "1.000000"
scans = "1.000000"
h_sharp = "4.000001"
s_sharp = "0.000000"
shadowMask = "2.000000"
maskLight = "1.000000"
mask_layout = "1.000000"
mask_gamma = "2.399998"
mclip = "0.000000"
gamma_out = "1.900000"
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3;SamplerLUT4"
SamplerLUT1 = "shaders_slang/crt/shaders/guest/advanced/lut/trinitron-lut.png"
SamplerLUT1_linear = "true"
SamplerLUT1_wrap_mode = "clamp_to_border"
SamplerLUT1_mipmap = "false"
SamplerLUT2 = "shaders_slang/crt/shaders/guest/advanced/lut/inv-trinitron-lut.png"
SamplerLUT2_linear = "true"
SamplerLUT2_wrap_mode = "clamp_to_border"
SamplerLUT2_mipmap = "false"
SamplerLUT3 = "shaders_slang/crt/shaders/guest/advanced/lut/nec-lut.png"
SamplerLUT3_linear = "true"
SamplerLUT3_wrap_mode = "clamp_to_border"
SamplerLUT3_mipmap = "false"
SamplerLUT4 = "shaders_slang/crt/shaders/guest/advanced/lut/ntsc-lut.png"
SamplerLUT4_linear = "true"
SamplerLUT4_wrap_mode = "clamp_to_border"
SamplerLUT4_mipmap = "false"
5 Likes

Doing a direct port of blargg’s filter is a no-go. It’s just not designed for it. In fact, its main design consideration was being able to run on blargg’s ~200 mHz PPC CPU. To that end, it’s really not particularly accurate, with banding caused by reduced color precision so the math works out faster/easier, etc. Blargg didn’t even actually write the algorithm, he just optimized the crap out of it (it originally came from NewRisingSun; I haven’t been able to find any trace of the original NRS algo anywhere online to examine and see whether it’s just a “looks good” approximation or what).

In contrast, themaister’s NTSC is based on modeling the actual signal de/modulation behavior in matlab and then taking those modeled values into the shader.

As for adding the filter into other cores, it’s possible but outside of my area of expertise, and, again, not really going to be any more accurate to what the consoles themselves did with their internal NTSC encoding circuits.

6 Likes

While Blargg’s NTSC filters are good for what they are, I don’t find them particularly accurate, especially in regards to NES and Genesis. The real NES composite output is grittier and appears to have more jaggies and flickering, and the Genesis Composite filter lacks the rainbow effects seen in the real console. As for banding, it’s especially bad on the SNES filters, and as a result of that and some weird ringing-like artifacts around edges, even the RGB filter looks off to me, which is a shame because I kind of like what it does to the colors.

3 Likes

I can’t really speak to the accuracy of the actual NTSC stuff that the NTSC shaders/filters are doing, but at a casual glance there’s definitely a difference when it comes to sharpness. Here’s SMB running via composite video. I think you’d agree that at least in terms of horizontal sharpness around high-contrast edges, Blargg’s filter is more accurate? There’s a blurriness to the shader that just doesn’t exist on the CRT. I don’t know if that’s due to the NTSC stuff per se so much as other settings.

Real CRT

Blargg’s filter + gdv + custom shader settings

gdv-nts, similarly adjusted

Here it is with subtractive sharpness added, looking a bit better, but still not as sharp as the CRT

3 Likes

Never paid much attention to Blargg’s filter until now. Tried a few games and it was able to blend dithering pixels without losing much sharpness. Didn’t notice washed out colors either. With the NTSC shader, if you want to fully blend dithering patterns, phase 2 is required and you’d lose sharpness and colors big time.

4 Likes

I am using that blargg filter since 2006 or '07 on an Athlon XP, Radeon X700 pro and Kega Fusion. Still have that PC in my parents home lol.

3 Likes

Here’s phase 2, and as you said the sharpness leaves something to be desired even with subtractive sharpness at 1.00. The mask is doing a lot of work to cover up some of the harshness/weirdness at the edges, but you can still see that the black lines aren’t nearly as clean as they should be, compared to the CRT.

3 Likes

3-phase still blends. But not as much as 2-phase. It looks more like svideo, or like composite on a TV that has a very good color decoder. TVs from the mid 90s and later usually had that. There’s been screenshots of CRT TVs posted here where composite was quite sharp and looks pretty much identical to 3-phase in the sonic waterfalls.

3 Likes

Honestly composite is such a mixed bag on CRTs it can go from looking like near RF levels of grunge to almost S-Video levels of sharpness, for tvs made in the same year…

3 Likes

Tbh, we just need to do a new video signal shader, and just fudge the ever living hell out of the effects. (We can achieve “accuracy” for what it’s doing, after we get it looking ballpark :joy:)

Mainly my brain is starting to finally register that our current video signal option are really lacking and odd if I’m being honest. Like I said previously, composite input into a CRT can look drastically different between sets, and I feel like we lack those kinds of controls to make this happen currently.

Granted I completely understand that it isn’t a simple task to just pull something like this out your ass, and with something like I’m describing we have to make a hard choice upfront. (Lots of settings that are hard to grasp and could be potentially problematic to set up “correctly” but lots of fine tuning vs less fine tuning but more stable preset setting situations)

Just some musing, feel free to leave on read :joy:.

EDIT: Btw, NTSC adaptive was definitely a step in the direction I’m crying for. (Tbh I feel like my crying is part of the reason NTSC adaptive exists now ROFL)

3 Likes

4 Likes

11 Likes

My latest test with crt guest advanced NTSC (1440p, slot mask, mask 9). The only difference between platforms is between composite (SNES, PCE, Genesis) or S-Video (arcade). On Genesis, though, I had to use 2 phase NTSC to achieve transparency as it was meant to be, sacrificing a lot of visual clarity. 3 phase is way better, so I’m pretty unsure about what I will choose. Open images in a new tab!

6 Likes

Very nice. What you’re doing is more or less what I’m looking for.

Mind sharing the presets? I’m looking for a slot mask look like that. Are you using any sharpening?

EDIT: Except Sonic, something does not look right there. Is it the same preset on all screenshots?

1 Like

Sure, it’s nothing too fancy, just some precise tweaks.

shaders = "17"
shader0 = "../shaders/shaders_slang/crt/shaders/guest/advanced/stock.slang"
filter_linear0 = "false"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "1.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "../shaders/shaders_slang/crt/shaders/guest/advanced/stock.slang"
filter_linear1 = "false"
wrap_mode1 = "clamp_to_border"
mipmap_input1 = "false"
alias1 = "StockPass"
float_framebuffer1 = "false"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "../shaders/shaders_slang/crt/shaders/guest/advanced/afterglow0.slang"
filter_linear2 = "true"
wrap_mode2 = "clamp_to_border"
mipmap_input2 = "false"
alias2 = "AfterglowPass"
float_framebuffer2 = "false"
srgb_framebuffer2 = "false"
scale_type_x2 = "source"
scale_x2 = "1.000000"
scale_type_y2 = "source"
scale_y2 = "1.000000"
shader3 = "../shaders/shaders_slang/crt/shaders/guest/advanced/pre-shaders-afterglow.slang"
filter_linear3 = "true"
wrap_mode3 = "clamp_to_border"
mipmap_input3 = "false"
alias3 = "PrePass0"
float_framebuffer3 = "false"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "../shaders/shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass1.slang"
filter_linear4 = "false"
wrap_mode4 = "clamp_to_border"
frame_count_mod4 = "2"
mipmap_input4 = "false"
alias4 = ""
float_framebuffer4 = "true"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "4.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "../shaders/shaders_slang/crt/shaders/guest/advanced/ntsc/ntsc-pass2.slang"
filter_linear5 = "true"
wrap_mode5 = "clamp_to_border"
mipmap_input5 = "false"
alias5 = ""
float_framebuffer5 = "false"
srgb_framebuffer5 = "false"
scale_type_x5 = "source"
scale_x5 = "0.500000"
scale_type_y5 = "source"
scale_y5 = "1.000000"
shader6 = "../shaders/shaders_slang/crt/shaders/guest/advanced/custom-fast-sharpen.slang"
filter_linear6 = "true"
wrap_mode6 = "clamp_to_border"
mipmap_input6 = "false"
alias6 = "NtscPass"
float_framebuffer6 = "false"
srgb_framebuffer6 = "false"
scale_type_x6 = "source"
scale_x6 = "1.000000"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "../shaders/shaders_slang/crt/shaders/guest/advanced/convert-ntsc.slang"
filter_linear7 = "true"
wrap_mode7 = "clamp_to_border"
mipmap_input7 = "false"
alias7 = ""
float_framebuffer7 = "false"
srgb_framebuffer7 = "false"
scale_type_x7 = "source"
scale_x7 = "0.500000"
scale_type_y7 = "source"
scale_y7 = "1.000000"
shader8 = "../shaders/shaders_slang/crt/shaders/guest/advanced/stock.slang"
filter_linear8 = "true"
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "true"
alias8 = "PrePass"
float_framebuffer8 = "false"
srgb_framebuffer8 = "false"
scale_type_x8 = "source"
scale_x8 = "1.000000"
scale_type_y8 = "source"
scale_y8 = "1.000000"
shader9 = "../shaders/shaders_slang/crt/shaders/guest/advanced/avg-lum-ntsc.slang"
filter_linear9 = "true"
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "true"
alias9 = "AvgLumPass"
float_framebuffer9 = "false"
srgb_framebuffer9 = "false"
scale_type_x9 = "source"
scale_x9 = "1.000000"
scale_type_y9 = "source"
scale_y9 = "1.000000"
shader10 = "../shaders/shaders_slang/crt/shaders/guest/advanced/linearize-ntsc.slang"
filter_linear10 = "true"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
alias10 = "LinearizePass"
float_framebuffer10 = "true"
srgb_framebuffer10 = "false"
scale_type_x10 = "source"
scale_x10 = "1.000000"
scale_type_y10 = "source"
scale_y10 = "1.000000"
shader11 = "../shaders/shaders_slang/crt/shaders/guest/advanced/gaussian_horizontal.slang"
filter_linear11 = "true"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "false"
alias11 = ""
float_framebuffer11 = "true"
srgb_framebuffer11 = "false"
scale_type_x11 = "absolute"
scale_x11 = "640"
scale_type_y11 = "source"
scale_y11 = "1.000000"
shader12 = "../shaders/shaders_slang/crt/shaders/guest/advanced/gaussian_vertical.slang"
filter_linear12 = "true"
wrap_mode12 = "clamp_to_border"
mipmap_input12 = "false"
alias12 = "GlowPass"
float_framebuffer12 = "true"
srgb_framebuffer12 = "false"
scale_type_x12 = "absolute"
scale_x12 = "640"
scale_type_y12 = "absolute"
scale_y12 = "480"
shader13 = "../shaders/shaders_slang/crt/shaders/guest/advanced/bloom_horizontal.slang"
filter_linear13 = "true"
wrap_mode13 = "clamp_to_border"
mipmap_input13 = "false"
alias13 = ""
float_framebuffer13 = "true"
srgb_framebuffer13 = "false"
scale_type_x13 = "absolute"
scale_x13 = "640"
scale_type_y13 = "absolute"
scale_y13 = "480"
shader14 = "../shaders/shaders_slang/crt/shaders/guest/advanced/bloom_vertical.slang"
filter_linear14 = "true"
wrap_mode14 = "clamp_to_border"
mipmap_input14 = "false"
alias14 = "BloomPass"
float_framebuffer14 = "true"
srgb_framebuffer14 = "false"
scale_type_x14 = "absolute"
scale_x14 = "640"
scale_type_y14 = "absolute"
scale_y14 = "480"
shader15 = "../shaders/shaders_slang/crt/shaders/guest/advanced/crt-guest-advanced-ntsc.slang"
filter_linear15 = "true"
wrap_mode15 = "clamp_to_border"
mipmap_input15 = "false"
alias15 = ""
float_framebuffer15 = "true"
srgb_framebuffer15 = "false"
scale_type_x15 = "viewport"
scale_x15 = "1.000000"
scale_type_y15 = "viewport"
scale_y15 = "1.000000"
shader16 = "../shaders/shaders_slang/crt/shaders/guest/advanced/deconvergence-ntsc.slang"
filter_linear16 = "true"
wrap_mode16 = "clamp_to_border"
mipmap_input16 = "false"
alias16 = ""
float_framebuffer16 = "false"
srgb_framebuffer16 = "false"
scale_type_x16 = "viewport"
scale_x16 = "1.000000"
scale_type_y16 = "viewport"
scale_y16 = "1.000000"
WP = "-20.000000"
wp_saturation = "0.900000"
vigstr = "0.200000"
quality = "0.000000"
ntsc_phase = "3.000000"
glow = "0.100000"
bloom = "0.600000"
bloom_dist = "0.600000"
halation = "0.100000"
warpX = "0.030000"
warpY = "0.040000"
csize = "0.010000"
bsize1 = "0.200000"
shadowMask = "9.000000"
maskstr = "1.000000"
slotmask = "1.000000"
slotmask1 = "1.000000"
slotwidth = "3.000000"
double_slot = "2.000000"
gamma_out = "2.000000"
post_br = "1.100000"
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3;SamplerLUT4"
SamplerLUT1 = "../shaders/shaders_slang/crt/shaders/guest/advanced/lut/trinitron-lut.png"
SamplerLUT1_linear = "true"
SamplerLUT1_wrap_mode = "clamp_to_border"
SamplerLUT1_mipmap = "false"
SamplerLUT2 = "../shaders/shaders_slang/crt/shaders/guest/advanced/lut/inv-trinitron-lut.png"
SamplerLUT2_linear = "true"
SamplerLUT2_wrap_mode = "clamp_to_border"
SamplerLUT2_mipmap = "false"
SamplerLUT3 = "../shaders/shaders_slang/crt/shaders/guest/advanced/lut/nec-lut.png"
SamplerLUT3_linear = "true"
SamplerLUT3_wrap_mode = "clamp_to_border"
SamplerLUT3_mipmap = "false"
SamplerLUT4 = "../shaders/shaders_slang/crt/shaders/guest/advanced/lut/ntsc-lut.png"
SamplerLUT4_linear = "true"
SamplerLUT4_wrap_mode = "clamp_to_border"
SamplerLUT4_mipmap = "false"

This is for S-Video, for composite just switch inside Retroarch. As for sharpening, I’ve played around with “Sharpen strenght”, leaving “Amount of sharpening” as it is. I think 2 is the limit, 3 seems a little too much. Personally I’m quite happy with 0, but as long as you stay in the 0-2 range it’s up to your preference.

The screenshot of Sonic has been grabbed with a minor difference, 2 phase NTSC instead of 3 phase. This way the transparency trick is better, but you lose visual clarity and colors. Just leave the preset as it is if you look for the latter.

1 Like

Thank you!

Yeah, I assumed Sonic was using 2 phase, but it looks like something else is off in the mask. Can’t really say what. Sonic and the game with the red arch look different than all the rest.

EDIT: “Nothing too fancy” is exactly what I’m looking for. I also like @sonkun’s presets a lot but I feel the base picture is changed a lot and I’m looking for something barebones but with a slot mask. I’m open to more recommendations, ofc.

2 Likes

Thank you I’m glad you like my presets. You’re right in that I’m constantly changing the picture,the slot mask pictures above are similar to how I started off when I started doing slot mask presets. At this point I’m just tweaking NTSC settings trying to hit a sweet spot with the sharpness both of my presets, dont want an image too blurry or too sharp but we’ll see how it goes when I post my next update soon

2 Likes

Looking forward to it! I usually use NTSC too. :slight_smile:

Regarding your presets, what should I change to make it suitable for 4K screens? Your presets work, but the slot mask seems too small and not right for 4K. I like the look of low TVL screens.

2 Likes

Try changing the “CRT Mask Size” to 2 or better. I never viewed my presets in 4k so I don’t know how they look that way or if I’d have to further tweak other parameters to get it looking just right in 4k. Hopefully changing that one parameter will do the trick though.

1 Like

Yoooooo @P-Kong i love that fire emblem screenshot! Holy looks so good! Any chance you could share that preset?

1 Like