Simple textured shader for non-backlit LCD systems (GBC etc.)

(EDIT: Oops - accidentally posted this before it was finished - let’s try again…)

Old non-backlit handhelds are easy on the eyes since viewing them is somewhat like looking at a sheet of paper. When you emulate them on a bright modern display, things can get nasty - especially when games make extensive use of white backgrounds. I was fed up of going snow blind every time I played Pokemon Pinball or Puzzle Link, so I made a very simple, very lightweight shader that (among other things) overlays pixels onto a comfortable textured background. You can download it here:

GLSL version: https://drive.google.com/file/d/1H-yuPiJW6GoRwQCY3900u1261zmoRkeU SLANG version: https://drive.google.com/file/d/1jjolwR0iiAc1CGLiyfNEvGqqIG656_kq

Whichever you download, you’ll end up with three shaders:

  • simpletex_lcd: base shader
  • simpletex_lcd+gbc-color: includes GBC colour correction
  • simpletex_lcd+gba-color: includes GBA colour correction

They work best with integer scaling ON, and they’ll run on pretty much anything (apart from a Raspberry Pi, i guess…). I get full speed on a Fire HD 10 tablet, and just a few frame drops on my ancient phone (mtk6735p + Mali-T720 GPU).

Anyway, here are some screenshots to show what these shaders do: (in fact, lots and lots of screenshots… I want to show how they behave in all sorts of conditions…)

simpletex_lcd

A handful of black and white games:

You can also get that old-school Game Boy green effect by pairing the shader with the following Gambatte palette: https://drive.google.com/file/d/1s7AW1E0coLo3shd73qO7P1IfoqpVky6D

simpletex_lcd+gbc-color

Here’s a random selection of GBC and NeoGeo Pocket games:

simpletex_lcd+gba-color

I wasn’t thinking about the Game Boy Advance when I made this shader, but it handles the platform quite well:



I’ve tried to configure these shaders with ‘sane’ default parameters, but they are designed to be tinkered with - you’ll almost certainly want to ‘tune’ them according to the resolution/contrast/brightness of your display.

The following variables can be accessed via the ‘Quick Menu > Shaders > Shader Parameters’ menu:

  • Grid Intensity: Sets overall visibility of grid effect (1.0: Grid is shown, 0.0: Grid is invisible)

  • Grid Width: Sets effective width of grid lines (1.0: Normal full width, 0.0: Minimum width)

  • Grid Bias: Dynamically adjusts the grid intensity based on pixel luminosity (0.0: Grid intensity is uniform, 1.0: Grid intensity scales linearly with pixel luminosity)

  • Darken Grid: Darkens grid (0.0: Grid is white, 1.0: Grid is black - I recommend leaving this at 0.0)

  • Darken Colours: Simply darkens pixel colours (0.0: Colours are normal, 2.0: Colours are too dark…)



A final note on textures:

The shaders are configured to use a 2048x2048 background texture image, which is fine for any display resolution up to 1200p.

If you have a display resolution higher than this (1440p, or 4k), you will need to make some edits:

1 - Open the glslp/slangp file you are using and replace:

BACKGROUND = "shaders/simpletex_lcd/png/2k/textured_paper.png"

with:

BACKGROUND = "shaders/simpletex_lcd/png/4k/textured_paper.png"

2 - Open the corresponding glsl/slang file and (a) comment out the “#define BG_TEXTURE_SIZE 2048.0” line, and (b) uncomment the “#define BG_TEXTURE_SIZE 4096.0” line - it should end up looking like this:

// Background texture size
// > 2048 x 2048 textures are suitable for screen resolutions up to
//   1200p (or 1440p if running 'square' aspect ratio systems)
//#define BG_TEXTURE_SIZE 2048.0
// > 4096 x 4096 textures are suitable for screen resolutions up to 4k
#define BG_TEXTURE_SIZE 4096.0

