diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 7980670ca4..74d37e4013 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -31,6 +31,8 @@ void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS) int gl_version = 430; std::vector 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(); diff --git a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp index 97d482e78e..b3f9b88df2 100644 --- a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp @@ -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) { diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp index 3d7197f53a..8c1fc79686 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp @@ -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 }, diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.h b/rpcs3/Emu/RSX/Program/GLSLCommon.h index 0ad55477ae..b9c1f2fda4 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.h @@ -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 diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl index 0b80ef8d07..384df3bcd7 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl @@ -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) { diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 08a9b38af6..8dcb246646 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -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) diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index c34e77c0d6..eb57d11f7a 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -29,28 +29,24 @@ std::string VKFragmentDecompilerThread::compareFunction(COMPARE f, const std::st void VKFragmentDecompilerThread::insertHeader(std::stringstream & OS) { - int version = 420; std::vector 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";