Universal Shader

It’s time to present my work. It’s been in development for quite some time, and this is the first release of my main work. In fact, there are at least two works I’ve done in recent years. I decided to publish them because I undoubtedly need the community to evaluate my work and share impressions and reviews. Over time, I’ve seen, tested, and evaluated the most popular presets in the scene, and I thought I could give my opinion. These shaders have been taken and extensively modified, almost completely, with the help of AI. The scanline generator, like perhaps others, were even created from scratch and with the help of generic, free AI. The goal was to create an extremely lightweight shader capable of running on any machine. My reference hardware, an AmLogic S905x3, runs this shader without any problems, and with plenty of GPU headroom. At the same time, I wanted to recreate a truly unique feel combined with complete customization. The result I achieved was based on the perception of the final result, and not on rigorous mathematical calculations. I present my Universal Shader here, along with an explanation of the individual parameters for ease of use. I also attach an explanation of how the whole thing works. As mentioned before, the shader is in glslp format, and I tested it on my reference hardware, an AmLogic S905x3. It obviously works great on PC too. I use a 1080p monitor without HDR or anything special; a perfectly normal monitor. Therefore, I recommend a 1080p resolution, simply because I’ve never tried it at other resolutions. To give you an idea, the GPU on my reference hardware is about 10 times less powerful than the old Intel HD4600 integrated graphics from almost twenty years ago, and as mentioned previously, I still have some headroom on the GPU in my S905x3. My second project, which I’ll probably post in another thread, aims for even better rendering, but with a fraction of the resources of the Universal Shader.

Thanks to my research into how CRTs work, the Universal Shader passes the three most demanding tests of modern shaders with flying colors.

Sonic Falls The Earthworm Jim screenshot The Vectorman intro

In addition to obviously delivering sharp rendering with very few parameter changes. I tried shaders for dithering, but while they worked well on the pattern, most reduced overall detail; this was too great a compromise, as in some cases the loss of detail was significant. The Universal Shader can blend the pattern of the three aforementioned games without blurring the image too much. You’ll notice that while it provides a convincing transparency effect on certain Mega Drive games, the image isn’t blurred too much.

To adjust the “blending” of the dithering pattern, or even more simply if we just want a less precise look, we need to adjust the X-axis values ​​for each RGB color channel of the noise filter. The Y-axis values ​​can remain very low, around 0.02. Why only on the X-axis? The CRT cannon sweeps from left to right across the screen, moving down one line of resolution each time. While the transition between the lines (Y-axis) is quite sharp and defined by the game’s vertical resolution (value 0.02), for horizontal movement (X-axis), the pixel’s dwell time depends heavily on the video signal, which could mix the values ​​as the brush sweeps along the X-axis. Remember that the brush always moves horizontally! For this reason, the shader value along the X-axis of the three primary colors is a fundamental parameter for determining the sharpness or blending of the pattern’s colors. By increasing the values ​​for the X-axis of the noise shader, we increase the blending and merging of adjacent pixels along the axis.

:video_game: Universal Shader Preset – CRT Emotion, Reimagined

After months of experimentation and fine-tuning, I’ve created a RetroArch shader preset that captures the warm, organic, and imperfect feel of old CRT televisions — while adding a modern touch and full customization.

This is not just a filter: it’s a creative tool for anyone who wants full control over the look of their retro games.

:mag: Preset Overview

This preset is made of 5 chained shaders , executed in sequence:

  1. Image Adjustment – global gamma, brightness, contrast, and saturation.
  2. Candy Bloom – soft glow effect, similar to a luminous halo.
  3. Film Noise – cinematic grain and subtle chromatic aberration.
  4. Frame Overlay – curved bezel with rounded corners and fade-to-black edges.
  5. Dynamic Dotmask – advanced CRT phosphor emulation with per-channel dynamic expansion .

The result is an image that looks like it’s being played on an old cathode ray tube, but with the quality and depth only a modern shader can provide.

