GS-hw: Increase 32->16bit conversion accuracy

Improves Dogs life (no longer goes completely black right away, but has decal problems)
Vastly improves texture quality in Spider-Man 3 when using Framebuffer Conversion to fix the textures
This commit is contained in:
refractionpcsx2 2022-02-11 21:01:27 +00:00
parent 6ab77be8fc
commit d4b1d9abe5
3 changed files with 9 additions and 50 deletions

View File

@ -114,15 +114,12 @@ float4 ps_scanlines(PS_INPUT input, int i)
return sample_c(input.t) * saturate(mask[i] + 0.5f);
}
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0
{
float4 c = sample_c(input.t);
uint4 i = sample_c(input.t) * float4(255.5f, 255.5f, 255.5f, 255.5f);
c.a *= 256.0f / 127; // hm, 0.5 won't give us 1.0 if we just multiply with 2
uint4 i = c * float4(0x001f, 0x03e0, 0x7c00, 0x8000);
return (i.x & 0x001f) | (i.y & 0x03e0) | (i.z & 0x7c00) | (i.w & 0x8000);
return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
PS_OUTPUT ps_datm1(PS_INPUT input)

View File

@ -74,47 +74,12 @@ void ps_depth_copy()
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
{
// Input Color is RGBA8
// We want to output a pixel on the PSMCT16* format
// A1-BGR5
#if 0
// Note: dot is a good idea from pseudo. However we must be careful about float accuraccy.
// Here a global idea example:
//
// SV_Target1 = dot(round(sample_c() * vec4(31.f, 31.f, 31.f, 1.f)), vec4(1.f, 32.f, 1024.f, 32768.f));
//
// For me this code is more accurate but it will require some tests
vec4 c = sample_c() * 255.0f + 0.5f; // Denormalize value to avoid float precision issue
// shift Red: -3
// shift Green: -3 + 5
// shift Blue: -3 + 10
// shift Alpha: -7 + 15
highp uvec4 i = uvec4(c * vec4(1/8.0f, 4.0f, 128.0f, 256.0f)); // Shift value
// bit field operation requires GL4 HW. Could be nice to merge it with step/mix below
SV_Target1 = (i.r & uint(0x001f)) | (i.g & uint(0x03e0)) | (i.b & uint(0x7c00)) | (i.a & uint(0x8000));
#else
// Old code which is likely wrong.
vec4 c = sample_c();
c.a *= 256.0f / 127.0f; // hm, 0.5 won't give us 1.0 if we just multiply with 2
highp uvec4 i = uvec4(c * vec4(uint(0x001f), uint(0x03e0), uint(0x7c00), uint(0x8000)));
// bit field operation requires GL4 HW.
SV_Target1 = (i.x & uint(0x001f)) | (i.y & uint(0x03e0)) | (i.z & uint(0x7c00)) | (i.w & uint(0x8000));
#endif
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
#endif

View File

@ -87,15 +87,12 @@ void ps_filter_transparency()
#endif
#ifdef ps_convert_rgba8_16bits
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
{
vec4 c = sample_c(v_tex);
highp uvec4 i = uvec4(sample_c(v_tex) * vec4(255.5f, 255.5f, 255.5f, 255.5f));
c.a *= 256.0f / 127; // hm, 0.5 won't give us 1.0 if we just multiply with 2
uvec4 i = uvec4(c * vec4(0x001f, 0x03e0, 0x7c00, 0x8000));
o_col0 = (i.x & 0x001fu) | (i.y & 0x03e0u) | (i.z & 0x7c00u) | (i.w & 0x8000u);
o_col0 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
#endif