This is a port of the crt-royale shader by TroggleMonkey from libretro to ReShade 4.8.3+.
The vast majority of the code here is taken from the current libretro shader repositories, so the most of the credit goes to those authors.
libretro/glsl-shaders
libretro/slang-shaders
Special thanks goes to Matsilagi for his time, suggestions, testing, debugging, and enthusiasm. It's been tremendously helpful, especially in figuring out some of the nastier bugs. Also thank you Crosire and co. for their work on ReShade, particularly for adding support for rectangular matrices and for ReShade's built-in debugging tools. Those features made this project orders of magnitude easier.
This shader should work with DX9, DX10/11/12, OpenGL, and Vulkan. It'll probably spit out a bunch of yellow error messages in DX9, but that's okay.
Matsilagi/RSRetroArch - Matsilagi has a chunk of other RetroArch shaders ported over here already. The PAL and NTSC shaders are particularly useful (load them before crt-royale).
-
This shader requires ReShade 4.9+. It requires rectangular matrix multiplication that Crosire added in 4.9. I recommend you calibrate your display's gamma and sharpness. You can use the tests from http://www.lagom.nl/lcd-test/ to do that.
-
The libretro implementation of crt-royale has the luxury of having the game's true viewport passed directly to it. The ReShade implementation by nature does not. This means the ReShade version by default grabs any letter-boxing as part of its input, and that throws off its geometry and phosphor calculations.
To help with this, I've added a "debug mode" of sorts. You can enable it by setting
CONTENT_BOX_VISIBLE
to1
in the global preprocessor definitions section of the ReShade UI. This will disable the main pipeline and swap to one that draws a box around the screen. UseCONTENT_HEIGHT
andCONTENT_WIDTH
to change the box's dimensions in pixels. UseCONTENT_CENTER_X
andCONTENT_CENTER_Y
to move the box left, right, up, or down as needed. ToggleCONTENT_BOX_INSCRIBED
to switch between drawing the box inside the viewport or drawing outside the viewport. And useCONTENT_BOX_THICKNESS
and theCONTENT_BOX_COLOR
settings to change the thickness and color of the box's lines, just in case the defaults aren't visible enough.Once you've got the box aligned, you can switch off
CONTENT_BOX_VISIBLE
; and the main pipeline will use your settings to draw everything correctly.Be aware that, if you resize the game's viewport, you'll probably have to readjust these settings. You can mitigate this by defining
CONTENT_WIDTH
andCONTENT_HEIGHT
algebraically in terms ofBUFFER_WIDTH
andBUFFER_HEIGHT
, but you'll have to figure out the expressions for that on a case by case basis. As an example, if you know the content has a 4:3 aspect ratio and fills the screen vertically, you can defineCONTENT_HEIGHT
asBUFFER_HEIGHT
andCONTENT_WIDTH
asCONTENT_HEIGHT * 4.0 / 3.0
. -
Focus primarily on setting the
Mask Type
,Mask Sample Mode
, andMask Triad Width
. Sample Mode "Smooth" tends to be smoother but dimmer, while Mode "Sharp" tends to be sharper and brighter but more prone to artifacts. You'll usually get the best results with triad sizes 3, 6, 9, etc. Multiples of 0.5 also seem to work fairly well, but they might cause color issues. If you're using DX9, the Mask Type is set by a preprocessor definitionphosphor_mask_type
instead of a slider. Valid values for that are 0, 1, and 2 or "GRILLE", "SLOT", and "SHADOW". -
Use the
USE_LARGE_PHOSPHOR_MASK
preprocessor definition to fix some artifacting with the phosphor mask. If you want a triad size larger than 8, you must setUSE_LARGE_PHOSPHOR_MASK
to 1, or you will get artifacts. If you have artifacting or color issues with a triad size of 3-8, try settingUSE_LARGE_PHOSPHOR_MASK
to 0. -
Use
Enable Interlacing
to toggle all things interlacing. This replaces all of the autodetection logic, so you have complete control over it now. UseScanline Thickness
to control the thickness of the scanlines in pixels. If you have problems with your framerate or skipped frames that cause the video to freeze and jitter, useScanline Blend Strength
to smooth it out. Setting it to 0 will replicate the original crt-royale behavior, while setting it to 1 will blend the current and previous frames together. At 60 fps, the video should look nearly identical no matter what you set the blend strength to. If the colors are distorted, nudgeScanline Blend Gamma
a little until the colors look right. -
Geom Mode, Geom Radius, and the
antialias_level
preprocessor definition are worth playing with; but I strongly recommend settingCONTENT_HEIGHT
andCONTENT_WIDTH
first. Meaningful values forantialias_level
are 0, 1, 5, 6, 7, 8, 12, 16, 20, and 24. Values in between these will be rounded down.
For the most part, configuring this implementation of crt-royale should be the same as configuring the libretro versions, so refer to any past experience or to the existing documentation for help with that. I've left almost all of the code's comments intact, so you can also scroll through that for descriptions of the various preprocessor definitions. You should be able to find all of them in user-settings.fxh
, derived-settings-and-constants.fxh
, bind-shader-params.fxh
, and shared-objects.fxh
. The main difference is that you configure many preprocessor definitions by setting them to integer values rather than just defining them. This is to let users set them from ReShade's UI instead of editing the source code.
There are a handful of notable differences:
-
Mask Sample Mode "Smooth" has a new setting
Downsampling Sharpness
. You can use it to make Mode "Smooth" look more similar to Mode "Sharp" if you prefer something in between. I find this particularly useful for the Shadow mask. -
The scanline logic is now user-toggleable instead of autodetected, and you can change the thickness of the scanlines if you want. You can now enable frame blending to smooth out VSync artifacting.
-
In DX9, the Mask Type is set by a preprocessor definition
phosphor_mask_type
. It can be either 0 for the Grille mask, 1 for the Slot mask, or 2 for the Shadow mask. You can also type "GRILLE", "SLOT", or "SHADOW" if you prefer. -
PHOSPHOR_BLOOM_TRIADS_LARGER_THAN_3_PIXELS
and its siblings are still present. You can choose one or none of them by settingPHOSPHOR_BLOOM_TRIAD_SIZE_MODE
to a value in range[0 - 4]
. This is defined inuser-settings.fxh
. -
The same is true for
SIMULATE_CRT_ON_LCD
and its siblings. SetGAMMA_SIMULATION_MODE
to[0 - 4]
to control which of those is active. This is defined inderived-settings-and-constants.fxh
. -
Most of the "RUNTIME_...", "ANISOTROPIC_...", "DRIVERS_ALLOW_...", and other performance-related preprocessor definitions are either hidden from the UI or gone. Some of them are extremely difficult to port correctly. Some of them either don't do anything anymore or never did anything to begin with. And some of them I'll be adding back later, but I'll have to refactor them and the affected code to make them more user-friendly.
-
I've disabled many of the beam settings due to my rewrite of the scanline logic. They currently are unused.
-
I've exposed
antialias_filter
,antialias_level
, andantialias_temporal
as preprocessor definitions. Note that the code dedicated to havingantialias_level
set to4
is disabled for now because it's currently broken.
Please be aware that, because ReShade and RetroArch shaders work so differently, it won't be possible to replicate the libretro version's output perfectly. There simply are too many low-level differences in too many bits of math to achieve a pixel-perfect port, especially now that I've rewritten the scanline logic to be variable-width. That being said, you should be able to get pretty darn close.
Obviously my top-priority is to make sure there aren't any breaking issues. If a configuration completely breaks the shader or crashes the game, I need to know about it. Similarly, if there's a configuration that runs well in RetroArch but is unplayably laggy in ReShade, I need to know about it. The same is true for configurations that completely screw up color balance in some stupid way (e.g. setting the Scanline Width to 2 used to throw off the brightness/gamma horribly, but 1 and 3+ were alright). Discrepancies that I won't be able to fix include occassional crushing in shadows, the bloom effect being more potent in places, or the scanlines being slightly different. These go back to limitations of ReShade and those aforementioned functional differences.