Crt-Royale Kurozumi Edition Help



First I wanted to shout out a big thanks to Kurozumi and HunterK for all their great work on this truly beautiful shader. :slight_smile:

Now on to my (very minor) problem… I’m trying to find the CG version of this shader but I’m not having any luck. I’ve downloaded the latest CG shaders update but even when I perform a search for “kurozumi” within the shaders_cg folder under Windows Explorer I can’t find any files related to this. That being said, I came across a separate “Quick explanation of shaders?” thread that HunterK responded to, in which he stated that CG is being depreciated, so is it possible that the CG version has recently been removed?

Thanks, Visor


It’s still in the Cg shaders:


Hi HunterK,

Thanks; I ended up finding it under …\shaders\shaders_cg\cgp. For some reason my Windows 10 File Manager search option failed to find it, even though it had no problem finding the similar files under the shaders_glsl and shaders_slang folders. Very weird.

Do you recommend the best version of this shader to use, or are they all pretty much identical at this point? I have a GTX 1080 Ti so processing power wouldn’t be an issue.

Also, I’ve been trying to get these shaders to work on FBAlpha for rotated games. I’ve ensured that I’m using integer scaling for both axes. The result is very stripy and uneven as per the example in the link below:

Is this working properly for you, or is this a known issue with rotated screens using FBAlpha?

Thanks, Visor


Vertical games always look weird with it for some reason. I’m not really sure why. I use crt-hyllian instead, which can go vertical without looking wrong.

The Cg version has support for curvature, which I could never get working in the slang/GLSL versions, and the the GLSL version has a weird striping issue with one of the mask_sample_mode settings, but otherwise, they should be similar/the same.


Thanks; I’ve tried out the hyllian shader but I’m not a fan of the grid-like look. I’ll see if I can find some documentation or a forum thread somewhere as to how to turn off the grid.


In the shader set PHOSPHOR to 0.0 instead of 1.0, that ought to do it.


Hi torridgristle,