If you don’t like the default background texture, I’ve included a handful of free-use textures from www.subtlepatterns.com that you can play around with if you so wish - have a look in the “shaders/simpletex_lcd/png/” folder, and just update the BACKGROUND line in the glslp/slangp file you are using.

If you are a Linux user, you can drop any tileable PNG image in the “shaders/simpletex_lcd/src/png” directory and run the shaders/simpletex_lcd/src/generate_bg.bash script to make a new background texture - feel free to experiment!

8 Likes

That looks really nice! Fantastic job. I love the newsprint-y texture.

If you don’t mind, I’ll add these to the shader repos.

I would be honoured if you added them to the shader repos! :smile:

(and apologies for the incomplete post the first time around - I accidentally hit tab, and for some reason it posted the message while I was still half-way through…)

I think we can tile those textures programatically instead of stitching together large, fixed-res background images, if you’d like me to work on that.

Yes, I did consider that - I guess it should be quite easy: just take the fractional part of (bgPixelCoord.xy * INV_BG_TEXTURE_SIZE) when sampling the background.

The only awkward bit is getting the texture size. I couldn’t find a way to determine this programmatically, so you’d need hard-coded values that you’d have to change whenever you wanted to try a different background. If I make all the images fixed-sized in advance, I don’t have to worry about this.

If you can come up with a better way of handling this stuff, I would be grateful!


As an aside, how does the external texture vertex coordinate work in the GLSL shader? I determined via brief experimentation that you have to scale TEX0 by ((OutputSize / InputSize) * 256) to get 1:1 pixel mapping on the screen, but I have no idea why… In the SLANG version, it is far more rational…

Yeah, that’s a good point about not being able to get the size of the textures, and I’ve run into that before and had to rely on goofy magic numbers. I think BACKGROUNDSize should be the same sort of vec4 as SourceSize, but it just straight-up doesn’t work, which I think is a bug (or perhaps just an oversight during implementation).

FAKEDIT: it looks like it may be working with d3d11 but not vulkan, so yeah, that could just be an oversight in the vulkan imlpementation.

For the GLSL texCoord thing, IIRC, it’s usually TEX0 * TextureSize / InputSize or something like that where InputSize is the actual size from the core (256x224 or whatever; that is, NPOT) and TextureSize is the size of the buffer (1024x1024 or whatever). maister (the guy who wrote and implemented the shader specs in the first place while he was still in college) decided this was a bad idea in retrospect and corrected it for the slang spec.

REALEDIT: the way to get the texture size in GLSL would presumably be BACKGROUNDTextureSize or BACKGROUNDInputSize, neither of which seem to do anything. So, if you/we want the shaders to all act the same regardless of driver implementation, it’s probably best to leave it as you have it, though we should probably pare down the number of backgrounds we put on the repo, just so it doesn’t add too much to the download.

OK, thanks for the info. I think you’re right - in lieu of working BACKGROUND*Size parameters, it’s probably best to leave things as they are.

For the reops, I would suggest culling all the backgrounds apart from the default ‘textured_paper.png’ - it’s by far and away my favourite, and people can always add more themselves (e.g. just by grabbing them from the zip files I posted). We might even get other users posting nice textures they have made… :wink:

Right, but where does the factor of 256 come from ?!?

Actually, don’t worry! I’m just happy that it works as-is. :slight_smile:

1 Like

I don’t know if it’s helpful, but I had a few spare minutes and just thought I’d re-bundle the shaders for uploading to the repos. I’ve removed all but the ‘textured_paper.png’ backgrounds, and also added a ‘4k’ variant of each shader (so users don’t have to mess about editing files if they have a super-high-res display). The size of each ‘package’ is ~2 MB, so I guess that’s not too bad?

GLSL: https://drive.google.com/file/d/1JoR1KuZP6BIXtfUecBXAfsU1maaMeM4d

