rsx: Make fragment state dynamic to reduce shader permutations

This commit is contained in:
kd-11 2017-08-21 20:56:31 +03:00
parent 8358bda133
commit f71f67c4ff
12 changed files with 161 additions and 145 deletions

View file

@ -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<std::string> 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";