Thanks for the tip, although I can’t seem to get things working. I opened and found that most of the parameters were commented out (at least that’s what I think the hashtag/# in front of each command means?) There was a parameter called “#define PHOSPHOR 1.0” in the file so I changed it to 0.0 and tried running it with and without the hashtag, but it made no difference. Am I missing something?


You don’t have to go in and do it in the shader. You should be able to change it on-the-fly using the runtime parameters menu. if you really want to change it in the shader, though, look for the line that looks like:

#pragma parameter PHOSPHOR "CRT - Phosphor ON/OFF" 1.0 0.0 1.0 1.0

and change that first 1.0 to 0.0, like this:

#pragma parameter PHOSPHOR "CRT - Phosphor ON/OFF" 0.0 0.0 1.0 1.0


Hi HunterK,

Sorry, but how do I access the runtime parameters menu?

Meanwhile, I made the change to the shader file as you demonstrated (at least temporarily until I figure out this runtime paramters stuff) and things are much more to my liking, thank you. :slight_smile:

Also, I discovered under …\shaders\presets\FB Alpha that there were shader preset files for every game, for example dkong.cgp. I was able to set PHOSPHOR to 0.0 in there, but this is of course not very ideal as I don’t want to have to edit this for each individual game. I don’t want to set this for the core either, as I’m using crt-royale-kurozumi for all my horizontally-oriented arcade games.

Thanks, Visor


With a game loaded, go back into the quick menu, then go to shaders > parameters and it will list all of the things you can change from the menu.

If you want to change it for all of the presets you already have, Notepad++‘s find-and-replace function has a “replace in all open files” option, so you could open all of the vertical games’ presets at once and then replace it in all of them at the same time.


Ahhh thank you, that’s a much better way to do things. I think I remember seeing that parameters menu ages ago, but I’ve totally forgotten that it was there. :stuck_out_tongue:

I’ll give that Notepad++ trick a try if I need to as I build up my vertical game presets.

Thanks a bunch!


This shader is amazing! Combining it with the Mdapt shader to blend dither to produce effects only available on composite would produce the best of both worlds, achieving something that a pure RGB setup cannot.

I tried manually stacking the Kurozumi and Mdapt shaders but it does not seem to work, resulting in no shader effects being displayed at all. Does anyone know the right way to combine multiple shaders in a way that doesn’t break the Kurozumi shader?


Here’s a slang preset for it:

# Shader passes need to know details about the image in the mask_texture LUT
# files, so set the following constants in user-cgp-constants.h accordingly:
# 1.) mask_triads_per_tile = (number of horizontal triads in mask texture LUT's)
# 2.) mask_texture_small_size = (texture size of mask*texture_small LUT's)
# 3.) mask_texture_large_size = (texture size of mask*texture_large LUT's)
# 4.) mask_grille_avg_color = (avg. brightness of mask_grille_texture* LUT's, in [0, 1])
# 5.) mask_slot_avg_color = (avg. brightness of mask_slot_texture* LUT's, in [0, 1])
# 6.) mask_shadow_avg_color = (avg. brightness of mask_shadow_texture* LUT's, in [0, 1])
# Shader passes also need to know certain scales set in this .slangp, but their
# compilation model doesn't currently allow the .slangp file to tell them.  Make
# sure to set the following constants in user-cgp-constants.h accordingly too:
# 1.) bloom_approx_scale_x = scale_x2
# 2.) mask_resize_viewport_scale = float2(scale_x6, scale_y5)
# Finally, shader passes need to know the value of geom_max_aspect_ratio used to
# calculate scale_y15 (among other values):
# 1.) geom_max_aspect_ratio = (geom_max_aspect_ratio used to calculate scale_y5)

shaders = "17"

# Set an identifier, filename, and sampling traits for the phosphor mask texture.
# Load an aperture grille, slot mask, and an EDP shadow mask, and load a small
# non-mipmapped version and a large mipmapped version.
# TODO: Test masks in other directories.
textures = "mask_grille_texture_small;mask_grille_texture_large;mask_slot_texture_small;mask_slot_texture_large;mask_shadow_texture_small;mask_shadow_texture_large"
mask_grille_texture_small = "../crt/shaders/crt-royale/TileableLinearApertureGrille15Wide8And5d5SpacingResizeTo64.png"
mask_grille_texture_large = "../crt/shaders/crt-royale/TileableLinearApertureGrille15Wide8And5d5Spacing.png"
mask_slot_texture_small = "../crt/shaders/crt-royale/TileableLinearSlotMaskTall15Wide9And4d5Horizontal9d14VerticalSpacingResizeTo64.png"
mask_slot_texture_large = "../crt/shaders/crt-royale/TileableLinearSlotMaskTall15Wide9And4d5Horizontal9d14VerticalSpacing.png"
mask_shadow_texture_small = "../crt/shaders/crt-royale/TileableLinearShadowMaskEDPResizeTo64.png"
mask_shadow_texture_large = "../crt/shaders/crt-royale/TileableLinearShadowMaskEDP.png"
mask_grille_texture_small_wrap_mode = "repeat"
mask_grille_texture_large_wrap_mode = "repeat"
mask_slot_texture_small_wrap_mode = "repeat"
mask_slot_texture_large_wrap_mode = "repeat"
mask_shadow_texture_small_wrap_mode = "repeat"
mask_shadow_texture_large_wrap_mode = "repeat"
mask_grille_texture_small_linear = "true"
mask_grille_texture_large_linear = "true"
mask_slot_texture_small_linear = "true"
mask_slot_texture_large_linear = "true"
mask_shadow_texture_small_linear = "true"
mask_shadow_texture_large_linear = "true"
mask_grille_texture_small_mipmap = "false"  # Mipmapping causes artifacts with manually resized masks without tex2Dlod
mask_grille_texture_large_mipmap = "true"   # Essential for hardware-resized masks
mask_slot_texture_small_mipmap = "false"    # Mipmapping causes artifacts with manually resized masks without tex2Dlod
mask_slot_texture_large_mipmap = "true"     # Essential for hardware-resized masks
mask_shadow_texture_small_mipmap = "false"  # Mipmapping causes artifacts with manually resized masks without tex2Dlod
mask_shadow_texture_large_mipmap = "true"   # Essential for hardware-resized masks

shader0 = ../dithering/shaders/mdapt/passes/mdapt-pass0.slang
filter_linear0 = false
scale_type0 = source
scale0 = 1.0

shader1 = ../dithering/shaders/mdapt/passes/mdapt-pass1.slang
filter_linear1 = false
scale_type1 = source
scale1 = 1.0

shader2 = ../dithering/shaders/mdapt/passes/mdapt-pass2.slang
filter_linear2 = false
scale_type2 = source
scale2 = 1.0

shader3 = ../dithering/shaders/mdapt/passes/mdapt-pass3.slang
filter_linear3 = false
scale_type3 = source
scale3 = 1.0

shader4 = ../dithering/shaders/mdapt/passes/mdapt-pass4.slang
filter_linear4 = false
scale_type4 = source
scale4 = 1.0

# Pass0: Linearize the input based on CRT gamma and bob interlaced fields.
# (Bobbing ensures we can immediately blur without getting artifacts.)
shader5 = "../crt/shaders/crt-royale/src/crt-royale-first-pass-linearize-crt-gamma-bob-fields.slang"
filter_linear5 = "false"
scale_type5 = "source"
scale5 = "1.0"
srgb_framebuffer5 = "true"

# Pass1: Resample interlaced (and misconverged) scanlines vertically.
# Separating vertical/horizontal scanline sampling is faster: It lets us
# consider more scanlines while calculating weights for fewer pixels, and
# it reduces our samples from vertical*horizontal to vertical+horizontal.
# This has to come right after ORIG_LINEARIZED, because there's no
# "original_source" scale_type we can use later.
shader6 = "../crt/shaders/crt-royale/src/crt-royale-scanlines-vertical-interlacing.slang"
filter_linear6 = "true"
scale_type_x6 = "source"
scale_x6 = "1.0"
scale_type_y6 = "viewport"
scale_y6 = "1.0"
#float_framebuffer6 = "true"
srgb_framebuffer6 = "true"

# Pass2: Do a small resize blur of ORIG_LINEARIZED at an absolute size, and
# account for convergence offsets.  We want to blur a predictable portion of the
# screen to match the phosphor bloom, and absolute scale works best for
# reliable results with a fixed-size bloom.  Picking a scale is tricky:
# a.) 400x305 is a good compromise for the "fake-bloom" version: It's low enough
#     to blur high-res/interlaced sources but high enough that resampling
#     doesn't smear low-res sources too much.
# b.) 320x245 works well for the "real bloom" version: It's 1-1.5% faster, and
#     the only noticeable visual difference is a larger halation spread (which
#     may be a good thing for people who like to crank it up).
# Note the 4:8 aspect ratio assumes the input has cropped geom_overscan (so it's
# *intended* for an ~4:8 aspect ratio).
shader7 = "../crt/shaders/crt-royale/src/crt-royale-bloom-approx.slang"
alias7 = "BLOOM_APPROX"
filter_linear7 = "true"
scale_type7 = "absolute"
scale_x7 = "320"
scale_y7 = "240"
srgb_framebuffer7 = "true"

# Pass3: Vertically blur the input for halation and refractive diffusion.
# Base this on BLOOM_APPROX: This blur should be small and fast, and blurring
# a constant portion of the screen is probably physically correct if the
# viewport resolution is proportional to the simulated CRT size.
shader8 = "../blurs/blur5fast-vertical.slang"
filter_linear8 = "true"
scale_type8 = "source"
scale8 = "1.0"
srgb_framebuffer8 = "true"

# Pass4: Horizontally blur the input for halation and refractive diffusion.
# Note: Using a one-pass 9x19 blur is about 1% slower.
shader9 = "../blurs/blur5fast-horizontal.slang"
alias9 = "HALATION_BLUR"
filter_linear9 = "true"
scale_type9 = "source"
scale9 = "1.0"
srgb_framebuffer9 = "true"

# Pass5: Lanczos-resize the phosphor mask vertically.  Set the absolute
# scale_x15 == mask_texture_small_size.x (see IMPORTANT above).  Larger scales
# will blur, and smaller scales could get nasty.  The vertical size must be
# based on the viewport size and calculated carefully to avoid artifacts later.
# First calculate the minimum number of mask tiles we need to draw.
# Since curvature is computed after the scanline masking pass:
#   num_resized_mask_tiles = 2.0;
# If curvature were computed in the scanline masking pass (it's not):
#   max_mask_texel_border = ~3.5 * (1/3.5 + 4.0*sqrt(2.0) + 0.15 + 1.0);
#   max_mask_tile_border = max_mask_texel_border/
#       (min_resized_phosphor_triad_size * mask_triads_per_tile);
#   num_resized_mask_tiles = max(2.0, 1.5 + max_mask_tile_border * 2.0);
#   At typical values (triad_size >= 2.0, mask_triads_per_tile == 8):
#       num_resized_mask_tiles = ~3.8
# Triad sizes are given in horizontal terms, so we need geom_max_aspect_ratio
# to relate them to vertical resolution.  The widest we expect is:
#   geom_max_aspect_ratio = 4.0/3.5  # Note: Shader passes need to know this!
# The fewer triads we tile across the screen, the larger each triad will be as a
# fraction of the viewport size, and the larger scale_y15 must be to draw a full
# num_resized_mask_tiles.  Therefore, we must decide the smallest number of
# triads we'll guarantee can be displayed on screen.  We'll set this according
# to 3-pixel triads at 768p resolution (the lowest anyone's likely to use):
#   min_allowed_viewport_triads = 768.0*geom_max_aspect_ratio / 3.5 = 341.333333
# Now calculate the viewport scale that ensures we can draw resized_mask_tiles:
#   min_scale_x = resized_mask_tiles * mask_triads_per_tile /
#       min_allowed_viewport_triads
#   scale_y15 = geom_max_aspect_ratio * min_scale_x
#   # Some code might depend on equal scales:
#   scale_x16 = scale_y5
# Given our default geom_max_aspect_ratio and min_allowed_viewport_triads:
#   scale_y15 = 4.0/3.5 * 2.0/(341.33338 / 8.0) = 0.0625
# IMPORTANT: The scales MUST be calculated in this way.  If you wish to change
# geom_max_aspect_ratio, update that constant in user-cgp-constants.h!
shader10 = "../crt/shaders/crt-royale/src/crt-royale-mask-resize-vertical.slang"
filter_linear10 = "true"
scale_type_x10 = "absolute"
scale_x10 = "64"
scale_type_y10 = "viewport"
scale_y10 = "0.0625" # Safe for >= 341.338 horizontal triads at viewport size
#srgb_framebuffer10 = "false" # mask_texture is already assumed linear

# Pass6: Lanczos-resize the phosphor mask horizontally.  scale_x16 = scale_y5.
# TODO: Check again if the shaders actually require equal scales.
shader11 = "../crt/shaders/crt-royale/src/crt-royale-mask-resize-horizontal.slang"
alias11 = "MASK_RESIZE"
filter_linear11 = "false"
scale_type_x11 = "viewport"
scale_x11 = "0.0625"
scale_type_y11 = "source"
scale_y11 = "1.0"
#srgb_framebuffer11 = "false" # mask_texture is already assumed linear

# Pass7: Resample (misconverged) scanlines horizontally, apply halation, and
# apply the phosphor mask.
shader12 = "../crt/shaders/crt-royale/src/crt-royale-scanlines-horizontal-apply-mask.slang"
filter_linear12 = "true" # This could just as easily be nearest neighbor.
scale_type12 = "viewport"
scale12 = "1.0"
#float_framebuffer12 = "true"
srgb_framebuffer12 = "true"

# Pass 8: Compute a brightpass.  This will require reading the final mask.
shader13 = "../crt/shaders/crt-royale/src/crt-royale-brightpass.slang"
alias13 = "BRIGHTPASS"
filter_linear13 = "true" # This could just as easily be nearest neighbor.
scale_type13 = "viewport"
scale13 = "1.0"
srgb_framebuffer13 = "true"

# Pass 9: Blur the brightpass vertically
shader14 = "../crt/shaders/crt-royale/src/crt-royale-bloom-vertical.slang"
filter_linear14 = "true" # This could just as easily be nearest neighbor.
scale_type14 = "source"
scale14 = "1.0"
srgb_framebuffer14 = "true"

# Pass 10: Blur the brightpass horizontally and combine it with the dimpass:
shader15 = "../crt/shaders/crt-royale/src/crt-royale-bloom-horizontal-reconstitute.slang"
filter_linear15 = "true"
scale_type15 = "source"
scale15 = "1.0"
srgb_framebuffer15 = "true"

# Pass 11: Compute curvature/AA:
shader16 = "../crt/shaders/crt-royale/src/crt-royale-geometry-aa-last-pass.slang"
filter_linear16 = "true"
scale_type16 = "viewport"
mipmap_input16 = "true"
texture_wrap_mode16 = "clamp_to_edge"

parameters = "crt_gamma;lcd_gamma;levels_contrast;halation_weight;diffusion_weight;bloom_underestimate_levels;bloom_excess;beam_min_sigma;beam_max_sigma;beam_spot_power;beam_min_shape;beam_max_shape;beam_shape_power;beam_horiz_filter;beam_horiz_sigma;beam_horiz_linear_rgb_weight;convergence_offset_x_r;convergence_offset_x_g;convergence_offset_x_b;convergence_offset_y_r;convergence_offset_y_g;convergence_offset_y_b;mask_type;mask_sample_mode_desired;mask_specify_num_triads;mask_triad_size_desired;mask_num_triads_desired;aa_subpixel_r_offset_x_runtime;aa_subpixel_r_offset_y_runtime;aa_cubic_c;aa_gauss_sigma;geom_mode_runtime;geom_radius;geom_view_dist;geom_tilt_angle_x;geom_tilt_angle_y;geom_aspect_ratio_x;geom_aspect_ratio_y;geom_overscan_x;geom_overscan_y;border_size;border_darkness;border_compress;interlace_bff;interlace_1080i"
crt_gamma = "2.400000"
lcd_gamma = "2.400000"
levels_contrast = "0.740000"
halation_weight = "0.004600"
diffusion_weight = "0.001000"
bloom_underestimate_levels = "0.800000"
bloom_excess = "0.000000"
beam_min_sigma = "0.020000"
beam_max_sigma = "0.200000"
beam_spot_power = "0.370000"
beam_min_shape = "2.000000"
beam_max_shape = "4.000000"
beam_shape_power = "0.250000"
beam_horiz_filter = "0.000000"
beam_horiz_sigma = "0.545000"
beam_horiz_linear_rgb_weight = "1.000000"
convergence_offset_x_r = "-0.050000"
convergence_offset_x_g = "0.000000"
convergence_offset_x_b = "0.000000"
convergence_offset_y_r = "0.100000"
convergence_offset_y_g = "-0.050000"
convergence_offset_y_b = "0.100000"
mask_type = "0.000000"
mask_sample_mode_desired = "0.000000"
mask_specify_num_triads = "0.000000"
mask_triad_size_desired = "1.000000"
mask_num_triads_desired = "900.000000"
aa_subpixel_r_offset_x_runtime = "-0.333333"
aa_subpixel_r_offset_y_runtime = "0.000000"
aa_cubic_c = "0.500000"
aa_gauss_sigma = "0.500000"
geom_mode_runtime = "0.000000"
geom_radius = "3.000000"
geom_view_dist = "2.000000"
geom_tilt_angle_x = "0.000000"
geom_tilt_angle_y = "0.000000"
geom_aspect_ratio_x = "432.000000"
geom_aspect_ratio_y = "329.000000"
geom_overscan_x = "1.000000"
geom_overscan_y = "1.000000"
border_size = "0.005000"
border_darkness = "0.000000"
border_compress = "2.500000"
interlace_bff = "0.000000"
interlace_1080i = "0.000000"

Just copy this into a text file and name it something like “mdapt-royale-kurozumi.slangp” and put it in your ‘presets’ directory.


Thanks hunterk!

Is there a trick to combining shaders in a preset like that? I noticed that the preset you wrote there not only numbers each shader (shader0, shader1, etc.) but also numbers each of the settings for each shader (scale0, scale1, etc.). I’m guessing that’s what was missing when I attempted to do it manually, but I imagine it would be too tedious to number each setting like that, so I’m wondering if you did it in a way that makes it easier.


using find-and-replace in a text editor, you can start at the end and add as many passes as you need and then work your way backwards. So, in this case, I needed to add 5 passes, so I f-a-r for '12 ’ (that’s twelve and a space) for '17 ’ (that’s seventeen and a space) and then do the same for '11 ’ to '16 ', rinse and repeat.

Still pretty tedious, but not that bad.

And yes, you need to change all of the associated settings to keep them in line with their correct pass.


That makes sense. I guess it’s not so bad doing it that way. Thanks for taking the time to help me out with this, hunterk!

Hopefully future versions of Retroarch introduce a way to make shader stacking more convenient. I think combining shader presets like this is the future. With higher resolution and faster refresh rate monitors (and more powerful GPUs to drive them), maybe we’re just a few years away from a solution that fully surpasses in every aspect even the best CRTs ever made.


Hi, to have the GLSL version of this preset, I just need to replace all the Slang extension by Glsl ?


No, you need to download the GLSL shaders by using “Online updater” -> “Update GLSL shaders” and then select the shader from the GLSL directory.


find-and-replace .slang with .glsl and rename it to *.glslp and drop it into your glsl shaders’ “presets” directory and yeah, you should be good.


Thanks Hunterk and Tromzy