Real GBA and DS-Phat colors

I agree the LUT is a must-have, without sounding too pushing. :slight_smile:

As a side note, strangely I can run v5.2 of this (even the lcd-motion flavour), but yours (tatsuya) crashes on me. Using latest RetroArch-testing under Linux PPA, Nvidia ā€œtestedā€ drivers, etc. It doesnā€™t bother me that much, but it boggles me plenty :slight_smile:

[QUOTE=twipley;22397]I agree the LUT is a must-have, without sounding too pushing. :slight_smile:

As a side note, strangely I can run v5.2 of this (even the lcd-motion flavour), but yours (tatsuya) crashes on me. Using latest RetroArch-testing under Linux PPA, Nvidia ā€œtestedā€ drivers, etc. It doesnā€™t bother me that much, but it boggles me plenty :)[/QUOTE]

Probably a driver issue / retoarch wip, idk. Itā€™s working here but thatā€™s on win64, Nvidia 350.12. Still using a nightly from the 15th of April because of problems with GLUI.

Updated the package and have a slight more contrast to grays. The bottom of the background shows a little bit more details.

http://imgur.com/Sreh9N9 (Left-last LUT / Right-New LUT)

Also, I uploaded an experimental version of the GBA colors without the use of LUT, but had a low quality of black contrast just like VBA-M version because the color matrix code was complicated and had to darken the colors without overlap the whites before brighten the gamma setting. I recommend the ones with LUT for a higher quality version.

Interesting! Iā€™m quite excited about the exploration of the potentials of this method.

Oh yeah, Iā€™m stoked for that, too. I would have merged these into the main repo long ago except for the giant LUTs. Whenever you get something youā€™re satisfied with in LUT-less form, Iā€™ll push it right up. :slight_smile:

Thanks for appreciate my experimental non-lut version of GBA shader. I have to learn more about the code. Someday, I will find the right code for it. I just need a certain gamma shader and a color shader that only changes color separately for black, red, green, blue, and white values. For now, use the LUT version unless you have less powerful GPU or had problems with the texture.

As for the picture I just uploaded in my last post, the bottom of the background should have a little better contrast for my latest LUT versions.

Nice, I can see the slight differences.

The shader without LUT is interesting. I played a bit with it, first thing I did was to disable the brightness boost as it always mess with the black.

Result with new LUT / without LUT

Weā€™re not that far from something similar. (a bit too much green, probably caused by gamma) Of course that depends of the settings you use for gamma/luminance/etc in conjunction with your vbam-pass2.cg. I think itā€™s possible to tweak both (img adjust & vbam-pass2 values) to get something great.

But perhaps it will be a bit more difficult to adjust between different games. Here are the files I tweaked if people with low GPU wants it. (you can slightly reduce the green in shader options, I could have done that) (well, actually no, thatā€™s just about the blue, it has a bad effect on the white, oh well, just experiment for yourselves!)

edit: Newer version here

Uploaded a new version of the experimental non-lut shader version for gba screen. Itā€™s now named gba-shader.cgp and itā€™s identical to the lut version. http://imgur.com/hUcxvTT Left - LUT Version/ Right - Pure Shaders

The LUT version are usually good on low contrast games like Circle of the Moon.

o_O