SLANG: https://drive.google.com/file/d/16yW8N43T45D5ZaBUhxT33jEGmQDgtV9e

Oh yeah, that is helpful, thanks!

I just pushed a version up to the GLSL shader repo with some small changes to make it tile the src pngs programmatically and a parameter to zoom the texture in/out for different texture/screen sizes. That gets the whole package down to a few hundred KB, even with a bunch of backgrounds, but if it looks bad to you, let me know and we can scrap it and use your repo bundle instead.

Oooh - That sounds neat! I’ll check it out once the repo updates (I guess there’s a time lag on github?).

Does the tiling/scaling have any appreciable effect on performance? One of the things I like best about the shader is that it runs on a potato… (I have a hard time finding decent shaders that work on rubbishy Android devices…)

oh lol, whoops, I hadn’t actually pushed it up, just created the commit (I do that all the time…). Check it now.

Dunno if it affected performance significantly at potato-scale, since I’ve only tested it on a full-size PC, but again, if it’s affected things negatively, just let me know and I’ll dump it for your 2MB bundle.

OK, you really puzzled me for a moment there! Everything was the wrong colour…

I should have mentioned that the generated textures are ‘adjusted’ slightly by the ‘generate_bg.bash’ script - it’s basically a:

convert image.png -brightness-contrast -30x25 image.png
convert image.png -colorspace Gray image.png

…so when you use the src images directly, everything’s too bright and a bit wishy-washy! But this is easily fixed.

I really appreciate what you’ve done with the tiling, but it kinda bugs me how we lose the pin-sharp 1:1 pixel mapping of the background texture. I tried a bunch of games and it looks a bit off to me. I’m not sure that anyone else would notice, but it tickles my OCD…

I guess I prefer my version…?

I feel terrible now… You’ve done something cool, and I’m being annoying about it… I bet you’ll say bad things about me behind my back…

lol no, it’s fine. We’ll go with your version. The sharpness does look a lot nicer.

Thanks, I appreciate it. You are a scholar and a gentleman!

BTW, it really is good of you to add my bit of code to the repos. I have so much love and respect for the RetroArch project. It feels nice to give a little something back :blush:

1 Like

Amazing job,m8! I need to test if these delicious shaders can run smoothly on my Sd801 now :wink:

Edit:So it’s amazing smooth,really thank you :smile:

Glad you like them!

I made sure they run at full speed with all handheld cores on my Fire HD 10, which has a PowerVR GX6250 GPU. The Adreno 330 in your SD 801 has very similar performance, so you should have no troubles at all. :smiley:

Great to know! :smile:

Hi jdgleaver,any plan making a smooth crt shader for snes/nes/genesis with warpX/Y&glow&scanline effects for old phone? Something like this: https://i.imgur.com/KuNfxoz.jpg

Could you post a preview of what the black grid version looks like?

No, sorry - I’m already quite content with the existing CRT shaders in the repos…

But there is a fair bit of choice, even for old Android devices - and your SD 801 is quite powerful. You should have no trouble running something like crt-hyllian-multipass for example.

If you really want screen curvature, then I would suggest either ‘crt-pi’ or the curved variant of ‘zfast_lcd’ which you can get here: https://retropie.org.uk/forum/topic/13356/new-crt-lcd-shaders-for-rpi3-they-run-at-60fps-at-higher-resolutions-and-are-configurable (read the whole thread!)

One thing to note: for ‘crt-pi’ to work correctly on Android, you might have to force ‘highp’ precision (I’ve had to do this with every Android device I’ve ever owned, due to dodgy GPU chipsets). The quick and dirty way to do this is:

  1. Open glsl-shaders/crt/shaders/crt-pi.glsl in a text editor

  2. Replace every instance of ‘mediump’ with ‘highp’

(and while you have the file open, you can play with the CURVATURE and SHARPER settings)

I guess the ‘highp’ hack might also be needed for the zfast_crt variants, but I haven’t tried them…

1 Like