:zap: Lightweight & Fast – Even on an S905X3

Despite its complexity, this shader preset is extremely lightweight .

:white_check_mark: No heavy post-processing :white_check_mark: No expensive multiple passes :white_check_mark: No high-resolution framebuffers

All effects are applied in a single pass per shader , with simple arithmetic operations. It runs smoothly even on low-power devices like the Amlogic S905X3 (used in many TV boxes and handhelds like the Super Console X, X96 Air, etc.).

:bulb: You can expect full speed even on demanding emulators (PS1, N64, Dreamcast) on S905X3-based devices.

:sparkles: What Makes This Preset Unique?

:brain: Dynamic Per-Channel Phosphor Expansion

Unlike classic CRT masks (Lottes, aperture grille, etc.), here each phosphor (R, G, B) expands independently based on the original color intensity. A bright red pixel will only expand the red phosphor, and so on.

Additionally, vertical expansion can be centered (simulating a cathode ray expanding from the center of the screen) or traditional (bottom-up).

:art: Smooth Fade-to-Black Frame

The frame isn’t just a black border. It fades smoothly toward the image with a customizable fade curve (from linear to high-power curves). This creates a very cinematic “fade to black” effect.

:rainbow: Adjustable Chromatic Aberration

Red, green, and blue channels can be independently shifted horizontally and vertically, creating the typical misalignment of old tubes or film stock.

:jigsaw: Technical Breakdown of Each Shader

:one: image-adjustment.glsl – Base Correction

Parameter Effect
Gamma Correction Expands or compresses mid-tones. <1 darkens mid-tones, >1 lightens them.
Brightness Shifts the whole image toward white (>0) or black (<0).
Contrast Increases or decreases the difference between light and dark areas.
Saturation Controls color intensity. 0 = grayscale, >1 = saturated colors.

:two: Candy-Bloom.glsl – Glow Effect

Parameter Effect
Glow Level Overall glow intensity.
Glow Tightness How tightly the glow follows bright areas. Low = diffused glow, high = concentrated glow.

:three: film_noise.glsl – Grain & Chromatic Aberration

Parameter Effect
X/Y Offset Red/Green/Blue Independent shift of the three color channels (chromatic aberration).
Grain Strength Intensity of the cinematic grain. Higher = dirtier look.

:four: overlay.glsl – Curved & Faded Frame

Parameter Effect
Enable Frame Enables/disables the frame overlay.
Frame Size % Thickness of the frame relative to the screen’s smallest dimension.
Curve Amount How much the sides curve inward.
Corner Radius % Roundness of the corners.
Fade Width % Width of the transition zone between image and black frame.
Fade Curve Shape of the transition. 1 = linear, >1 = steeper curve toward the image.

:five: dotmask.glsl – The Heart of the CRT Effect (:star: Emphasis)

This is the most important shader in the chain. It simulates the actual phosphor grid of a CRT.

Parameter Effect
Phosphor Intensity How much the CRT mask affects the final image.
Black between Phosphors Amount of black space between phosphors (simulates the dark grille).
Mask Light / Dark Maximum and minimum brightness of lit/unlit phosphors.
Grid Columns / Rows Number of columns and rows in the phosphor grid.
Vertical Stagger Row shifting effect (typical of shadow mask CRTs).
Horizontal Expansion How much color intensity widens the phosphor horizontally.
Min / Max Width Minimum and maximum phosphor width (as a fraction of the cell).
Vertical Expansion How much color intensity widens the phosphor vertically.
Min / Max Height Minimum and maximum phosphor height.
Vertical Center Expansion Key parameter : 0 = expansion from the bottom, 1 = symmetrical expansion from the center (simulates a beam originating from the center of the screen).

:brain: Why is this unique? Most CRT shaders use a static mask . Here, the mask is dynamic and per-channel . A bright red pixel will literally “grow” only the red phosphor. This creates a much more organic, responsive CRT feel.

:framed_picture: Visual Example (imaginary)

