From 153a2d2b40be98d74c37833868b1906556b2c18d Mon Sep 17 00:00:00 2001 From: Oil Date: Wed, 14 Sep 2016 17:47:53 +0300 Subject: [PATCH] Fixed fog and alphakill implementation in glsl (based on DH's old commits) (#2137) * Fixed NV4097_SET_COLOR_CLEAR_VALUE * Fixed fog and alphakill implementation in glsl (based on DH's old commits) --- rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp | 113 +++++++++++++++++-------- rpcs3/Emu/RSX/RSXFragmentProgram.h | 3 + rpcs3/Emu/RSX/RSXThread.cpp | 10 +++ 3 files changed, 93 insertions(+), 33 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 68ec3ae1d9..94922c881c 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -88,6 +88,7 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) int index = atoi(&PI.name.data()[3]); OS << "uniform " << samplerType << " " << PI.name << ";" << std::endl; + OS << "uniform " << "vec4 " << "f" << PI.name << "_cm = vec4(1.0);" << std::endl; } } @@ -118,33 +119,69 @@ namespace // But it makes more sense to compute exp of interpoled value than to interpolate exp values. void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode) { + std::string fog_func = {}; switch (mode) { case rsx::fog_mode::linear: - OS << " vec4 fogc = vec4(fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.), 0., 0.);\n"; - return; + fog_func = "fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.)"; + break; case rsx::fog_mode::exponential: - OS << " vec4 fogc = vec4(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5)), 0., 0.);\n"; - return; + fog_func = "11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5))"; + break; case rsx::fog_mode::exponential2: - OS << " vec4 fogc = vec4(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5)), 2.), 0., 0.);\n"; - return; + fog_func = "4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5)), 2.)"; + break; case rsx::fog_mode::linear_abs: - OS << " vec4 fogc = vec4(fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), 0., 0.);\n"; - return; + fog_func = "fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), fog_param1 * abs(fog_c.x) + (fog_param0 - 1.)"; + break; case rsx::fog_mode::exponential_abs: - OS << " vec4 fogc = vec4(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)), 0., 0.);\n"; - return; + fog_func = "11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5))"; + break; case rsx::fog_mode::exponential2_abs: - OS << " vec4 fogc = vec4(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)), 2.), 0., 0.);\n"; - return; + fog_func = "4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)), 2.)"; + break; + + default: fog_func = "0.0, 0.0"; } + + OS << " vec4 fogc = clamp(vec4(" << fog_func << ", 0., 0.), 0., 1.);\n"; + } + + void insert_texture_fetch(std::stringstream & OS, const RSXFragmentProgram& prog, const ParamArray& param) + { + OS << "vec4 texture_fetch(int index, vec4 coord)\n{\n"; + OS << " switch (index)\n\t{\n"; + + for (u8 id = 0; id < 16; id++) + { + if (prog.textures_alpha_kill[id]) + { + OS << " case " + std::to_string(id) + ": return "; + + switch (prog.get_texture_dimension(id)) + { + case rsx::texture_dimension_extended::texture_dimension_1d: OS << "texture(tex" + std::to_string(id) + ", coord.x)"; break; + case rsx::texture_dimension_extended::texture_dimension_2d: OS << "texture(tex" + std::to_string(id) + ", coord.xy)"; break; + case rsx::texture_dimension_extended::texture_dimension_3d: + case rsx::texture_dimension_extended::texture_dimension_cubemap: OS << "texture(tex" + std::to_string(id) + ", coord.xyz)"; break; + + default: OS << "vec4(0.0)"; + } + + OS << ";\n"; + } + } + + OS << " default: return vec4(0.0);\n"; + OS << " }\n"; + OS << "}\n"; } } void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { insert_glsl_legacy_function(OS); + insert_texture_fetch(OS, m_prog, m_parr); OS << "void main ()" << std::endl; OS << "{" << std::endl; @@ -174,11 +211,11 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) if (m_prog.unnormalized_coords & (1 << index)) { - OS << "vec2 tex" << index << "_coord_scale = 1. / textureSize(" << PI.name << ", 0);\n"; + OS << " vec2 tex" << index << "_coord_scale = 1. / textureSize(" << PI.name << ", 0);\n"; } else { - OS << "vec2 tex" << index << "_coord_scale = vec2(1.);\n"; + OS << " vec2 tex" << index << "_coord_scale = vec2(1.);\n"; } } } @@ -231,27 +268,37 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) if (!first_output_name.empty()) { - switch (m_prog.alpha_func) + auto make_comparison_test = [](rsx::comparison_function compare_func, const std::string &test, const std::string &a, const std::string &b) -> std::string { - case rsx::comparison_function::equal: - OS << " if (bool(alpha_test) && " << first_output_name << ".a != alpha_ref) discard;\n"; - break; - case rsx::comparison_function::not_equal: - OS << " if (bool(alpha_test) && " << first_output_name << ".a == alpha_ref) discard;\n"; - break; - case rsx::comparison_function::less_or_equal: - OS << " if (bool(alpha_test) && " << first_output_name << ".a > alpha_ref) discard;\n"; - break; - case rsx::comparison_function::less: - OS << " if (bool(alpha_test) && " << first_output_name << ".a >= alpha_ref) discard;\n"; - break; - case rsx::comparison_function::greater: - OS << " if (bool(alpha_test) && " << first_output_name << ".a <= alpha_ref) discard;\n"; - break; - case rsx::comparison_function::greater_or_equal: - OS << " if (bool(alpha_test) && " << first_output_name << ".a < alpha_ref) discard;\n"; - break; + if (compare_func == rsx::comparison_function::always) return{}; + + if (compare_func == rsx::comparison_function::never) return " discard;\n"; + + std::string compare; + switch (compare_func) + { + case rsx::comparison_function::equal: compare = " == "; break; + case rsx::comparison_function::not_equal: compare = " != "; break; + case rsx::comparison_function::less_or_equal: compare = " <= "; break; + case rsx::comparison_function::less: compare = " < "; break; + case rsx::comparison_function::greater: compare = " > "; break; + case rsx::comparison_function::greater_or_equal: compare = " >= "; break; + } + + return " if (" + test + "!(" + a + compare + b + ")) discard;\n"; + }; + + for (u8 index = 0; index < 16; ++index) + { + if (m_prog.textures_alpha_kill[index]) + { + std::string index_string = std::to_string(index); + std::string fetch_texture = "texture_fetch(" + index_string + ", tc" + index_string + " * ftex" + index_string + "_cm).a"; + OS << make_comparison_test((rsx::comparison_function)m_prog.textures_zfunc[index], "", "0", fetch_texture); + } } + + OS << make_comparison_test(m_prog.alpha_func, "alpha_test != 0 && ", first_output_name + ".a", "alpha_ref"); } OS << "}" << std::endl; diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index f8d576ed86..9b1d763c18 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -233,6 +233,9 @@ struct RSXFragmentProgram rsx::fog_mode fog_equation; u16 height; + u8 textures_alpha_kill[16]; + u32 textures_zfunc[16]; + rsx::texture_dimension_extended get_texture_dimension(u8 id) const { return (rsx::texture_dimension_extended)((texture_dimensions >> (id * 2)) & 0x3); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index c3e1cc62d3..cb35c5f7a8 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -808,9 +808,19 @@ namespace rsx for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i) { if (!rsx::method_registers.fragment_textures[i].enabled()) + { texture_dimensions[i] = texture_dimension_extended::texture_dimension_2d; + result.textures_alpha_kill[i] = 0; + result.textures_zfunc[i] = 0; + } + else + { texture_dimensions[i] = rsx::method_registers.fragment_textures[i].get_extended_texture_dimension(); + result.textures_alpha_kill[i] = rsx::method_registers.fragment_textures[i].alpha_kill_enabled() ? 1 : 0; + result.textures_zfunc[i] = rsx::method_registers.fragment_textures[i].zfunc(); + } + if (rsx::method_registers.fragment_textures[i].enabled() && (rsx::method_registers.fragment_textures[i].format() & CELL_GCM_TEXTURE_UN)) result.unnormalized_coords |= (1 << i); }