EDIT: nice work. cannot wait for official LCD shader (cgwg_grid) / motion-blur to be referenced in a .cgp together with the non-lut version! (

Thanks! I had to do a little adjustment to the shader and make LCD and XBR .cgp files. I also have to do an nds shader too, but Iā€™m almost done with the GBA one. The only difference from lut is that I was able to use the shadow bright tool to have very dark contrast visible. Games like Castlevania are dark on the VBA-M filter but looks good on my lut shader. So far, pure shaders make it look identical. Iā€™ll upload a new version in a few days.

Nice youā€™re getting close.

ā€¦but couldnā€™t you get the same result with the greys? raw with LUT / raw no LUT

Thatā€™s why the shader without LUT burns details in the 1st Castlevania or both Metroid games. Having the default setting showing ā€œtoo much greysā€ is better so that you can use an image adjustment shader behind it and tweak easily for different games.

As it is right now, if I put both behind the lcd shader and try to adjust the contrast I get this: with LUT / no LUT

The luminance I rise to make up for the loss of the lcd-grid pass accentuates the differences: the greys get too light, blue is greener, some differences between blue/purple dark colors, red is getting a bit too light (not really apparent on this picture).

Another example with the same settings: with LUT / no LUT

Quite a difference, donā€™t know which one is closer to the real thing.

I combined the 3-pass LUT-less shaders into a single-pass Cg shader and it looks fine to me, but I wanted to make sure it didnā€™t mess anything up before I commit it to the repo, so Iā€™d appreciate it if you guys could do some quick testing to make sure it looks the same:

/*
   Author: Pokefan531
   License: Public domain
*/

// Shader that replicates the LCD dynamics from a GameBoy Advance

void main_vertex
(
   float4 position : POSITION,
   out float4 oPosition : POSITION,
   uniform float4x4 modelViewProj,

   float2 tex : TEXCOORD,
   out float2 oTex : TEXCOORD
)
{
   oPosition = mul(modelViewProj, position);
   oTex = tex;
}

float3 grayscale(float3 col)
{
   // Non-conventional way to do grayscale,
   // but bSNES uses this as grayscale value.
   return float3(dot(col, float3(0.2126, 0.7152, 0.0722)));
}

float4 main_fragment(float2 tex : TEXCOORD, uniform sampler2D s0 : TEXUNIT0) : COLOR
{
//part 1
float saturation = 1.0;
float Display_gamma = 1.02;
float CRT_gamma = 2.4;
float luminance = 1.0;

   float3 gamma = float3(CRT_gamma / Display_gamma);
   float3 res = tex2D(s0, tex).xyz;
   res = lerp(grayscale(res), res, saturation); // Apply saturation
   res = pow(res, gamma.rgb); // Apply gamma
   float4 c = float4(saturate(res * luminance), 1.0);

//part 2
	float r = c.x;
	float g = c.y;
	float b = c.z;
	float a = c.w;
	float w = r * 0.714 + g * 0.251 + b * 0.000;
	float q = r * 0.071 + g * 0.643 + b * 0.216;
	float e = r * 0.071 + g * 0.216 + b * 0.643;

//part 3
saturation = 1.0;
Display_gamma = 3.6;
CRT_gamma = 2.4;
luminance = 1.01;

   res = float3(w, q, e);
   gamma = gamma = float3(CRT_gamma / Display_gamma);
   res = lerp(grayscale(res), res, saturation); // Apply saturation
   res = pow(res, gamma.rgb); // Apply gamma
   return float4(saturate(res * luminance), 1.0);
}

[QUOTE=hunterk;22776]I combined the 3-pass LUT-less shaders into a single-pass Cg shader and it looks fine to me, but I wanted to make sure it didnā€™t mess anything up before I commit it to the repo, so Iā€™d appreciate it if you guys could do some quick testing to make sure it looks the same: [/QUOTE] Nice. Thatā€™s almost the same. Yeah thereā€™s a small difference that happens, some rounded values or something: 3 passes / 1 pass

You can spot the difference if you compare them in a viewer and look at the darkest spots on top of the screen (near those blue/black pillars) and on the left (the darkest end of that grey brick gradient thing). Thatā€™s good enough probably.

Hmm. Subtracting those two images in Photoshop is only showing differences in the parts that were moving, AFAICT: Even if there is any difference, I think it is indeed close enough, so Iā€™ll push it up to the repo.

You guys may be interested in an extended image adjustment shader I made that gives full control over the color matrix in runtime params (e.g., you can control how much red is in the blue channel or how much green is in the red channel), which may be easier to work with than what you guys have been doing:

/*
   Color Mangler
   Author: hunterk
   License: Public domain
*/

// Shader that replicates the LCD dynamics from a GameBoy Advance
#pragma parameter display_gamma "Display Gamma" 2.2 0.0 10.0 0.1
#pragma parameter target_gamma "Target Gamma" 2.2 0.0 10.0 0.1
#pragma parameter overscan_percent_x "Horizontal Overscan %" 0.0 -25.0 25.0 1.0
#pragma parameter overscan_percent_y "Vertical Overscan %" 0.0 -25.0 25.0 1.0
#pragma parameter sat "Saturation" 1.0 0.0 3.0 0.01
#pragma parameter lum "Luminance" 1.0 0.0 5.0 0.01
#pragma parameter contrast "Contrast" 1.0 0.0 2.0 0.01
#pragma parameter r "Red" 1.0 0.0 2.0 0.01
#pragma parameter g "Green" 1.0 0.0 2.0 0.01
#pragma parameter b "Blue" 1.0 0.0 2.0 0.01
#pragma parameter rg "Red-Green Tint" 0.0 0.0 1.0 0.005
#pragma parameter rb "Red-Blue Tint" 0.0 0.0 1.0 0.005
#pragma parameter gr "Green-Red Tint" 0.0 0.0 1.0 0.005
#pragma parameter gb "Green-Blue Tint" 0.0 0.0 1.0 0.005
#pragma parameter br "Blue-Red Tint" 0.0 0.0 1.0 0.005
#pragma parameter bg "Blue-Green Tint" 0.0 0.0 1.0 0.005
#pragma parameter blr "Black-Red Tint" 0.0 0.0 1.0 0.005
#pragma parameter blg "Black-Green Tint" 0.0 0.0 1.0 0.005
#pragma parameter blb "Black-Blue Tint" 0.0 0.0 1.0 0.005
#ifdef PARAMETER_UNIFORM
uniform float display_gamma;
uniform float target_gamma;
uniform float sat;
uniform float lum;
uniform float contrast;
uniform float blr;
uniform float blg;
uniform float blb;
uniform float r;
uniform float g;
uniform float b;
uniform float rg;
uniform float rb;
uniform float gr;
uniform float gb;
uniform float br;
uniform float bg;
uniform float overscan_percent_x;
uniform float overscan_percent_y;
#else
#define display_gamma 2.2
#define target_gamma 2.2
#define sat 1.0
#define lum 1.0
#define contrast 1.0
#define blr 0.0
#define blg 0.0
#define blb 0.0
#define r 1.0
#define g 1.0
#define b 1.0
#define rg 0.0
#define rb 0.0
#define gr 0.0
#define gb 0.0
#define br 0.0
#define bg 0.0
#define overscan_percent_x 0.0
#define overscan_percent_y 0.0
#endif

struct input
{
  float2 video_size;
  float2 texture_size;
  float2 output_size;
  float  frame_count;
  float  frame_direction;
  float frame_rotation;
};

void main_vertex
(
   float4 position : POSITION,
   out float4 oPosition : POSITION,
   uniform float4x4 modelViewProj,
   uniform input IN,

   float2 tex : TEXCOORD,
   out float2 oTex : TEXCOORD
)
{
   oPosition = mul(modelViewProj, position);
   float2 shift = 0.5 * IN.video_size / IN.texture_size;
   float2 overscan_coord = (tex - shift) * (1.0 - float2(overscan_percent_x / 100.0, overscan_percent_y / 100.0)) + shift;
   oTex = overscan_coord;
}

float4 main_fragment(float2 tex : TEXCOORD, uniform sampler2D s0 : TEXUNIT0) : COLOR
{
float4 screen = pow(tex2D(s0, tex), target_gamma).rgba; //sample image in linear colorspace
float4 avglum = float4(0.5);
screen = lerp(screen, avglum, (1.0 - contrast));

//				r   g    b   black
mat4x4 color = {r,  gr,  br, blr,  //red channel
			   rg,   g,  bg, blg,  //green channel
			   rb,  gb,   b, blb,  //blue channel
			  0.0, 0.0, 0.0,    1.0}; //alpha channel; these numbers do nothing for our purposes.
			  
mat4x4 adjust = {(1.0 - sat) * 0.3086 + sat, (1.0 - sat) * 0.6094,          (1.0 - sat) * 0.0820,          0.0,
			    (1.0 - sat) * 0.3086,          (1.0 - sat) * 0.6094 + sat, (1.0 - sat) * 0.0820,          0.0,
			    (1.0 - sat) * 0.3086,          (1.0 - sat) * 0.6094,          (1.0 - sat) * 0.0820 + sat, 0.0,
			     1.0, 1.0, 1.0, 1.0};

color = mul(color, adjust);
screen = saturate(screen * lum);
screen = mul(color, screen);
return pow(screen, 1.0 / display_gamma);
}

I can see it in your picture, there is a ghost shadow of those pillars (and over all the bricks that I couldnā€™t see), but yeah, thatā€™s subtle. If youā€™ve got a TN or IPS panel with an average contrast you probably donā€™t see it.

Gonna check this shader, looks interesting, thanks.

edit: you should put 0.01 steps for the contrast as well in this shader, 0.1 is a bit too strong too fast imo. Isnā€™t luminance a lot weaker than before? ā€¦and contrast really strong!

oh yeah, youā€™re right. I had to tilt my monitor to see it, but there it is. Wonder whatā€™s causing the differenceā€¦ Anyway, at least itā€™s subtle :slight_smile:

Yeah, that shader uses very different functions to do the same end-results, so itā€™ll take some getting used to if youā€™re accustomed to the other one. Iā€™ll change the step on the contrast and change the luminance calculation to match the other method. EDIT: ok, try it now. Also, would it be helpful to separate the brightness setting into a per-channel setting?

[QUOTE=hunterk;22788] EDIT: ok, try it now. Also, would it be helpful to separate the brightness setting into a per-channel setting?[/QUOTE]

Got this error:

E:\Emulateurs\RetroArch64\shaders/misc/image-adjustment-v2.cg(111) : error C1101
: ambiguous overloaded function reference "saturate(float4x4)"
    (0) : gp5 cp50 fp50 vp50 gp50 cpf fpf vpf gpf double saturate(double)
    (0) : gp5 gp4 cp50 fp50 vp50 gp50 cpf fpf vpf gpf fixed saturate(fixed)
    (0) : gp5 gp4 cp50 fp50 vp50 gp50 cpf fpf vpf gpf half saturate(half)
    (0) : gp5 gp4 cp50 fp50 vp50 gp50 cpf fpf vpf gpf float saturate(float)
    (0) : ps fixed saturate(fixed)
    (0) : ps half saturate(half)
    (0) : ps float saturate(float)

Per-channel setting? well the more options the best, like blue-in-blue, red-in-red, etc?

Does the new image adjustment keeps the grays and whites intact? On the second pass shader where it has the color matrix, sometimes it would overlaps the limit from 255 and kill some white contrast because each custom red, green, and blue values are added together, like if both red and blue have red at 192, and blue at 255, then overlapping happen because it would be 368 for red and 510 for blue that would stay at 255. So I think black and white should also have a channel if possible. Iā€™m almost ready for uploading a new version soon and the single pass helps a little with very low contrast parts. Iā€™m currently doing the same for nds.

I fixed that error by moving the luminance calculation to another part of the code (sorry, I should have tested it before throwing it out there like that) and I also made some more options configurable. Iā€™m not sure about the color clipping being any better on this one, but all of the calculations take place in linear colorspace, which should be more predictable than working along the gamma curve.

Well, thanks for improving the code for image adjustment. In Photoshop, I used curves which are different from gamma, and used shadow tool to brighten the dark colors a little. Also for your combined single pass shader, it saves the dark contrast from banding, and it doesnā€™t seem to rasterize the image on each step, unlike how my multipass shader went. Other thing about the GBA hardware is with my pure shader version, the contrast and gamma is similar to the screen, but they are better than the filter from VBA-M. I only had original GBA to test with. I never had the one with afterburner kit or gba-sp AGS 001 that has the front lit screen. The afterburner kit usually retains the color palettes and gamma from the non-lit screen. I only have nds phat to test with the shader.