“With this preset, 8/16-bit games feel alive. The reds in Super Mario World’s title pulse, the blues in Sonic shine without washing out, and the grain adds a cinematic depth that no clean filter can match.”

4 Likes

Continue your good work; always remember that AI delivers impressive results. Leverage this free intelligence and achieve your vision. I believe your next step is to create NTSC artifact shading.

Thank’s; absoutely yes…AI changes posssibilies and horizon of what we can achieve. Also had to say that i’m challenging hardware limit as my reference is the S905x3 AmLogic chip. i’ts important to put limits for to challemge results. Say that i’ve quiet room in the GPU for to inprove. Do not know if You have tested this shader; this topic is also for test and feeedback. Now i’m wondering if i was released the version whitin “Lottes pixel” logic or not. By the way updates are planned…

Don’t know if considerer an NTSC filter, but in the work i’ve another shader that need a fraction of resources compare to Universal, and if my work goes well, the result can be better than this. This other shader can replicate the sensation to be in front a real CRT by distorting the scanlines and recreate the tipical disturb we can witness on real thing, to put an emphasis on perception instead of real complex calculation.

Universal shader put emphasis on the perception of the image and are not considered fixed or complicated matemathics calculation and beside that do not disfigure side by side the best and complex shaders on this channel.

Hope this Universal Shader can be popular, and many can test different setup by posting demonstrative screenshot.

1 Like

One tiny bit of constructive criticism, please update the title. It doesn’t reflect the effort you posted in the op. Emojis, code section :exploding_head:

Ok…accept the critisicm, but, let’s see Your shader proposal… Try to criticize on the merits, otherwise it is gratuitous criticism… try to state the areas that don’t convince you.

It’s okay to be proud of what you have achieved, even if it was with the help of AI. However, you should avoid blowing your own trumpet, “passes with flying colors” is something that others should judge.

My honest opinion
The shader has basically no performs impact and exposes all the parameters of the effects it provides for customization. But the overall look does not appeal to me. In general the screenshots you shown are too blurry and too dark. There is no real scanlines simulation, the scanlines are kinda mimicked by the slot mask pattern, that does not align the with the raw pixel rows and therefore contributes to the blurriness.

Personally, I think it is quite overconfident of you to name the shader “Universal”. There are already other equally fast shaders that provide similar features but execute them better.

3 Likes

The documentation is also AI generated, so the hyperbole and self-congratulatory nature of it is par for the course.

2 Likes

Actually this shader could become “so bad it’s good” with some touches, correcting some monstrous errors AI created. Lots of people like blurry-mess (not faithful to a CRT is a good bonus, scrolling scanlines, 2 cm/1 inch deconvergence and all) shaders like new-pixie etc. I mean at least do some tricks to keep some brightness so one can see without using a flashlight

1 Like

A quick test, 32 stripes of colors should be there, all details - dark and bright are totally crashed. Annihilated, burned then ashes thrown to nearest river.

2 Likes

Hey, coming back to this. My first comment was snarky, my bad.

One thing I do like: you used arrows and boxes in your screenshots to point stuff out. That’s actually really helpful for shader threads. Just a heads up, some of them are missing those marks. Keeping it consistent would make it even better.

For the title, maybe something like ‘SoC-Friendly Universal Shader’? That way people know right away it runs well on low-end hardware, which seems like your biggest win here.

1 Like

yuzuqailo, you don’t need to apologize. More than anything, compared to the other users who commented, I don’t know what to say. The name Universal Shader wasn’t meant to offend or upset any of your expectations. It’s just a name. However, I want to point out that the shader is fully adjustable, both in brightness and sharpness. I also want to point out, as I wrote, that the reference hardware is an S905X3 with a GPU that, to give you an idea, is 210 times inferior to a GTX 1050. Probably, if I hadn’t set limits, I could have achieved better results. But the triode amplitude modulation on a GPU like that, combined with all the other adjustments, I think is a great achievement. I’m sorry that a user used a suite without even touching any parameters, just to make my work look bad. I’m sorry, but it’s not right, especially from a long-time member of this forum like you. I only needed two adjustments and everything was fine. My preset isn’t intended to be sharp, but it’s obvious that some adjustment is needed for monitors other than mine, or simply to suit your tastes. That said, updates are in the works.

