rsx: Properly implement 8-bit signed renormalization for textures

This commit is contained in:
kd-11 2024-06-02 04:55:30 +03:00 committed by kd-11
parent 0b22423ab8
commit 14e1214645
7 changed files with 63 additions and 19 deletions

View File

@ -31,6 +31,8 @@ void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS)
int gl_version = 430;
std::vector<std::string> required_extensions;
required_extensions.push_back("GL_EXT_shader_integer_mix");
if (device_props.has_native_half_support)
{
const auto driver_caps = gl::get_driver_caps();

View File

@ -68,12 +68,12 @@ void FragmentProgramDecompiler::SetDst(std::string code, u32 flags)
if (dst.fp16 && device_props.has_native_half_support && !(flags & OPFLAGS::skip_type_cast))
{
// Cast to native data type
code = ClampValue(code, 1);
code = ClampValue(code, RSX_FP_PRECISION_HALF);
}
if (dst.saturate)
{
code = ClampValue(code, 4);
code = ClampValue(code, RSX_FP_PRECISION_SATURATE);
}
else if (dst.prec)
{

View File

@ -328,6 +328,10 @@ namespace glsl
{ "EXPAND_G_BIT" , rsx::texture_control_bits::EXPAND_G },
{ "EXPAND_B_BIT" , rsx::texture_control_bits::EXPAND_B },
{ "EXPAND_A_BIT" , rsx::texture_control_bits::EXPAND_A },
{ "SEXT_R_BIT" , rsx::texture_control_bits::SEXT_R },
{ "SEXT_G_BIT" , rsx::texture_control_bits::SEXT_G },
{ "SEXT_B_BIT" , rsx::texture_control_bits::SEXT_B },
{ "SEXT_A_BIT" , rsx::texture_control_bits::SEXT_A },
{ "ALPHAKILL ", rsx::texture_control_bits::ALPHAKILL },
{ "RENORMALIZE ", rsx::texture_control_bits::RENORMALIZE },

View File

@ -22,6 +22,10 @@ namespace rsx
EXPAND_R,
EXPAND_G,
EXPAND_B,
SEXT_A,
SEXT_R,
SEXT_G,
SEXT_B,
DEPTH_FLOAT,
DEPTH_COMPARE_OP,
DEPTH_COMPARE_1,
@ -33,7 +37,9 @@ namespace rsx
GAMMA_CTRL_MASK = (1 << GAMMA_R) | (1 << GAMMA_G) | (1 << GAMMA_B) | (1 << GAMMA_A),
EXPAND_MASK = (1 << EXPAND_R) | (1 << EXPAND_G) | (1 << EXPAND_B) | (1 << EXPAND_A),
EXPAND_OFFSET = EXPAND_A
EXPAND_OFFSET = EXPAND_A,
SEXT_MASK = (1 << SEXT_R) | (1 << SEXT_G) | (1 << SEXT_B) | (1 << SEXT_A),
SEXT_OFFSET = SEXT_A
};
enum ROP_control_bits : u32

View File

@ -7,9 +7,14 @@ R"(
#define EXPAND_G_MASK (1 << EXPAND_G_BIT)
#define EXPAND_B_MASK (1 << EXPAND_B_BIT)
#define EXPAND_A_MASK (1 << EXPAND_A_BIT)
#define SEXT_R_MASK (1 << SEXT_R_BIT)
#define SEXT_G_MASK (1 << SEXT_G_BIT)
#define SEXT_B_MASK (1 << SEXT_B_BIT)
#define SEXT_A_MASK (1 << SEXT_A_BIT)
#define GAMMA_CTRL_MASK (GAMMA_R_MASK | GAMMA_G_MASK | GAMMA_B_MASK | GAMMA_A_MASK)
#define SIGN_EXPAND_MASK (EXPAND_R_MASK | EXPAND_G_MASK | EXPAND_B_MASK | EXPAND_A_MASK)
#define SEXT_MASK (SEXT_R_MASK | SEXT_G_MASK | SEXT_B_MASK | SEXT_A_MASK)
#define FILTERED_MASK (FILTERED_MAG_BIT | FILTERED_MIN_BIT)
#ifdef _ENABLE_TEXTURE_EXPAND
@ -164,6 +169,15 @@ vec4 _texcoord_xform_shadow(const in vec4 coord4, const in sampler_info params)
#endif // _EMULATE_SHADOW
vec4 _sext_unorm8x4(const in vec4 x)
{
// TODO: Handle clamped sign-extension
const ivec4 bits = ivec4(floor(fma(x, vec4(255.), vec4(0.5f))));
const bvec4 sign_check = lessThan(bits, ivec4(0x80));
const ivec4 ret = _select(bits - 256, bits, sign_check);
return ret / 127.f;
}
vec4 _process_texel(in vec4 rgba, const in uint control_bits)
{
if (control_bits == 0)
@ -190,16 +204,25 @@ vec4 _process_texel(in vec4 rgba, const in uint control_bits)
uvec4 mask;
vec4 convert;
uint op_mask = control_bits & uint(SIGN_EXPAND_MASK);
if (op_mask != 0)
uint op_mask = control_bits & uint(SIGN_EXPAND_MASK);
if (op_mask != 0u)
{
// Expand to signed normalized
// Expand to signed normalized by decompressing the signal
mask = uvec4(op_mask) & uvec4(EXPAND_R_MASK, EXPAND_G_MASK, EXPAND_B_MASK, EXPAND_A_MASK);
convert = (rgba * 2.f - 1.f);
rgba = _select(rgba, convert, notEqual(mask, uvec4(0)));
}
op_mask = control_bits & uint(SEXT_MASK);
if (op_mask != 0u)
{
// Sign-extend the input signal
mask = uvec4(op_mask) & uvec4(SEXT_R_MASK, SEXT_G_MASK, SEXT_B_MASK, SEXT_A_MASK);
convert = _sext_unorm8x4(rgba);
rgba = _select(rgba, convert, notEqual(mask, uvec4(0)));
}
op_mask = control_bits & uint(GAMMA_CTRL_MASK);
if (op_mask != 0u)
{

View File

@ -2600,7 +2600,8 @@ namespace rsx
}
// Special operations applied to 8-bit formats such as gamma correction and sign conversion
// NOTE: The unsigned_remap being set to anything other than 0 flags the texture as being signed (UE3)
// NOTE: The unsigned_remap=bias flag being set flags the texture as being sign-expanded (BX2) (UE3)
// NOTE: The ARGB8_signed flag means to reinterpret the raw bytes as signed. This is different than unsigned_remap=bias
// This is a separate method of setting the format to signed mode without doing so per-channel
// Precedence = SIGNED override > GAMMA > UNSIGNED_REMAP (See Resistance 3 for GAMMA/REMAP relationship, UE3 for REMAP effect)
@ -2609,23 +2610,35 @@ namespace rsx
const u32 unsigned_remap = (tex.unsigned_remap() == CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL)? 0u : (~gamma & 0xF);
u32 argb8_convert = gamma;
if (const u32 sign_convert = (argb8_signed | unsigned_remap))
// Helper function to apply a per-channel mask based on an input mask
const auto apply_sign_convert_mask = [&](u32 mask, u32 bit_offset)
{
// Apply remap to avoid mapping 1 to -1. Only the sign conversion needs this check
// TODO: Use actual remap mask to account for 0 and 1 overrides in default mapping
// TODO: Replace this clusterfuck of texture control with matrix transformation
const auto remap_ctrl = (tex.remap() >> 8) & 0xAA;
if (remap_ctrl == 0xAA)
{
argb8_convert |= (sign_convert & 0xFu) << texture_control_bits::EXPAND_OFFSET;
argb8_convert |= (unsigned_remap & 0xFu) << texture_control_bits::EXPAND_OFFSET;
}
else
{
if (remap_ctrl & 0x03) argb8_convert |= (sign_convert & 0x1u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0x0C) argb8_convert |= (sign_convert & 0x2u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0x30) argb8_convert |= (sign_convert & 0x4u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0xC0) argb8_convert |= (sign_convert & 0x8u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0x03) argb8_convert |= (unsigned_remap & 0x1u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0x0C) argb8_convert |= (unsigned_remap & 0x2u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0x30) argb8_convert |= (unsigned_remap & 0x4u) << texture_control_bits::EXPAND_OFFSET;
if (remap_ctrl & 0xC0) argb8_convert |= (unsigned_remap & 0x8u) << texture_control_bits::EXPAND_OFFSET;
}
};
if (argb8_signed)
{
// Apply integer sign extension from uint8 to sint8 and renormalize
apply_sign_convert_mask(argb8_signed, texture_control_bits::SEXT_OFFSET);
}
if (unsigned_remap)
{
// Apply sign expansion, compressed normal-map style (2n - 1)
apply_sign_convert_mask(unsigned_remap, texture_control_bits::EXPAND_OFFSET);
}
if (argb8_convert)

View File

@ -29,28 +29,24 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st
void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS)
{
int version = 420;
std::vector<const char*> required_extensions;
if (device_props.has_native_half_support)
{
version = std::max(version, 450);
required_extensions.emplace_back("GL_EXT_shader_explicit_arithmetic_types_float16");
}
if (properties.multisampled_sampler_mask)
{
version = std::max(version, 450);
required_extensions.emplace_back("GL_ARB_shader_texture_image_samples");
}
if (m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION)
{
version = std::max(version, 450);
required_extensions.emplace_back("GL_EXT_fragment_shader_barycentric");
}
OS << "#version " << version << "\n";
OS << "#version 450\n";
for (const auto ext : required_extensions)
{
OS << "#extension " << ext << ": require\n";