From f71f67c4ff0311a373e99572eb9b6fa78208b9ba Mon Sep 17 00:00:00 2001 From: kd-11 Date: Mon, 21 Aug 2017 20:56:31 +0300 Subject: [PATCH] rsx: Make fragment state dynamic to reduce shader permutations --- rpcs3/Emu/RSX/Common/GLSLCommon.h | 81 +++++++++++++++++++ rpcs3/Emu/RSX/Common/ProgramStateCache.cpp | 3 +- rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp | 2 + rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h | 1 + .../D3D12/D3D12FragmentProgramDecompiler.cpp | 63 ++++++--------- rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp | 63 +++++---------- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 2 +- rpcs3/Emu/RSX/RSXFragmentProgram.h | 5 -- rpcs3/Emu/RSX/RSXThread.cpp | 18 ++--- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 59 +++++--------- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 2 +- rpcs3/Emu/RSX/rsx_cache.h | 7 -- 12 files changed, 161 insertions(+), 145 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/GLSLCommon.h b/rpcs3/Emu/RSX/Common/GLSLCommon.h index add643e2c0..5de0effc94 100644 --- a/rpcs3/Emu/RSX/Common/GLSLCommon.h +++ b/rpcs3/Emu/RSX/Common/GLSLCommon.h @@ -3,6 +3,80 @@ #include "ShaderParam.h" +namespace program_common +{ + static void insert_compare_op(std::ostream& OS) + { + OS << "bool comparison_passes(float a, float b, uint func)\n"; + OS << "{\n"; + OS << " switch (func)\n"; + OS << " {\n"; + OS << " default:\n"; + OS << " case 0: return false; //never\n"; + OS << " case 1: return (a < b); //less\n"; + OS << " case 2: return (a == b); //equal\n"; + OS << " case 3: return (a <= b); //lequal\n"; + OS << " case 4: return (a > b); //greater\n"; + OS << " case 5: return (a != b); //nequal\n"; + OS << " case 6: return (a >= b); //gequal\n"; + OS << " case 7: return true; //always\n"; + OS << " }\n"; + OS << "}\n\n"; + } + + static void insert_fog_declaration(std::ostream& OS, const std::string wide_vector_type, const std::string input_coord, bool declare = false) + { + std::string template_body; + + if (!declare) + template_body += "$T fetch_fog_value(uint mode)\n"; + else + template_body += "$T fetch_fog_value(uint mode, $T $I)\n"; + + template_body += "{\n"; + template_body += " $T result = $T(0., 0., 0., 0.);\n"; + template_body += " switch(mode)\n"; + template_body += " {\n"; + template_body += " default:\n"; + template_body += " return result;\n"; + template_body += " case 0:\n"; + template_body += " //linear\n"; + template_body += " result = $T(fog_param1 * $I.x + (fog_param0 - 1.), fog_param1 * $I.x + (fog_param0 - 1.), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " case 1:\n"; + template_body += " //exponential\n"; + template_body += " result = $T(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5)), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " case 2:\n"; + template_body += " //exponential2\n"; + template_body += " result = $T(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), 2.)), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " case 3:\n"; + template_body += " //exponential_abs\n"; + template_body += " result = $T(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5)), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " case 4:\n"; + template_body += " //exponential2_abs\n"; + template_body += " result = $T(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " case 5:\n"; + template_body += " //linear_abs\n"; + template_body += " result = $T(fog_param1 * abs($I.x) + (fog_param0 - 1.), fog_param1 * abs($I.x) + (fog_param0 - 1.), 0., 0.);\n"; + template_body += " break;\n"; + template_body += " }\n"; + template_body += "\n"; + template_body += " result.y = clamp(result.y, 0., 1.);\n"; + template_body += " return result;\n"; + template_body += "}\n\n"; + + std::pair replacements[] = + {std::make_pair("$T", wide_vector_type), + std::make_pair("$I", input_coord)}; + + OS << fmt::replace_all(template_body, replacements); + } +} + namespace glsl { enum program_domain @@ -242,6 +316,8 @@ namespace glsl if (domain == glsl::program_domain::glsl_vertex_program) return; + program_common::insert_compare_op(OS); + //NOTE: After testing with GOW, the w component is either the original depth or wraps around to the x component //Since component.r == depth_value with some precision loss, just use the precise depth value for now (further testing needed) OS << "vec4 decodeLinearDepth(float depth_value)\n"; @@ -263,4 +339,9 @@ namespace glsl OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n"; OS << "}\n\n"; } + + static void insert_fog_declaration(std::ostream& OS) + { + program_common::insert_fog_declaration(OS, "vec4", "fog_c"); + } } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp index e680652c4e..2e84fa2ce4 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.cpp @@ -107,9 +107,8 @@ size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) cons bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const { if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords || - binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode || binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output || - binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func || binary1.fog_equation != binary2.fog_equation || + binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.shadow_textures != binary2.shadow_textures || binary1.redirected_textures != binary2.redirected_textures) return false; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp index b7caa76b64..552f840690 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -124,6 +124,8 @@ void insert_d3d12_legacy_function(std::ostream& OS, bool is_fragment_program) if (!is_fragment_program) return; + program_common::insert_compare_op(OS); + OS << "uint packSnorm2x16(float2 val)"; OS << "{\n"; OS << " uint high_bits = round(clamp(val.x, -1., 1.) * 32767.);\n"; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h index 251f1d4742..9ea7141a5a 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h @@ -1,6 +1,7 @@ #pragma once #include "../Common/ShaderParam.h" +#include "../Common/GLSLCommon.h" std::string getFloatTypeNameImp(size_t elementCount); std::string getFunctionImp(FUNCTION f); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index c0f5debe70..40c5ebad58 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -42,8 +42,12 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS) OS << " float4 userClipFactor[2];\n"; OS << " float fog_param0;\n"; OS << " float fog_param1;\n"; - OS << " int isAlphaTested;\n"; - OS << " float alphaRef;\n"; + OS << " uint alpha_test;\n"; + OS << " float alpha_ref;\n"; + OS << " uint alpha_func;\n"; + OS << " uint fog_mode;\n"; + OS << " uint window_origin;\n"; + OS << " uint window_height;\n"; OS << " float4 texture_parameters[16];\n"; OS << "};\n"; } @@ -151,38 +155,6 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) namespace { - // Note: It's not clear whether fog is computed per pixel or per vertex. - // 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) - { - switch (mode) - { - case rsx::fog_mode::linear: - OS << " float4 fogc = float4(fog_param1 * In.fogc.x + (fog_param0 - 1.), fog_param1 * In.fogc.x + (fog_param0 - 1.), 0., 0.);\n"; - break; - case rsx::fog_mode::exponential: - OS << " float4 fogc = float4(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5)), 0., 0.);\n"; - break; - case rsx::fog_mode::exponential2: - OS << " float4 fogc = float4(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), 2.)), 0., 0.);\n"; - break; - case rsx::fog_mode::linear_abs: - OS << " float4 fogc = float4(fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), 0., 0.);\n"; - break; - case rsx::fog_mode::exponential_abs: - OS << " float4 fogc = float4(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5)), 0., 0.);\n"; - break; - case rsx::fog_mode::exponential2_abs: - OS << " float4 fogc = float4(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n"; - break; - default: - OS << " float4 fogc = float4(0., 0., 0., 0.);\n"; - return; - } - - OS << " fogc.y = saturate(fogc.y);\n"; - } - std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index) { std::string tex_name = "tex" + std::to_string(index) + ".Sample"; @@ -205,6 +177,18 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) { insert_d3d12_legacy_function(OS, true); + for (const ParamType &PT : m_parr.params[PF_PARAM_IN]) + { + for (const ParamItem &PI : PT.items) + { + if (PI.name == "fogc") + { + program_common::insert_fog_declaration(OS, "float4", "fogc", true); + break; + } + } + } + const std::set output_value = { "r0", "r1", "r2", "r3", "r4", @@ -231,7 +215,7 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) } if (PI.name == "fogc") { - insert_fog_declaration(OS, m_prog.fog_equation); + OS << " float4 fogc = fetch_fog_value(fog_mode, In.fogc);\n"; continue; } if (PI.name == "ssa") @@ -239,10 +223,9 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";\n"; } } - // A bit unclean, but works. - OS << " " << "float4 wpos = In.Position;\n"; - if (m_prog.origin_mode == rsx::window_origin::bottom) - OS << " wpos.y = (" << std::to_string(m_prog.height) << " - wpos.y);\n"; + + OS << " float4 wpos = In.Position;\n"; + OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n"; OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n"; // Declare output @@ -363,7 +346,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS) } } - OS << make_comparison_test(m_prog.alpha_func, "isAlphaTested && ", "Out." + first_output_name + ".a", "alphaRef"); + OS << " if (alpha_test != 0 && !comparison_passes(Out." << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n"; } OS << " return Out;\n"; diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 547873da96..ed79fb7370 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -3,7 +3,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "GLFragmentProgram.h" - +#include "../Common/ProgramStateCache.h" #include "GLCommonDecompiler.h" #include "../GCM.h" @@ -145,45 +145,16 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << " float fog_param1;\n"; OS << " uint alpha_test;\n"; OS << " float alpha_ref;\n"; + OS << " uint alpha_func;\n"; + OS << " uint fog_mode;\n"; + OS << " uint window_origin;\n"; + OS << " uint window_height;\n"; OS << " vec4 texture_parameters[16];\n"; //sampling: x,y scaling and (unused) offsets data OS << "};\n"; } - namespace { - // Note: It's not clear whether fog is computed per pixel or per vertex. - // 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) - { - 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"; - 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"; - 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"; - 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"; - 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"; - 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"; - break; - default: - OS << " vec4 fogc = vec4(0.);\n"; - return; - } - - OS << " fogc.y = clamp(fogc.y, 0., 1.);\n"; - } - void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index) { std::string vec_type = "vec2"; @@ -223,6 +194,19 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program); + //TODO: Generate input mask during parse stage to avoid this + for (const ParamType& PT : m_parr.params[PF_PARAM_IN]) + { + for (const ParamItem& PI : PT.items) + { + if (PI.name == "fogc") + { + glsl::insert_fog_declaration(OS); + break; + } + } + } + const std::set output_values = { "r0", "r1", "r2", "r3", "r4", @@ -241,6 +225,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) } } + OS << "//FP_HASH=" << fmt::format("%llX", program_hash_util::fragment_program_hash()(m_prog)) << "\n"; OS << "void fs_main(" << parameters << ")\n"; OS << "{\n"; @@ -261,11 +246,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; OS << " vec4 wpos = gl_FragCoord;\n"; - - //Flip wpos in Y - //We could optionally export wpos from the VS, but this is so much easier - if (m_prog.origin_mode == rsx::window_origin::bottom) - OS << " wpos.y = " << std::to_string(m_prog.height) << " - wpos.y;\n"; + OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n"; for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) { @@ -326,7 +307,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) if (PI.name == "fogc") { - insert_fog_declaration(OS, m_prog.fog_equation); + OS << " vec4 fogc = fetch_fog_value(fog_mode);\n"; continue; } } @@ -394,7 +375,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) } } - OS << make_comparison_test(m_prog.alpha_func, "alpha_test != 0 && ", first_output_name + ".a", "alpha_ref"); + OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n"; } OS << "}\n\n"; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 906b06c05a..bc3bc5284b 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -937,7 +937,7 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count) u32 fragment_constants_offset; const u32 fragment_constants_size = (const u32)m_prog_buffer.get_fragment_constants_buffer_size(fragment_program); - const u32 fragment_buffer_size = fragment_constants_size + (17 * 4 * sizeof(float)); + const u32 fragment_buffer_size = fragment_constants_size + (18 * 4 * sizeof(float)); if (manually_flush_ring_buffers) { diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 3281ab1b06..8c0623dc4c 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -223,17 +223,12 @@ struct RSXFragmentProgram u16 unnormalized_coords; u16 redirected_textures; u16 shadow_textures; - rsx::comparison_function alpha_func; bool front_back_color_enabled : 1; bool back_color_diffuse_output : 1; bool back_color_specular_output : 1; bool front_color_diffuse_output : 1; bool front_color_specular_output : 1; u32 texture_dimensions; - rsx::window_origin origin_mode; - rsx::window_pixel_center pixel_center_mode; - rsx::fog_mode fog_equation; - u16 height; float texture_pitch_scale[16]; u8 textures_alpha_kill[16]; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 906f0bfb78..853bab81d7 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -598,17 +598,22 @@ namespace rsx void thread::fill_fragment_state_buffer(void *buffer, const RSXFragmentProgram &fragment_program) { - u32 *dst = static_cast(buffer); - const u32 is_alpha_tested = rsx::method_registers.alpha_test_enabled(); const float alpha_ref = rsx::method_registers.alpha_ref() / 255.f; const f32 fog0 = rsx::method_registers.fog_params_0(); const f32 fog1 = rsx::method_registers.fog_params_1(); + const u32 alpha_func = static_cast(rsx::method_registers.alpha_func()); + const u32 fog_mode = static_cast(rsx::method_registers.fog_equation()); + const u32 window_origin = static_cast(rsx::method_registers.shader_window_origin()); + const u32 window_height = rsx::method_registers.shader_window_height(); const float one = 1.f; - stream_vector(dst, (u32&)fog0, (u32&)fog1, is_alpha_tested, (u32&)alpha_ref); + u32 *dst = static_cast(buffer); - size_t offset = 4; + stream_vector(dst, (u32&)fog0, (u32&)fog1, is_alpha_tested, (u32&)alpha_ref); + stream_vector(dst + 4, alpha_func, fog_mode, window_origin, window_height); + + size_t offset = 8; for (int index = 0; index < 16; ++index) { stream_vector(&dst[offset], (u32&)fragment_program.texture_pitch_scale[index], (u32&)one, 0U, 0U); @@ -1097,11 +1102,6 @@ namespace rsx result.back_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR); result.front_color_diffuse_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE); result.front_color_specular_output = !!(rsx::method_registers.vertex_attrib_output_mask() & CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR); - result.alpha_func = rsx::method_registers.alpha_func(); - result.fog_equation = rsx::method_registers.fog_equation(); - result.origin_mode = rsx::method_registers.shader_window_origin(); - result.pixel_center_mode = rsx::method_registers.shader_window_pixel(); - result.height = rsx::method_registers.shader_window_height(); result.redirected_textures = 0; result.shadow_textures = 0; diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 74055eba5c..0559d13039 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -164,6 +164,10 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) OS << " float fog_param1;\n"; OS << " uint alpha_test;\n"; OS << " float alpha_ref;\n"; + OS << " uint alpha_func;\n"; + OS << " uint fog_mode;\n"; + OS << " uint window_origin;\n"; + OS << " uint window_height;\n"; OS << " vec4 texture_parameters[16];\n"; OS << "};\n"; @@ -178,38 +182,6 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) namespace vk { - // Note: It's not clear whether fog is computed per pixel or per vertex. - // 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) - { - 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"; - 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"; - 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"; - 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"; - 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"; - 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"; - break; - default: - OS << " vec4 fogc = vec4(0.);\n"; - return; - } - - OS << " fogc.y = clamp(fogc.y, 0., 1.);\n"; - } - std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index) { std::string tex_name = "tex" + std::to_string(index); @@ -231,6 +203,19 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) { glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program); + //TODO: Generate input mask during parse stage to avoid this + for (const ParamType& PT : m_parr.params[PF_PARAM_IN]) + { + for (const ParamItem& PI : PT.items) + { + if (PI.name == "fogc") + { + glsl::insert_fog_declaration(OS); + break; + } + } + } + const std::set output_values = { "r0", "r1", "r2", "r3", "r4", @@ -269,11 +254,7 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; OS << " vec4 wpos = gl_FragCoord;\n"; - - //Flip wpos in Y - //We could optionally export wpos from the VS, but this is so much easier - if (m_prog.origin_mode == rsx::window_origin::bottom) - OS << " wpos.y = " << std::to_string(m_prog.height) << " - wpos.y;\n"; + OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n"; bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output); @@ -323,7 +304,7 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) if (PI.name == "fogc") { - vk::insert_fog_declaration(OS, m_prog.fog_equation); + OS << " vec4 fogc = fetch_fog_value(fog_mode);\n"; continue; } } @@ -391,7 +372,7 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS) } } - OS << make_comparison_test(m_prog.alpha_func, "bool(alpha_test) && ", first_output_name + ".a", "alpha_ref"); + OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n"; } OS << "}\n\n"; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index e624863156..a2b8d41d0d 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1842,7 +1842,7 @@ void VKGSRender::load_program(u32 vertex_count, u32 vertex_base) auto &fragment_program = current_fragment_program; const size_t fragment_constants_sz = m_prog_buffer->get_fragment_constants_buffer_size(fragment_program); - const size_t fragment_buffer_sz = fragment_constants_sz + (17 * 4 * sizeof(float)); + const size_t fragment_buffer_sz = fragment_constants_sz + (18 * 4 * sizeof(float)); const size_t required_mem = 512 + 8192 + fragment_buffer_sz; const size_t vertex_state_offset = m_uniform_buffer_ring_info.alloc<256>(required_mem); diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index 04ea3ee536..71660ae36d 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -409,11 +409,6 @@ namespace rsx fp.ctrl = data.fp_ctrl; fp.texture_dimensions = data.fp_texture_dimensions; fp.unnormalized_coords = data.fp_unnormalized_coords; - fp.height = data.fp_height; - fp.pixel_center_mode = (rsx::window_pixel_center)(data.fp_pixel_layout & 0x3); - fp.origin_mode = (rsx::window_origin)((data.fp_pixel_layout >> 2) & 0x1); - fp.alpha_func = (rsx::comparison_function)((data.fp_pixel_layout >> 3) & 0xF); - fp.fog_equation = (rsx::fog_mode)((data.fp_pixel_layout >> 7) & 0xF); fp.front_back_color_enabled = (data.fp_lighting_flags & 0x1) != 0; fp.back_color_diffuse_output = ((data.fp_lighting_flags >> 1) & 0x1) != 0; fp.back_color_specular_output = ((data.fp_lighting_flags >> 2) & 0x1) != 0; @@ -444,8 +439,6 @@ namespace rsx data_block.fp_ctrl = fp.ctrl; data_block.fp_texture_dimensions = fp.texture_dimensions; data_block.fp_unnormalized_coords = fp.unnormalized_coords; - data_block.fp_height = fp.height; - data_block.fp_pixel_layout = (u16)fp.pixel_center_mode | (u16)fp.origin_mode << 2 | (u16)fp.alpha_func << 3; data_block.fp_lighting_flags = (u16)fp.front_back_color_enabled | (u16)fp.back_color_diffuse_output << 1 | (u16)fp.back_color_specular_output << 2 | (u16)fp.front_color_diffuse_output << 3 | (u16)fp.front_color_specular_output << 4; data_block.fp_shadow_textures = fp.shadow_textures;