Why people don’t just use zfast-crt or something and ask AI for miracles is beyond me. Isn’t zfast-crt working well on that chip? I bet it is. It’s a fantastic shader as far as “fast” shaders go.

1 Like

Added the “ROUNDNESS” option to round the vertical triode bars.

The new file was simply overwritten, so the link is the same as at the beginning of this topic. I’m still working on/understanding the optimal parameters for this last option. I remember using a standard 1080p monitor without HDR for my tests. From the attached photos, you can see the triode bars rounded and soft at the edges. I’m looking for the right parameters to stretch and join the triodes vertically when the brightness is very high without creating artifacts. For optimal viewing, I recommend downloading the image and viewing it locally on your PC. Resizing the preview may darken or create artifacts in the image.

1 Like

I hear your point on zfast-crt being a reliable standard for performance, and I respect that. My intention wasn’t to dismiss legacy shaders, but rather to highlight the gap between ‘fast’ solutions and the more complex CRT simulations that many users are looking for. While zfast-crt works perfectly for the performance target, it does lack features like luminance-dependent scanlines and phosphor simulation. I see AI-assisted iteration as a tool to bridge that gap not to replace legacy standards, but to offer more variety. It’s not about limiting the community; it’s about providing more options for those who want to push visual fidelity beyond the basics. I think there’s room for both approaches to coexist.

There is always room for improvement, and do not let destructive opinions discourage you. Using AI is just a tool, and the final output is what matters

If you want to speed up your workflow and get professional results quickly, you can use a structured prompt like this. Just copy and paste this into the AI, and it will give you the optimized code :

[Copy and paste this prompt:]

"I need to create a shader. Please follow these constraints carefully to ensure high-quality, professional code:

  1. Apply the CRT Warp code with 1:1 center.
  2. Texture Atlas Fix: You MUST normalize coordinates using TextureSize and InputSize to find the true center of the video frame before applying the warp, then convert back. Do not just subtract 0.5 from vTexCoord.
  3. No Forced Zoom/Scaling: Apply the pure curve WITHOUT any zoom-in or scaling correction. The center of the image must remain exactly 1:1.
  4. Black Corners: Leave the curved corners empty and apply a strict black bounds/border using step() so the rounded CRT edges are visible.
  5. Features: Include a basic brightness boost, Make the scanlines luminance-dependent: they should fade out in bright areas and only be visible in darker or mid-tone areas., and an Aperture Grille (Sony) mask.
  6. Synchronization: Make the scanlines synchronized pixel-by-pixel with the game at a full 6.283185 cycle, and ensure the mask follows gl_FragCoord.x.
  7. Parameters: Add #pragma parameter for each feature so they are adjustable in the menu, and define them as uniform float.
  8. Slot Mask Option: If you want slot tell ai make maske 6x2 : Row 1: Red Green Blue Black Black Black / Row 2: Black Black Black Red Green Blue.

Here is the base code structure to merge these features into:

#version 110



#if defined(VERTEX)
attribute vec4 VertexCoord;
attribute vec2 TexCoord;
varying vec2 uv;
uniform mat4 MVPMatrix;

void main() {
    uv = TexCoord;
    gl_Position = MVPMatrix * VertexCoord;
}

#elif defined(FRAGMENT)
#ifdef GL_ES
precision highp float;
#endif

varying vec2 uv;
uniform sampler2D Texture;
uniform vec2 TextureSize, InputSize;

#ifdef PARAMETER_UNIFORM
uniform float  ;
#endif

void main() {

    vec3 res = texture2D(Texture, uv).rgb;

    gl_FragColor = vec4(res, 1.0);
}
#endif