CRT-Royale is a highly advanced multi-pass CRT shader that simulates almost every aspect of the CRT screen. There are tons of parameters to configure, such as phosphor type (aperture grille, slot mask, and EDP shadow mask) and size (i.e. dot pitch), convergence offsets, scanline blooming and many others. Higher resolution is better for this shader, especially with EDP shadow mask phosphor layout and with smaller phosphor dot pitch values. This shader is really complicated compared to most other CRT shaders, reading the README and the documentation in the
user-settings.h is a must.
CRT-Royale is a large and complex shader, so it will need modern hardware to run correctly. Discrete Nvidia or AMD video cards made in the last few years are recommended. In particular, Intel iGPUs will struggle to run the shader and some may not even run in some cases. The author provided a preset for Intel users that compromises some functionality for compatibility. There's also various
user-settings.h files in
crt-royale-settings-files that enable/disable options for different GPU profiles.
The display you use for CRT-Royale should have at least 1440p of resolution to give a decent level of detail for slot mask emulation, though 4K (2160p) or higher resolutions are recommended. 1080p displays can work for aperture grille emulation since less resolution is needed to render vertically aligned phosphors.
This shader uses some features in RetroArch's Cg shader format that has only been somewhat recently added since version 184.108.40.206, such as sRGB framebuffers and mipmapping, so you should at least be using RetroArch 1.2 for this shader.
Since CRT-Royale has a large number of different settings for customization, this article will only cover those that have the most noticeable effect on the overall image.
CRT-Royale can be customized one of two ways: using the runtime shader parameters from inside RetroArch or editing the
user-settings.h file. In order for the settings in
user-settings.h that are marked with
_static to take effect, runtime parameters must be disabled by commenting out
#define RUNTIME_SHADER_PARAMS_ENABLE in
user-settings.h. Doing this will make the runtime parameters non-functional so you will need to reload the shader to apply changes made in
user-settings.h, but it will result in a performance boost since there is less need for expensive branching in the shader code when the settings are static.
There are some settings in
user-settings.h that are static only and do not have a runtime parameter, and therefore do not require runtime parameters to be disabled to have an effect.
The settings listed below are taken from the runtime parameters with their default values.
Gamma and Contrast
crt_gamma = 2.500000 lcd_gamma = 2.200000 levels_contrast = 1.000000
Gamma and contrast controls. CRT gamma is the output gamma of the shader, while LCD gamma is the input gamma, which should be 2.4 and 2.2 in most cases, respectively.
Halation and Diffusion
halation_weight = 0.000000 diffusion_weight = 0.075000
Weights for halation and diffusion of the simulated CRT. Halation is the light being reflected on the phosphors, while diffusion is the light causing a glow when passing through the glass. Some may find these effects to be annoying, so they can be turned off by setting them to 0.0.
bloom_underestimate_levels = 0.800000 bloom_excess = 0.000000
These settings control the level of blooming in the shader. Higher
bloom_underestimate will cause the bloom to be more intense on phosphors that are fully lit, which raises the overall brightness of the image and counteracts the loss of brightness caused drawing a phosphor grid over the image.
bloom_excess causes extra blurring of all colors to soften the bloom effect, which is disabled by default.
beam_min_sigma = 0.020000 beam_max_sigma = 0.300000 beam_spot_power = 0.330000 beam_min_shape = 2.000000 beam_max_shape = 4.000000 beam_shape_power = 0.250000 beam_horiz_filter = 0.000000 beam_horiz_sigma = 0.350000 beam_horiz_linear_rgb_weight = 1.000000
These settings determine the shape and size of the lit scanlines of the simulated CRT.
Min and max sigma settings affect the size of each scan line relative to the brightness of the image. A large range of beam sigmas causes the scanlines to vary in width depending on brightness, while small ranges result in a less variable width of scanlines. Higher sigmas increase the size of the scan lines, resulting in smaller gaps and more vertical blurring.
Min and max shape settings affect the Gaussian profile of the scanlines. Higher values for these make the scanline plateaus flatter and have steeper drop-offs. These effects are really only noticeable at higher screen resolutions.
beam_horiz_filter specifies how the beam is filtered horizontally. The options are 0.0 (Quilez, sharp and fast), 1.0 (Gaussian, configurable sharpness), and 2.0 (Lanczos2, sharp and higher quality).
beam_horiz_sigma is used to set the level of blur when using Gaussian horizontal filtering.
convergence_offset_x_r = 0.000000 convergence_offset_x_g = 0.000000 convergence_offset_x_b = 0.000000 convergence_offset_y_r = 0.000000 convergence_offset_y_g = 0.000000 convergence_offset_y_b = 0.000000
The convergence offsets settings specify how well the simulated CRT electron beams are aligned. The default values indicate perfect convergence with no colors that are misaligned. However, real CRTs, particularly cheaper consumer models, very often did not have perfect convergence, so you can change the offsets to simulate that flaw if you want.
mask_type = 1.000000 mask_sample_mode_desired = 0.000000 mask_specify_num_triads = 0.000000 mask_triad_size_desired = 3.000000 mask_num_triads_desired = 480.000000
The mask settings control how the phosphor mask is rendered on the screen.
mask_type specifies which layout of phosphors the screen has. The options for this are 0.0 (Aperture Grille), 1.0 (Slot Mask), and 2.0 (Dot Mask). Aperture Grille phosphor layout is easier to render at lower resolutions, the other options require higher resolutions to render at an acceptable level of detail.
mask_sample_mode_desired specifies the sampling mode of the phosphor mask. The default of 0.0 is the highest quality and slowest method, while 1.0 is lower quality but faster. The 2.0 setting makes the mask tile without resizing, which results in a huge phosphor mask with the default mask textures, so it's intended more for mask textures for a screen of a fixed size.
mask_triad_size_desired specifies the size of each phosphor triad relative to the screen. Smaller triad size will make the simulated CRT like a high-resolution PC CRT or a Sony BVM with increased sharpness and less visible phosphors, while a larger triad size makes the simulated CRT into a low-resolution CRT like many consumer TVs with more blurring and less visible scanline gaps. It's recommended to keep this setting as a whole number since fractional sizes seem to cause scaling artifacts sometimes.
mask_specify_num_triads is set to 1.0, then the phosphor mask will be scaled to use the number of triads specified in
mask_num_triads_desired. This is disabled by default.
Examples of each kind of phosphor style. :
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
These settings affect the anti-aliasing for curvature, overscan, and subpixels that is done to the shader in the last pass. These settings are quite technical and may not have immediately apparent effects. Refer to the documentation in
user-settings.h for detailed explanations.
geom_mode_runtime = 0.000000 geom_radius = 2.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
These are the settings that control the geometry of the simulated CRT.
The geometry modes available are 0.0 (Flat), 1.0 (CRT-Geom style curvature), 2.0 (bulbous curvature), and 3.0 (cylindrical Trinitron curvature). View distance specifies how far the CRT is in the user's field of view. The tilt angle settings control which direction the screen is tilted. The aspect ratio of the simulated screen can also be configured. Overscan affects how much of the image is visible on the simulated CRT since many consumer TVs did not display the full scan area.
Some people may find curvature to be distracting so leaving these settings at default will leave the CRT image perfectly flat.
border_size = 0.015000 border_darkness = 2.000000 border_compress = 2.500000
These settings affect the size and shape of the black border around the CRT. The default settings create a bit of vignetting around the corners; if you dislike this effect, you can set the size and darkness of the border to 0.0.
interlace_bff = 0.000000 interlace_1080i = 0.000000
These settings control how interlacing is handled by the shader. The "bff" setting refers to the order in which each scan line field is displayed, where setting that to 1.0 would make it "bottom field first" as opposed to "top field first" like the default. The 1080i setting specifies whether interlacing is enabled if the input image is 1080 pixels tall, setting it to 1.0 makes it display 1080i instead of 1080p.
Interlacing detection can be turned off entirely by editing
user-settings.h to be
false. This will make it display 480 pixel tall content as 480p instead of 480i, which will eliminate any flickering, but may result in combing artifacts if the game is interlaced natively. This setting is static only and is not a runtime parameter.
A recent version seems to have made this tunable at runtime. This was motivated by user feedback on SNES emulation, where the shader improperly detected interlacing on progressive video.
There are some different variants of the shader provided as different presets. Besides the default
crt-royale.cgp, there is a "fake bloom" preset that uses a much faster bloom method that is lower quality. There are also Intel variants of both the full and fake bloom versions of the shader that omit some features to allow the shader to run on Intel iGPUs. There are also presets with passes of Themaister's NTSC shader applied before the CRT-Royale passes, though this increases the requirements quite a bit.
CRT Royale works best at 2,880 × 2,160 (4K) resolution. That resolution is exactly 9 times 320x240, which was a common resolution for these consoles.