So, I'm working on some pixel shaders for old, old emulators like Super Nintendo. You have classic algorithms like HQnx, 2xSaI, etc. And they are definitely written to work on processors and scale exactly twice before blitting to the screen.
Turning to the shaders of GPU fragments, these algorithms can be performed almost for free. I work with OpenGL and Cg / GLSL, but this question should also apply to Direct3D / HLSL encoders.
The main problem is that these algorithms are mixed with neighboring pixels using some algorithm to determine the color. However, I pretty much found this concept with shader languages. Typically, using flash shaders, you can get the texture coordinate of a floating point, which you can use to find a texture, usually with GL_LINEAR, used as a texture filter. Most pixel shaders use GL_NEAREST and smooth themselves.
The problem arises if I want to find, say, an exact neighboring pixel. I saw some implementations, but sometimes they cause artifacts on the screen. Probably due to floating point inaccuracies. I found that most artifacts simply disappear when using double-sized textures, which further strengthens my belief that floating point inaccuracies occur. Here is an example of a shader fragment in Cg that shows problems:
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
struct deltas
{
float2 UL, UR, DL, DR;
};
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s_p : TEXUNIT0)
{
float2 texsize = IN.texture_size;
float dx = pow(texsize.x, -1.0) * 0.25;
float dy = pow(texsize.y, -1.0) * 0.25;
float3 dt = float3(1.0, 1.0, 1.0);
deltas VAR = {
tex + float2(-dx, -dy),
tex + float2(dx, -dy),
tex + float2(-dx, dy),
tex + float2(dx, dy)
};
float3 c00 = tex2D(s_p, VAR.UL).xyz;
float3 c20 = tex2D(s_p, VAR.UR).xyz;
float3 c02 = tex2D(s_p, VAR.DL).xyz;
float3 c22 = tex2D(s_p, VAR.DR).xyz;
float m1=dot(abs(c00-c22),dt)+0.001;
float m2=dot(abs(c02-c20),dt)+0.001;
output OUT;
OUT.color = float4((m1*(c02+c20)+m2*(c22+c00))/(2.0*(m1+m2)),1.0);
return OUT;
}
Is there a way to make sure that we can capture color data from the pixel we expect and not another? I believe this problem occurs because we can request a pixel from a coordinate that is just two pixels away (if that makes sense). Hope there are some built-in functions in these shader languages that I skip.