Converting MiSTer FPGA Composite Blending shader to GLSL

This shader is very good at dealing with Genesis\MD dithering. It’s already ported to Retroarch thanks to Aeana. But I want to use it on an old phone which is gl only. Is it hard to convert? Here’s the source.

2 Likes

You know Blargg NTSC S-Video and Composite Video Filters also do a pretty great job at this.

I even have some custom presets for Blargg NTSC filters that you can use in my preset pack.

3 Likes

That mister implementation is just a simple 50% blend between neighbor pixels.

You can use sgenpt-mix (glsl or slang) that has many options on how to blend these pixels.

It’s located inside dithering folder.

Thread about it: SGENPT-MIX - Sega Genesis Pseudo Transparency Mixer shader

4 Likes

It’s a super-basic effect and there are much better options, such as hyllian’s sgenpt-mix, but if you just really want it for whatever reason, here you go:

// 50% horizontal blend; not gamma-corrected
// by hunterk
// license: public domain

#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 TEX0;

uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
   gl_Position = MVPMatrix * VertexCoord;
   TEX0.xy = TexCoord.xy;
   TEX0.zw = TexCoord.xy - vec2(SourceSize.z, 0.);
}

#elif defined(FRAGMENT)

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out COMPAT_PRECISION vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
   vec3 curr_px = COMPAT_TEXTURE(Source, TEX0.xy).rgb;
   vec3 prev_px = COMPAT_TEXTURE(Source, TEX0.zw).rgb;

   FragColor = vec4(mix(curr_px, prev_px, vec3(0.5)), 1.0);
} 
#endif

One problem with this shader (and the original) is that it does the blending in curved gamma, which makes the image favor darker pixels when blending. Here it is normally:

And here it is with gamma-correct blending:

7 Likes

Yeah these look great. Thank you! I think they deserve to be included in official Retroarch video filters pack.

I wasn’t quite satisfied with the default look but didn’t had time to experiment with options yet.

Thank you very much hunterk for converting it! It’s nice to have a choice.

Did you create second (gamma-correct) version of this shader or just modified the picture?

2 Likes

It’s a modification of the shader, yes.

1 Like

Can you share the source for it too please? Thank you!

1 Like

Sure, it’s very similar. Try this one:

// 50% horizontal blend; quick and dirty gamma correction
// by hunterk
// license: public domain

#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 TEX0;

uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
   gl_Position = MVPMatrix * VertexCoord;
   TEX0.xy = TexCoord.xy;
   TEX0.zw = TexCoord.xy - vec2(SourceSize.z, 0.);
}

#elif defined(FRAGMENT)

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out COMPAT_PRECISION vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
   vec3 curr_px = COMPAT_TEXTURE(Source, TEX0.xy).rgb;
   vec3 prev_px = COMPAT_TEXTURE(Source, TEX0.zw).rgb;

   curr_px *= curr_px;
   prev_px *= prev_px;

   FragColor = vec4(sqrt((curr_px + prev_px) / 2.), 1.0);
} 
#endif
3 Likes

Thanks! I don’t mind. That might be up to @hunterk and the rest of LibRetro team I suppose. It shouldn’t be too difficult as its just a few presets which attempt to improve on what’s already there, especially in terms of minimizing distracting artifacts, brightness improvements and most importantly finding the highest resolution where dither blending would still work.

I’d be honoured if they could be included.

You mean the ones in the “Video options”?

These don’t work. If i use GenesisPlusGX, i get a squished image that only takes half of my screen. If i use BlastEM, it just won’t do anything.

2 Likes

GPGX has it built-in and modified to work with the Genesis/MD video output.

2 Likes

That’s strange, they’ve always worked fine for me.

I was referring to the filters that are included in the Core Options–>Video.

It’s the ones made for SNES in the Video Filters Folder that used to do what you described on certain cores.

I haven’t used the ones in the Video Options in a while because I now use my custom Video Filter presets which work perfectly.

You can give them a try and see if they work for you. They’re in my CyberLab Mega Bezel Death To Pixels Shader Preset Pack.

1 Like

Ok i downloaded the new filters in the archive and these work.

The core options do work but the composite option creates some banding artifacts on Sonic’waterfalls when you scroll. These new video filter options though work nicely.

Thanks :slight_smile:

2 Likes

I second this. Just tried it with some random cores and they work and look marvelous.

1 Like

Is it just the filt presets that are changed? or do the libs need to have changes in the source?

2 Likes

Just the filt presets. blargg_ntsc_snes.dll remains the same.

That’s why I suggested @Cyber Genesis .filt presets to be bundled with Retroarch. Others have side effects (GPGX Comsposite), dont eliminate dithering (GPGX S-Video and RGB) or squish image (SNES presets from filters/video folder)

2 Likes

If it’s just the presets, yeah, that should be pretty straightforward to include. If it needed modifications to the lib, that would take some more due diligence.

I think we can move on this pretty quickly. If anyone wants to put in a PR for it, go for it. Otherwise, I’ll get one going later on.

3 Likes

You can go right ahead. How can I go about doing a PR though? Maybe this can be one of my first pull requests and additions to my so far unused GitHub Repo?

You fork the original libretro repo to your own account, make your changes locally, make a commit and push it up to your repo, then go to the ‘pull requests’ tab and make one against the parent repo (it chooses it automatically by default). Once submitted, we can check it out and review it and if everything looks good, we merge it into the main codebase.

3 Likes

Thanks a lot. I’ll try this over the next couple days. If I don’t get through, you can go ahead and add it.

One thing I noticed is that the built-in Genesis Composite Filter creates a rainbow effect but mine don’t, but they do de-dither and they do it cleanly. I use them in conjunction with presets with sharpness cranked to the highest point before unwanted artifacts.

I have those in my pack but users can also crank sharpness up in presets of their own and de-dithering will still work.

Update:

@hunterk Just created my first PR!

Do you need any additional information?

2 Likes