From 89c81d9f2268756aa7f71e9b6c89da978f7c5533 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 20 Jun 2023 00:20:51 +0300 Subject: [PATCH] rsx: Switch common codegen to use the glsl scripts --- rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp | 4 +- rpcs3/Emu/RSX/Program/GLSLCommon.cpp | 645 ++++-------------- rpcs3/Emu/RSX/Program/GLSLCommon.h | 7 - .../RSXProg/RSXFragmentPrologue.glsl | 73 +- .../RSXProg/RSXProgramCommon.glsl | 2 +- .../RSXProg/RSXVertexPrologue.glsl | 2 +- rpcs3/Emu/RSX/Program/GLSLTypes.h | 1 + rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 4 +- 8 files changed, 193 insertions(+), 545 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index a0e610bae5..23c4f90954 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -191,6 +191,7 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) m_shader_props.require_texture_expand = properties.has_exp_tex_op; m_shader_props.require_srgb_to_linear = properties.has_upg; m_shader_props.require_linear_to_srgb = properties.has_pkg; + m_shader_props.require_fog_read = properties.in_register_mask & in_fogc; m_shader_props.emulate_coverage_tests = true; // g_cfg.video.antialiasing_level == msaa_level::none; m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare; m_shader_props.low_precision_tests = ::gl::get_driver_caps().vendor_NVIDIA && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION); @@ -203,9 +204,6 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { - if (properties.in_register_mask & in_fogc) - program_common::insert_fog_declaration(OS); - std::set output_registers; if (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) { diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp index 180ea9d74b..6a511b56ca 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.cpp +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.cpp @@ -20,104 +20,14 @@ namespace program_common OS << "\n"; } - void insert_compare_op(std::ostream& OS) + void define_glsl_switches(std::ostream& OS, std::vector& enums) { - OS << - "bool comparison_passes(const in float a, const in float b, const in uint func)\n" - "{\n" - " switch (func)\n" - " {\n" - " default:\n" - " case 0: return false; //never\n" - " case 1: return (CMP_FIXUP(a) < CMP_FIXUP(b)); //less\n" - " case 2: return (CMP_FIXUP(a) == CMP_FIXUP(b)); //equal\n" - " case 3: return (CMP_FIXUP(a) <= CMP_FIXUP(b)); //lequal\n" - " case 4: return (CMP_FIXUP(a) > CMP_FIXUP(b)); //greater\n" - " case 5: return (CMP_FIXUP(a) != CMP_FIXUP(b)); //nequal\n" - " case 6: return (CMP_FIXUP(a) >= CMP_FIXUP(b)); //gequal\n" - " case 7: return true; //always\n" - " }\n" - "}\n\n"; - } - - void insert_compare_op_vector(std::ostream& OS) - { - OS << - "bvec4 comparison_passes(const in vec4 a, const in vec4 b, const in uint func)\n" - "{\n" - " switch (func)\n" - " {\n" - " default:\n" - " case 0: return bvec4(false); //never\n" - " case 1: return lessThan(CMP_FIXUP(a), CMP_FIXUP(b)); //less\n" - " case 2: return equal(CMP_FIXUP(a), CMP_FIXUP(b)); //equal\n" - " case 3: return lessThanEqual(CMP_FIXUP(a), CMP_FIXUP(b)); //lequal\n" - " case 4: return greaterThan(CMP_FIXUP(a), CMP_FIXUP(b)); //greater\n" - " case 5: return notEqual(CMP_FIXUP(a), CMP_FIXUP(b)); //nequal\n" - " case 6: return greaterThanEqual(CMP_FIXUP(a), CMP_FIXUP(b)); //gequal\n" - " case 7: return bvec4(true); //always\n" - " }\n" - "}\n\n"; - } - - void insert_fog_declaration(std::ostream& OS, std::string_view wide_vector_type, std::string_view input_coord) - { - define_glsl_constants(OS, + for (const auto& e : enums) { - { "FOG_LINEAR", rsx::fog_mode::linear }, - { "FOG_EXP", rsx::fog_mode::exponential }, - { "FOG_EXP2", rsx::fog_mode::exponential2 }, - { "FOG_LINEAR_ABS", rsx::fog_mode::linear_abs }, - { "FOG_EXP_ABS", rsx::fog_mode::exponential_abs }, - { "FOG_EXP2_ABS", rsx::fog_mode::exponential2_abs } - }); + OS << "#define " << e << "\n"; + } - std::string template_body = "$T fetch_fog_value(const in uint mode)\n"; - - template_body += - "{\n" - " $T result = $T($I.x, 0., 0., 0.);\n" - " switch(mode)\n" - " {\n" - " default:\n" - " return result;\n" - " case FOG_LINEAR:\n" - " //linear\n" - " result.y = fog_param1 * $I.x + (fog_param0 - 1.);\n" - " break;\n" - " case FOG_EXP:\n" - " //exponential\n" - " result.y = exp(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5));\n" - " break;\n" - " case FOG_EXP2:\n" - " //exponential2\n" - " result.y = exp(-pow(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), 2.));\n" - " break;\n" - " case FOG_EXP_ABS:\n" - " //exponential_abs\n" - " result.y = exp(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5));\n" - " break;\n" - " case FOG_EXP2_ABS:\n" - " //exponential2_abs\n" - " result.y = exp(-pow(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), 2.));\n" - " break;\n" - " case FOG_LINEAR_ABS:\n" - " //linear_abs\n" - " result.y = fog_param1 * abs($I.x) + (fog_param0 - 1.);\n" - " break;\n" - " }\n" - "\n" - " result.y = clamp(result.y, 0., 1.);\n" - " return result;\n" - "}\n\n"; - - std::pair replacements[] = - { - std::make_pair("$T", std::string(wide_vector_type)), - std::make_pair("$I", std::string(input_coord)) - }; - - OS << fmt::replace_all(template_body, replacements); + OS << "\n"; } } @@ -522,6 +432,17 @@ namespace glsl void insert_glsl_legacy_function(std::ostream& OS, const shader_properties& props) { + std::vector enabled_options; + if (props.low_precision_tests) + { + enabled_options.push_back("_GPU_LOW_PRECISION_COMPARE"); + } + + if (props.require_lit_emulation) + { + enabled_options.push_back("_ENABLE_LIT_EMULATION"); + } + OS << "#define _select mix\n"; OS << "#define _saturate(x) clamp(x, 0., 1.)\n"; OS << "#define _get_bits(x, off, count) bitfieldExtract(x, off, count)\n"; @@ -529,508 +450,182 @@ namespace glsl OS << "#define _test_bit(x, y) (_get_bits(x, y, 1) != 0)\n"; OS << "#define _rand(seed) fract(sin(dot(seed.xy, vec2(12.9898f, 78.233f))) * 43758.5453f)\n\n"; - if (props.low_precision_tests) - { - OS << "#define CMP_FIXUP(a) (sign(a) * 16. + a)\n\n"; - } - else - { - OS << "#define CMP_FIXUP(a) (a)\n\n"; - } if (props.domain == glsl::program_domain::glsl_fragment_program) { OS << "// ROP control\n"; - OS << "#define ALPHA_TEST_ENABLE_BIT " << rsx::ROP_control_bits::ALPHA_TEST_ENABLE_BIT << "\n"; - OS << "#define SRGB_FRAMEBUFFER_BIT " << rsx::ROP_control_bits::SRGB_FRAMEBUFFER_BIT << "\n"; - OS << "#define ALPHA_TO_COVERAGE_ENABLE_BIT " << rsx::ROP_control_bits::ALPHA_TO_COVERAGE_ENABLE_BIT << "\n"; - OS << "#define MSAA_WRITE_ENABLE_BIT " << rsx::ROP_control_bits::MSAA_WRITE_ENABLE_BIT << "\n"; - OS << "#define INT_FRAMEBUFFER_BIT " << rsx::ROP_control_bits::INT_FRAMEBUFFER_BIT << "\n"; - OS << "#define POLYGON_STIPPLE_ENABLE_BIT " << rsx::ROP_control_bits::POLYGON_STIPPLE_ENABLE_BIT << "\n"; - OS << "#define ALPHA_TEST_FUNC_OFFSET " << rsx::ROP_control_bits::ALPHA_FUNC_OFFSET << "\n"; - OS << "#define ALPHA_TEST_FUNC_LENGTH " << rsx::ROP_control_bits::ALPHA_FUNC_NUM_BITS << "\n"; - OS << "#define MSAA_SAMPLE_CTRL_OFFSET " << rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_OFFSET << "\n"; - OS << "#define MSAA_SAMPLE_CTRL_LENGTH " << rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_NUM_BITS << "\n"; - OS << "#define ROP_CMD_MASK " << rsx::ROP_control_bits::ROP_CMD_MASK << "\n\n"; - - // 8-bit rounding/quantization + program_common::define_glsl_constants(OS, { - const auto _16bit_outputs = (!props.fp32_outputs && props.supports_native_fp16); - const auto _255 = _16bit_outputs ? "f16vec4(255.)" : "vec4(255.)"; - const auto _1_over_2 = _16bit_outputs ? "f16vec4(0.5)" : "vec4(0.5)"; - OS << "#define round_to_8bit(v4) (floor(fma(v4, " << _255 << ", " << _1_over_2 << ")) / " << _255 << ")\n\n"; + { "ALPHA_TEST_ENABLE_BIT ", rsx::ROP_control_bits::ALPHA_TEST_ENABLE_BIT }, + { "SRGB_FRAMEBUFFER_BIT ", rsx::ROP_control_bits::SRGB_FRAMEBUFFER_BIT }, + { "ALPHA_TO_COVERAGE_ENABLE_BIT ", rsx::ROP_control_bits::ALPHA_TO_COVERAGE_ENABLE_BIT }, + { "MSAA_WRITE_ENABLE_BIT ", rsx::ROP_control_bits::MSAA_WRITE_ENABLE_BIT }, + { "INT_FRAMEBUFFER_BIT ", rsx::ROP_control_bits::INT_FRAMEBUFFER_BIT }, + { "POLYGON_STIPPLE_ENABLE_BIT ", rsx::ROP_control_bits::POLYGON_STIPPLE_ENABLE_BIT }, + { "ALPHA_TEST_FUNC_OFFSET ", rsx::ROP_control_bits::ALPHA_FUNC_OFFSET }, + { "ALPHA_TEST_FUNC_LENGTH ", rsx::ROP_control_bits::ALPHA_FUNC_NUM_BITS }, + { "MSAA_SAMPLE_CTRL_OFFSET ", rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_OFFSET }, + { "MSAA_SAMPLE_CTRL_LENGTH ", rsx::ROP_control_bits::MSAA_SAMPLE_CTRL_NUM_BITS }, + { "ROP_CMD_MASK ", rsx::ROP_control_bits::ROP_CMD_MASK } + }); + + if (props.fp32_outputs || !props.supports_native_fp16) + { + enabled_options.push_back("_32_BIT_OUTPUT"); } - OS << "// Workaround for broken early discard in some drivers\n"; if (props.disable_early_discard) { - OS << "bool _fragment_discard = false;\n"; - OS << "#define _kill() _fragment_discard = true\n\n"; - } - else - { - OS << "#define _kill() discard\n\n"; - } - - if (props.require_texture_ops) - { - // Declare special texture control flags - OS << "#define GAMMA_R_MASK (1 << " << rsx::texture_control_bits::GAMMA_R << ")\n"; - OS << "#define GAMMA_G_MASK (1 << " << rsx::texture_control_bits::GAMMA_G << ")\n"; - OS << "#define GAMMA_B_MASK (1 << " << rsx::texture_control_bits::GAMMA_B << ")\n"; - OS << "#define GAMMA_A_MASK (1 << " << rsx::texture_control_bits::GAMMA_A << ")\n"; - OS << "#define EXPAND_R_MASK (1 << " << rsx::texture_control_bits::EXPAND_R << ")\n"; - OS << "#define EXPAND_G_MASK (1 << " << rsx::texture_control_bits::EXPAND_G << ")\n"; - OS << "#define EXPAND_B_MASK (1 << " << rsx::texture_control_bits::EXPAND_B << ")\n"; - OS << "#define EXPAND_A_MASK (1 << " << rsx::texture_control_bits::EXPAND_A << ")\n\n"; - - OS << "#define ALPHAKILL " << rsx::texture_control_bits::ALPHAKILL << "\n"; - OS << "#define RENORMALIZE " << rsx::texture_control_bits::RENORMALIZE << "\n"; - OS << "#define DEPTH_FLOAT " << rsx::texture_control_bits::DEPTH_FLOAT << "\n"; - OS << "#define DEPTH_COMPARE " << rsx::texture_control_bits::DEPTH_COMPARE_OP << "\n"; - OS << "#define FILTERED_MAG_BIT " << rsx::texture_control_bits::FILTERED_MAG << "\n"; - OS << "#define FILTERED_MIN_BIT " << rsx::texture_control_bits::FILTERED_MIN << "\n"; - OS << "#define INT_COORDS_BIT " << rsx::texture_control_bits::UNNORMALIZED_COORDS << "\n"; - OS << "#define GAMMA_CTRL_MASK (GAMMA_R_MASK|GAMMA_G_MASK|GAMMA_B_MASK|GAMMA_A_MASK)\n"; - OS << "#define SIGN_EXPAND_MASK (EXPAND_R_MASK|EXPAND_G_MASK|EXPAND_B_MASK|EXPAND_A_MASK)\n"; - OS << "#define FILTERED_MASK (FILTERED_MAG_BIT|FILTERED_MIN_BIT)\n\n"; + enabled_options.push_back("_DISABLE_EARLY_DISCARD"); } } - if (props.require_lit_emulation) - { - OS << - "vec4 lit_legacy(const in vec4 val)" - "{\n" - " vec4 clamped_val = val;\n" - " clamped_val.x = max(val.x, 0.);\n" - " clamped_val.y = max(val.y, 0.);\n" - " vec4 result;\n" - " result.x = 1.;\n" - " result.w = 1.;\n" - " result.y = clamped_val.x;\n" - " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 0.0000000001))) : 0.;\n" - " return result;\n" - "}\n\n"; - } + // Import common header + program_common::define_glsl_switches(OS, enabled_options); + enabled_options.clear(); + + OS << + #include "GLSLSnippets/RSXProg/RSXProgramCommon.glsl" + ; if (props.domain == glsl::program_domain::glsl_vertex_program) { if (props.require_explicit_invariance) { - // PS3 has shader invariance, but we don't really care about most attributes outside ATTR0 - OS << "invariant gl_Position;\n\n"; + enabled_options.push_back("_FORCE_POSITION_INVARIANCE"); } if (props.emulate_zclip_transform) { if (props.emulate_depth_clip_only) { - // Technically the depth value here is the 'final' depth that should be stored in the Z buffer. - // Forward mapping eqn is d' = d * (f - n) + n, where d' is the stored Z value (this) and d is the normalized API value. - OS << - "vec4 apply_zclip_xform(const in vec4 pos, const in float near_plane, const in float far_plane)\n" - "{\n" - " if (pos.w != 0.0)\n" - " {\n" - " const float real_n = min(far_plane, near_plane);\n" - " const float real_f = max(far_plane, near_plane);\n" - " const double depth_range = double(real_f - real_n);\n" - " const double inv_range = (depth_range > 0.000001) ? (1.0 / (depth_range * pos.w)) : 0.0;\n" - " const double actual_d = (double(pos.z) - double(real_n * pos.w)) * inv_range;\n" - " const double nearest_d = floor(actual_d + 0.5);\n" - " const double epsilon = (inv_range * pos.w) / 16777215.;\n" // Epsilon value is the minimum discernable change in Z that should affect the stored Z - " const double d = _select(actual_d, nearest_d, abs(actual_d - nearest_d) < epsilon);\n" - " return vec4(pos.xy, float(d * pos.w), pos.w);\n" - " }\n" - " else\n" - " {\n" - " return pos;\n" // Only values where Z=0 can ever pass this clip - " }\n" - "}\n\n"; + enabled_options.push_back("_EMULATE_ZCLIP_XFORM_STANDARD"); } else { - OS << - "vec4 apply_zclip_xform(const in vec4 pos, const in float near_plane, const in float far_plane)\n" - "{\n" - " float d = float(pos.z / pos.w);\n" - " if (d < 0.f && d >= near_plane)\n" - " {\n" - " // Clamp\n" - " d = 0.f;\n" - " }\n" - " else if (d > 1.f && d <= far_plane)\n" - " {\n" - " // Compress Z and store towards highest end of the range\n" - " d = min(1., 0.99 + (0.01 * (pos.z - near_plane) / (far_plane - near_plane)));\n" - " }\n" - " else\n" // This catch-call also handles w=0 since d=inf - " {\n" - " return pos;\n" - " }\n" - "\n" - " return vec4(pos.x, pos.y, d * pos.w, pos.w);\n" - "}\n\n"; + enabled_options.push_back("_EMULATE_ZCLIP_XFORM_FALLBACK"); } } + // Import vertex header + program_common::define_glsl_switches(OS, enabled_options); + + OS << + #include "GLSLSnippets/RSXProg/RSXVertexPrologue.glsl" + ; + return; } - program_common::insert_compare_op(OS); - if (props.emulate_coverage_tests) { - // Purely stochastic - OS << - "bool coverage_test_passes(const in vec4 _sample)\n" - "{\n" - " float random = _rand(gl_FragCoord);\n" - " return (_sample.a > random);\n" - "}\n\n"; + enabled_options.push_back("_EMULATE_COVERAGE_TEST"); } if (!props.fp32_outputs || props.require_linear_to_srgb) { - OS << - "vec4 linear_to_srgb(const in vec4 cl)\n" - "{\n" - " vec4 low = cl * 12.92;\n" - " vec4 high = 1.055 * pow(cl, vec4(1. / 2.4)) - 0.055;\n" - " bvec4 selection = lessThan(cl, vec4(0.0031308));\n" - " return clamp(mix(high, low, selection), 0., 1.);\n" - "}\n\n"; + enabled_options.push_back("_ENABLE_LINEAR_TO_SRGB"); } if (props.require_texture_ops || props.require_srgb_to_linear) { - OS << - "vec4 srgb_to_linear(const in vec4 cs)\n" - "{\n" - " vec4 a = cs / 12.92;\n" - " vec4 b = pow((cs + 0.055) / 1.055, vec4(2.4));\n" - " return _select(a, b, greaterThan(cs, vec4(0.04045)));\n" - "}\n\n"; + enabled_options.push_back("_ENABLE_SRGB_TO_LINEAR"); } - if (props.require_depth_conversion) + if (props.require_wpos) { - ensure(props.require_texture_ops); - - //NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS) - //The A component (Z) is useless (should contain stencil8 or just 1) - OS << - "vec4 decode_depth24(const in float depth_value, const in bool depth_float)\n" - "{\n" - " uint value;\n" - " if (!depth_float)\n" - " value = uint(depth_value * 16777215.);\n" - " else\n" - " value = _get_bits(floatBitsToUint(depth_value), 7, 24);\n" - "\n" - " uint b = _get_bits(value, 0, 8);\n" - " uint g = _get_bits(value, 8, 8);\n" - " uint r = _get_bits(value, 16, 8);\n" - " return vec4(float(g)/255., float(b)/255., 1., float(r)/255.);\n" - "}\n\n" - - "vec4 remap_vector(const in vec4 color, const in uint remap)\n" - "{\n" - " vec4 result;\n" - " if (_get_bits(remap, 0, 8) == 0xE4)\n" - " {\n" - " result = color;\n" - " }\n" - " else\n" - " {\n" - " uvec4 remap_channel = uvec4(remap) >> uvec4(2, 4, 6, 0);\n" - " remap_channel &= 3;\n" - " remap_channel = (remap_channel + 3) % 4; // Map A-R-G-B to R-G-B-A\n\n" - - " // Generate remapped result\n" - " result.a = color[remap_channel.a];\n" - " result.r = color[remap_channel.r];\n" - " result.g = color[remap_channel.g];\n" - " result.b = color[remap_channel.b];\n" - " }\n\n" - - " if (_get_bits(remap, 8, 8) == 0xAA)\n" - " return result;\n\n" - - " uvec4 remap_select = uvec4(remap) >> uvec4(10, 12, 14, 8);\n" - " remap_select &= 3;\n" - " bvec4 choice = lessThan(remap_select, uvec4(2));\n" - " return _select(result, vec4(remap_select), choice);\n" - "}\n\n" - - "vec4 convert_z24x8_to_rgba8(const in vec2 depth_stencil, const in uint remap, const in uint flags)\n" - "{\n" - " vec4 result = decode_depth24(depth_stencil.x, _test_bit(flags, DEPTH_FLOAT));\n" - " result.z = depth_stencil.y / 255.;\n\n" - - " if (remap == 0xAAE4)\n" - " return result;\n\n" - - " return remap_vector(result, remap);\n" - "}\n\n"; + enabled_options.push_back("_ENABLE_WPOS"); } + if (props.require_fog_read) + { + program_common::define_glsl_constants(OS, + { + { "FOG_LINEAR", rsx::fog_mode::linear }, + { "FOG_EXP", rsx::fog_mode::exponential }, + { "FOG_EXP2", rsx::fog_mode::exponential2 }, + { "FOG_LINEAR_ABS", rsx::fog_mode::linear_abs }, + { "FOG_EXP_ABS", rsx::fog_mode::exponential_abs }, + { "FOG_EXP2_ABS", rsx::fog_mode::exponential2_abs }, + }); + + enabled_options.push_back("_ENABLE_FOG_READ"); + } + + // Import fragment header + program_common::define_glsl_switches(OS, enabled_options); + enabled_options.clear(); + + OS << + #include "GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl" + ; + if (props.require_texture_ops) { - OS << + // Declare special texture control flags + OS << "#define GAMMA_R_MASK (1 << " << rsx::texture_control_bits::GAMMA_R << ")\n"; + OS << "#define GAMMA_G_MASK (1 << " << rsx::texture_control_bits::GAMMA_G << ")\n"; + OS << "#define GAMMA_B_MASK (1 << " << rsx::texture_control_bits::GAMMA_B << ")\n"; + OS << "#define GAMMA_A_MASK (1 << " << rsx::texture_control_bits::GAMMA_A << ")\n"; + OS << "#define EXPAND_R_MASK (1 << " << rsx::texture_control_bits::EXPAND_R << ")\n"; + OS << "#define EXPAND_G_MASK (1 << " << rsx::texture_control_bits::EXPAND_G << ")\n"; + OS << "#define EXPAND_B_MASK (1 << " << rsx::texture_control_bits::EXPAND_B << ")\n"; + OS << "#define EXPAND_A_MASK (1 << " << rsx::texture_control_bits::EXPAND_A << ")\n\n"; - //TODO: Move all the texture read control operations here - "vec4 process_texel(in vec4 rgba, const in uint control_bits)\n" - "{\n" - " if (control_bits == 0)\n" - " {\n" - " return rgba;\n" - " }\n" - "\n" - " if (_test_bit(control_bits, ALPHAKILL))\n" - " {\n" - " // Alphakill\n" - " if (rgba.a < 0.000001)\n" - " {\n" - " _kill();\n" - " return rgba;\n" - " }\n" - " }\n" - "\n" - " if (_test_bit(control_bits, RENORMALIZE))\n" - " {\n" - " // Renormalize to 8-bit (PS3) accuracy\n" - " rgba = floor(rgba * 255.);\n" - " rgba /= 255.;\n" - " }\n" - "\n" - " uvec4 mask;\n" - " vec4 convert;\n" - " uint op_mask = control_bits & uint(SIGN_EXPAND_MASK);\n" - "\n" - " if (op_mask != 0)\n" - " {\n" - " // Expand to signed normalized\n" - " mask = uvec4(op_mask) & uvec4(EXPAND_R_MASK, EXPAND_G_MASK, EXPAND_B_MASK, EXPAND_A_MASK);\n" - " convert = (rgba * 2.f - 1.f);\n" - " rgba = _select(rgba, convert, notEqual(mask, uvec4(0)));\n" - " }\n" - "\n" - " op_mask = control_bits & uint(GAMMA_CTRL_MASK);\n" - " if (op_mask != 0u)\n" - " {\n" - " // Gamma correction\n" - " mask = uvec4(op_mask) & uvec4(GAMMA_R_MASK, GAMMA_G_MASK, GAMMA_B_MASK, GAMMA_A_MASK);\n" - " convert = srgb_to_linear(rgba);\n" - " return _select(rgba, convert, notEqual(mask, uvec4(0)));\n" - " }\n" - "\n" - " return rgba;\n" - "}\n\n"; + OS << "#define ALPHAKILL " << rsx::texture_control_bits::ALPHAKILL << "\n"; + OS << "#define RENORMALIZE " << rsx::texture_control_bits::RENORMALIZE << "\n"; + OS << "#define DEPTH_FLOAT " << rsx::texture_control_bits::DEPTH_FLOAT << "\n"; + OS << "#define DEPTH_COMPARE " << rsx::texture_control_bits::DEPTH_COMPARE_OP << "\n"; + OS << "#define FILTERED_MAG_BIT " << rsx::texture_control_bits::FILTERED_MAG << "\n"; + OS << "#define FILTERED_MIN_BIT " << rsx::texture_control_bits::FILTERED_MIN << "\n"; + OS << "#define INT_COORDS_BIT " << rsx::texture_control_bits::UNNORMALIZED_COORDS << "\n"; + OS << "#define GAMMA_CTRL_MASK (GAMMA_R_MASK|GAMMA_G_MASK|GAMMA_B_MASK|GAMMA_A_MASK)\n"; + OS << "#define SIGN_EXPAND_MASK (EXPAND_R_MASK|EXPAND_G_MASK|EXPAND_B_MASK|EXPAND_A_MASK)\n"; + OS << "#define FILTERED_MASK (FILTERED_MAG_BIT|FILTERED_MIN_BIT)\n\n"; if (props.require_texture_expand) { - OS << - "uint _texture_flag_override = 0;\n" - "#define _enable_texture_expand() _texture_flag_override = SIGN_EXPAND_MASK\n" - "#define _disable_texture_expand() _texture_flag_override = 0\n" - "#define TEX_FLAGS(index) (texture_parameters[index].flags | _texture_flag_override)\n"; + enabled_options.push_back("_ENABLE_TEXTURE_EXPAND"); } - else - { - OS << - "#define TEX_FLAGS(index) texture_parameters[index].flags\n"; - } - - OS << - "#define TEX_NAME(index) tex##index\n" - "#define TEX_NAME_STENCIL(index) tex##index##_stencil\n\n" - - "#define COORD_SCALE1(index, coord1) ((coord1 + texture_parameters[index].scale_bias.w) * texture_parameters[index].scale_bias.x)\n" - "#define COORD_SCALE2(index, coord2) ((coord2 + texture_parameters[index].scale_bias.w) * texture_parameters[index].scale_bias.xy)\n" - "#define COORD_SCALE3(index, coord3) ((coord3 + texture_parameters[index].scale_bias.w) * texture_parameters[index].scale_bias.xyz)\n\n" - - "#define TEX1D(index, coord1) process_texel(texture(TEX_NAME(index), COORD_SCALE1(index, coord1)), TEX_FLAGS(index))\n" - "#define TEX1D_BIAS(index, coord1, bias) process_texel(texture(TEX_NAME(index), COORD_SCALE1(index, coord1), bias), TEX_FLAGS(index))\n" - "#define TEX1D_LOD(index, coord1, lod) process_texel(textureLod(TEX_NAME(index), COORD_SCALE1(index, coord1), lod), TEX_FLAGS(index))\n" - "#define TEX1D_GRAD(index, coord1, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), COORD_SCALE1(index, coord1), dpdx, dpdy), TEX_FLAGS(index))\n" - "#define TEX1D_PROJ(index, coord4) process_texel(textureProj(TEX_NAME(index), vec2(COORD_SCALE1(index, coord4.x), coord4.w)), TEX_FLAGS(index))\n" - - "#define TEX2D(index, coord2) process_texel(texture(TEX_NAME(index), COORD_SCALE2(index, coord2)), TEX_FLAGS(index))\n" - "#define TEX2D_BIAS(index, coord2, bias) process_texel(texture(TEX_NAME(index), COORD_SCALE2(index, coord2), bias), TEX_FLAGS(index))\n" - "#define TEX2D_LOD(index, coord2, lod) process_texel(textureLod(TEX_NAME(index), COORD_SCALE2(index, coord2), lod), TEX_FLAGS(index))\n" - "#define TEX2D_GRAD(index, coord2, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), COORD_SCALE2(index, coord2), dpdx, dpdy), TEX_FLAGS(index))\n" - "#define TEX2D_PROJ(index, coord4) process_texel(textureProj(TEX_NAME(index), vec4(COORD_SCALE2(index, coord4.xy), coord4.z, coord4.w)), TEX_FLAGS(index))\n\n"; if (props.emulate_shadow_compare) { - OS << - "#define SHADOW_COORD(index, coord3) vec3(COORD_SCALE2(index, coord3.xy), _test_bit(TEX_FLAGS(index), DEPTH_FLOAT)? coord3.z : min(float(coord3.z), 1.0))\n" - "#define SHADOW_COORD4(index, coord4) vec4(SHADOW_COORD(index, coord4.xyz), coord4.w)\n" - "#define SHADOW_COORD_PROJ(index, coord4) vec4(COORD_SCALE2(index, coord4.xy), _test_bit(TEX_FLAGS(index), DEPTH_FLOAT)? coord4.z : min(coord4.z, coord4.w), coord4.w)\n\n" + enabled_options.push_back("_EMULATED_TEXSHADOW"); + } - "#define TEX2D_SHADOW(index, coord3) texture(TEX_NAME(index), SHADOW_COORD(index, coord3))\n" - "#define TEX3D_SHADOW(index, coord4) texture(TEX_NAME(index), SHADOW_COORD4(index, coord4))\n" - "#define TEX2D_SHADOWPROJ(index, coord4) textureProj(TEX_NAME(index), SHADOW_COORD_PROJ(index, coord4))\n"; - } - else - { - OS << - "#define TEX2D_SHADOW(index, coord3) texture(TEX_NAME(index), vec3(COORD_SCALE2(index, coord3.xy), coord3.z))\n" - "#define TEX3D_SHADOW(index, coord4) texture(TEX_NAME(index), vec4(COORD_SCALE3(index, coord4.xyz), coord4.w))\n" - "#define TEX2D_SHADOWPROJ(index, coord4) textureProj(TEX_NAME(index), vec4(COORD_SCALE2(index, coord4.xy), coord4.zw))\n"; - } + program_common::define_glsl_switches(OS, enabled_options); + enabled_options.clear(); OS << - "#define TEX3D(index, coord3) process_texel(texture(TEX_NAME(index), COORD_SCALE3(index, coord3)), TEX_FLAGS(index))\n" - "#define TEX3D_BIAS(index, coord3, bias) process_texel(texture(TEX_NAME(index), COORD_SCALE3(index, coord3), bias), TEX_FLAGS(index))\n" - "#define TEX3D_LOD(index, coord3, lod) process_texel(textureLod(TEX_NAME(index), COORD_SCALE3(index, coord3), lod), TEX_FLAGS(index))\n" - "#define TEX3D_GRAD(index, coord3, dpdx, dpdy) process_texel(textureGrad(TEX_NAME(index), COORD_SCALE3(index, coord3), dpdx, dpdy), TEX_FLAGS(index))\n" - "#define TEX3D_PROJ(index, coord4) process_texel(texture(TEX_NAME(index), COORD_SCALE3(index, coord4.xyz) / coord4.w), TEX_FLAGS(index))\n\n"; + #include "GLSLSnippets/RSXProg/RSXFragmentTextureOps.glsl" + ; if (props.require_depth_conversion) { OS << - "#define ZS_READ(index, coord) vec2(texture(TEX_NAME(index), coord).r, float(texture(TEX_NAME_STENCIL(index), coord).x))\n" - "#define TEX1D_Z24X8_RGBA8(index, coord1) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE1(index, coord1)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n" - "#define TEX2D_Z24X8_RGBA8(index, coord2) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE2(index, coord2)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n" - "#define TEX3D_Z24X8_RGBA8(index, coord3) process_texel(convert_z24x8_to_rgba8(ZS_READ(index, COORD_SCALE3(index, coord3)), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n\n"; + #include "GLSLSnippets/RSXProg/RSXFragmentTextureDepthConversion.glsl" + ; } if (props.require_msaa_ops) { OS << - "#define ZCOMPARE_FUNC(index) _get_bits(TEX_FLAGS(index), DEPTH_COMPARE, 3)\n" - "#define ZS_READ_MS(index, coord) vec2(sampleTexture2DMS(TEX_NAME(index), coord, index).r, float(sampleTexture2DMS(TEX_NAME_STENCIL(index), coord, index).x))\n" - "#define TEX2D_MS(index, coord2) process_texel(sampleTexture2DMS(TEX_NAME(index), coord2, index), TEX_FLAGS(index))\n" - "#define TEX2D_SHADOW_MS(index, coord3) vec4(comparison_passes(sampleTexture2DMS(TEX_NAME(index), coord3.xy, index).x, coord3.z, ZCOMPARE_FUNC(index)))\n" - "#define TEX2D_SHADOWPROJ_MS(index, coord4) TEX2D_SHADOW_MS(index, (coord4.xyz / coord4.w))\n" - "#define TEX2D_Z24X8_RGBA8_MS(index, coord2) process_texel(convert_z24x8_to_rgba8(ZS_READ_MS(index, coord2), texture_parameters[index].remap, TEX_FLAGS(index)), TEX_FLAGS(index))\n\n"; + #include "GLSLSnippets/RSXProg/RSXFragmentTextureMSAAOps.glsl" + ; - OS << - "vec3 compute2x2DownsampleWeights(const in float coord, const in float uv_step, const in float actual_step)" - "{\n" - " const float next_sample_point = coord + actual_step;\n" - " const float next_coord_step = fma(floor(coord / uv_step), uv_step, uv_step);\n" - " const float next_coord_step_plus_one = next_coord_step + uv_step;\n" - " vec3 weights = vec3(next_coord_step, min(next_coord_step_plus_one, next_sample_point), max(next_coord_step_plus_one, next_sample_point)) - vec3(coord, next_coord_step, next_coord_step_plus_one);\n" - " return weights / actual_step;\n" - "}\n\n"; + // Generate multiple versions of the actual sampler code. + // We could use defines to generate these, but I don't trust some OpenGL compilers to do the right thing. + const std::string_view msaa_sampling_impl = + #include "GLSLSnippets/RSXProg/RSXFragmentTextureMSAAOpsInternal.glsl" + ; - auto insert_msaa_sample_code = [&OS](const std::string_view& sampler_type) - { - OS << - "vec4 texelFetch2DMS(in " << sampler_type << " tex, const in vec2 sample_count, const in ivec2 icoords, const in int index, const in ivec2 offset)\n" - "{\n" - " const vec2 resolve_coords = vec2(icoords + offset);\n" - " const vec2 aa_coords = floor(resolve_coords / sample_count);\n" // AA coords = real_coords / sample_count - " const vec2 sample_loc = fma(aa_coords, -sample_count, resolve_coords);\n" // Sample ID = real_coords % sample_count - " const float sample_index = fma(sample_loc.y, sample_count.y, sample_loc.x);\n" - " return texelFetch(tex, ivec2(aa_coords), int(sample_index));\n" - "}\n\n" - - "vec4 sampleTexture2DMS(in " << sampler_type << " tex, const in vec2 coords, const in int index)\n" - "{\n" - " const uint flags = TEX_FLAGS(index);\n" - " const vec2 normalized_coords = COORD_SCALE2(index, coords);\n" - " const vec2 sample_count = vec2(2., textureSamples(tex) * 0.5);\n" - " const vec2 image_size = textureSize(tex) * sample_count;\n" - " const ivec2 icoords = ivec2(normalized_coords * image_size);\n" - " const vec4 sample0 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(0));\n" - "\n" - " if (_get_bits(flags, FILTERED_MAG_BIT, 2) == 0)\n" - " {\n" - " return sample0;\n" - " }\n" - "\n" - " // Bilinear scaling, with upto 2x2 downscaling with simple weights\n" - " const vec2 uv_step = 1.0 / vec2(image_size);\n" - " const vec2 actual_step = vec2(dFdx(normalized_coords.x), dFdy(normalized_coords.y));\n" - "\n" - " const bvec2 no_filter = lessThan(abs(uv_step - actual_step), vec2(0.000001));\n" - " if (no_filter.x && no_filter.y)\n" - " {\n" - " return sample0;\n" - " }\n" - "\n" - " vec4 a, b;\n" - " float factor;\n" - " const vec4 sample2 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(0, 1)); // Top left\n" - "\n" - " if (no_filter.x)\n" - " {\n" - " // No scaling, 1:1\n" - " a = sample0;\n" - " b = sample2;\n" - " }\n" - " else\n" - " {\n" - " // Filter required, sample more data\n" - " const vec4 sample1 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(1, 0)); // Bottom right\n" - " const vec4 sample3 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(1, 1)); // Top right\n" - "\n" - " if (actual_step.x > uv_step.x)\n" - " {\n" - " // Downscale in X, centered\n" - " const vec3 weights = compute2x2DownsampleWeights(normalized_coords.x, uv_step.x, actual_step.x);\n" - "\n" - " const vec4 sample4 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(2, 0)); // Further bottom right\n" - " a = fma(sample0, weights.xxxx, sample1 * weights.y) + (sample4 * weights.z); // Weighted sum\n" - "\n" - " if (!no_filter.y)\n" - " {\n" - " const vec4 sample5 = texelFetch2DMS(tex, sample_count, icoords, index, ivec2(2, 1)); // Further top right\n" - " b = fma(sample2, weights.xxxx, sample3 * weights.y) + (sample5 * weights.z); // Weighted sum\n" - " }\n" - " }\n" - " else if (actual_step.x < uv_step.x)\n" - " {\n" - " // Upscale in X\n" - " factor = fract(normalized_coords.x * image_size.x);\n" - " a = mix(sample0, sample1, factor);\n" - " b = mix(sample2, sample3, factor);\n" - " }\n" - " }\n" - "\n" - " if (no_filter.y)\n" - " {\n" - " // 1:1 no scale\n" - " return a;\n" - " }\n" - " else if (actual_step.y > uv_step.y)\n" - " {\n" - " // Downscale in Y\n" - " const vec3 weights = compute2x2DownsampleWeights(normalized_coords.y, uv_step.y, actual_step.y);\n" - " // We only have 2 rows computed for performance reasons, so combine rows 1 and 2\n" - " return a * weights.x + b * (weights.y + weights.z);\n" - " }\n" - " else if (actual_step.y < uv_step.y)\n" - " {\n" - " // Upscale in Y\n" - " factor = fract(normalized_coords.y * image_size.y);\n" - " return mix(a, b, factor);\n" - " }\n" - "}\n\n"; - }; - - insert_msaa_sample_code("sampler2DMS"); + OS << fmt::replace_all(msaa_sampling_impl, "_MSAA_SAMPLER_TYPE_", "sampler2DMS"); if (props.require_depth_conversion) { - insert_msaa_sample_code("usampler2DMS"); + OS << fmt::replace_all(msaa_sampling_impl, "_MSAA_SAMPLER_TYPE_", "usampler2DMS"); } } } - - if (props.require_wpos) - { - OS << - "vec4 get_wpos()\n" - "{\n" - " float abs_scale = abs(wpos_scale);\n" - " return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(0., wpos_bias, 0., 0.);\n" - "}\n\n"; - } } std::string getFunctionImpl(FUNCTION f) @@ -1152,12 +747,8 @@ namespace glsl // Global types and stuff // Must be compatible with std140 packing rules OS << - "struct sampler_info\n" - "{\n" - " vec4 scale_bias;\n" - " uint remap;\n" - " uint flags;\n" - "};\n\n"; + #include "GLSLSnippets/RSXProg/RSXDefines2.glsl" + ; } void insert_fragment_shader_inputs_block( diff --git a/rpcs3/Emu/RSX/Program/GLSLCommon.h b/rpcs3/Emu/RSX/Program/GLSLCommon.h index 4346b3d5fe..dba5c1c630 100644 --- a/rpcs3/Emu/RSX/Program/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Program/GLSLCommon.h @@ -76,13 +76,6 @@ namespace rsx }; } -namespace program_common -{ - void insert_compare_op(std::ostream& OS, bool low_precision); - void insert_compare_op_vector(std::ostream& OS); - void insert_fog_declaration(std::ostream& OS, std::string_view vector_type = "vec4", std::string_view input_coord = "fog_c"); -} - namespace glsl { struct two_sided_lighting_config diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl index b3c98e0870..01e83f3c2d 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXFragmentPrologue.glsl @@ -1,5 +1,4 @@ R"( - #ifdef _32_BIT_OUTPUT // Default. Used when we're not utilizing native fp16 #define round_to_8bit(v4) (floor(fma(v4, vec4(255.), vec4(0.5))) / vec4(255.)) @@ -9,9 +8,10 @@ R"( #endif #ifdef _DISABLE_EARLY_DISCARD -#define kill() _fragment_discard = true +bool _fragment_discard = false; +#define _kill() _fragment_discard = true #else -#define kill() discard +#define _kill() discard #endif #ifdef _ENABLE_WPOS @@ -22,6 +22,73 @@ vec4 get_wpos() } #endif +#ifdef _ENABLE_FOG_READ +vec4 fetch_fog_value(const in uint mode) +{ + vec4 result = vec4(fog_c.x, 0., 0., 0.); + switch(mode) + { + default: + return result; + case FOG_LINEAR: + // linear + result.y = fog_param1 * fog_c.x + (fog_param0 - 1.); + break; + case FOG_EXP: + // exponential + result.y = exp(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5)); + break; + case FOG_EXP2: + // exponential2 + result.y = exp(-pow(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), 2.)); + break; + case FOG_EXP_ABS: + // exponential_abs + result.y = exp(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)); + break; + case FOG_EXP2_ABS: + // exponential2_abs + result.y = exp(-pow(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), 2.)); + break; + case FOG_LINEAR_ABS: + // linear_abs + result.y = fog_param1 * abs(fog_c.x) + (fog_param0 - 1.); + break; + } + + result.y = clamp(result.y, 0., 1.); + return result; +} +#endif + +#ifdef _EMULATE_COVERAGE_TEST +// Purely stochastic +bool coverage_test_passes(const in vec4 _sample) +{ + float random = _rand(gl_FragCoord); + return (_sample.a > random); +} +#endif + +#ifdef _ENABLE_LINEAR_TO_SRGB +vec4 linear_to_srgb(const in vec4 cl) +{ + vec4 low = cl * 12.92; + vec4 high = 1.055 * pow(cl, vec4(1. / 2.4)) - 0.055; + bvec4 selection = lessThan(cl, vec4(0.0031308)); + return clamp(mix(high, low, selection), 0., 1.); +} +#endif + +#ifdef _ENABLE_SRGB_TO_LINEAR +vec4 srgb_to_linear(const in vec4 cs) +{ + vec4 a = cs / 12.92; + vec4 b = pow((cs + 0.055) / 1.055, vec4(2.4)); + return _select(a, b, greaterThan(cs, vec4(0.04045))); +} +#endif + // Required by all fragment shaders for alpha test bool comparison_passes(const in float a, const in float b, const in uint func) { diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXProgramCommon.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXProgramCommon.glsl index 887212f1d2..4e9574a4e5 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXProgramCommon.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXProgramCommon.glsl @@ -24,4 +24,4 @@ vec4 lit_legacy(const in vec4 val) } #endif -)" \ No newline at end of file +)" diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXVertexPrologue.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXVertexPrologue.glsl index 23e272625f..3342802652 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXVertexPrologue.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/RSXProg/RSXVertexPrologue.glsl @@ -1,5 +1,6 @@ R"( #ifdef _FORCE_POSITION_INVARIANCE +// PS3 has shader invariance, but we don't really care about most attributes outside ATTR0 invariant gl_Position; #endif @@ -54,5 +55,4 @@ vec4 apply_zclip_xform( }\n #endif - )" diff --git a/rpcs3/Emu/RSX/Program/GLSLTypes.h b/rpcs3/Emu/RSX/Program/GLSLTypes.h index 7bfb84f8ce..4e31a369ef 100644 --- a/rpcs3/Emu/RSX/Program/GLSLTypes.h +++ b/rpcs3/Emu/RSX/Program/GLSLTypes.h @@ -32,6 +32,7 @@ namespace glsl bool require_srgb_to_linear : 1; bool require_linear_to_srgb : 1; bool require_explicit_invariance: 1; + bool require_fog_read : 1; bool emulate_coverage_tests : 1; bool emulate_shadow_compare : 1; bool emulate_zclip_transform : 1; diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 412b939fe7..dd7a83d8cd 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -243,6 +243,7 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) m_shader_props.require_texture_expand = properties.has_exp_tex_op; m_shader_props.require_srgb_to_linear = properties.has_upg; m_shader_props.require_linear_to_srgb = properties.has_pkg; + m_shader_props.require_fog_read = properties.in_register_mask & in_fogc; m_shader_props.emulate_coverage_tests = g_cfg.video.antialiasing_level == msaa_level::none; m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare; m_shader_props.low_precision_tests = device_props.has_low_precision_rounding && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION); @@ -255,9 +256,6 @@ void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { - if (properties.in_register_mask & in_fogc) - program_common::insert_fog_declaration(OS); - std::set output_registers; if (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) {