rsx/fp: Fix some decompiler bugs

This commit is contained in:
kd-11 2017-03-07 13:40:38 +03:00
parent 1c8cb3b7d3
commit be4bb48476
13 changed files with 174 additions and 126 deletions

View File

@ -41,6 +41,10 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask)
{ {
code = saturate(code); code = saturate(code);
} }
else if (!dst.no_dest)
{
code = NoOverflow(code);
}
code += (append_mask ? "$m" : ""); code += (append_mask ? "$m" : "");
@ -60,6 +64,13 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask)
std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m"; std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m";
if (dst.exp_tex)
{
//TODO
//If exp_tex really sets _bx2 flag, we may need to perform extra modifications to the src
AddCode("//TODO: exp tex flag is set");
}
AddCodeCond(Format(dest), code); AddCodeCond(Format(dest), code);
//AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); //AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";"));
@ -148,6 +159,45 @@ std::string FragmentProgramDecompiler::AddTex()
return m_parr.AddParam(PF_PARAM_UNIFORM, sampler, std::string("tex") + std::to_string(dst.tex_num)); return m_parr.AddParam(PF_PARAM_UNIFORM, sampler, std::string("tex") + std::to_string(dst.tex_num));
} }
//Both of these were tested with a trace SoulCalibur IV title screen
//Failure to catch causes infinite values since theres alot of rcp(0)
std::string FragmentProgramDecompiler::NotZero(const std::string& code)
{
return "(max(abs(" + code + "), 1.E-10) * sign(" + code + "))";
}
std::string FragmentProgramDecompiler::NotZeroPositive(const std::string& code)
{
return "max(" + code + ", 1.E-10)";
}
std::string FragmentProgramDecompiler::NoOverflow(const std::string& code)
{
//FP16 is expected to overflow alot easier at 0+-65504
//FP32 can still work upto 0+-3.4E38
//See http://http.download.nvidia.com/developer/Papers/2005/FP_Specials/FP_Specials.pdf
if (dst.exp_tex)
{
//If dst.exp_tex really is _bx2 postfix, we need to unpack dynamic range
return "((" + code + "- 0.5) * 2.)";
}
switch (dst.prec)
{
case 0:
break;
case 1:
//Disabled: Causes blue output in some games such as persona V and soul calibur IV
//return "clamp(" + code + ", -65504., 65504.)";
break;
case 2:
return "clamp(" + code + ", -1., 1.)";
}
return code;
}
std::string FragmentProgramDecompiler::Format(const std::string& code) std::string FragmentProgramDecompiler::Format(const std::string& code)
{ {
const std::pair<std::string, std::function<std::string()>> repl_list[] = const std::pair<std::string, std::function<std::string()>> repl_list[] =
@ -358,10 +408,10 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode)
switch (opcode) switch (opcode)
{ {
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / " + NotZero("$1.x") + ")"); return true;
// Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). // Note: DIVSQ is not IEEE compliant. divsq(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, $1)"); return true; case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt(" + NotZeroPositive("$1.x") + "))"); return true;
case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true;
case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true;
case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true;
@ -372,10 +422,10 @@ bool FragmentProgramDecompiler::handle_sct(u32 opcode)
case RSX_FP_OPCODE_MOV: SetDst("$0"); return true; case RSX_FP_OPCODE_MOV: SetDst("$0"); return true;
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true; case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true;
// Note: It's higly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found // Note: It's higly likely that RCP is not IEEE compliant but a game that uses rcp(0) has to be found
case RSX_FP_OPCODE_RCP: SetDst("rcp_legacy($0)"); return true; case RSX_FP_OPCODE_RCP: SetDst("(1. / " + NotZero("$0") + ")"); return true;
// Note: RSQ is not IEEE compliant. rsq(0) is some big number (Silent Hill 3 HD) // Note: RSQ is not IEEE compliant. rsq(0) is some big number (Silent Hill 3 HD)
// It is not know what happens if 0 is negative. // It is not know what happens if 0 is negative.
case RSX_FP_OPCODE_RSQ: SetDst("rsq_legacy($0)"); return true; case RSX_FP_OPCODE_RSQ: SetDst("(" + getFloatTypeName(4) + "(1.) / sqrt(" + NotZeroPositive("$0.x") + "))"); return true;
case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true; case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true;
case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true; case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true;
case RSX_FP_OPCODE_SGE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); return true; case RSX_FP_OPCODE_SGE: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); return true;
@ -394,10 +444,10 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
{ {
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true; case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); return true;
case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true; case RSX_FP_OPCODE_COS: SetDst("cos($0.xxxx)"); return true;
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1.xxxx)"); return true; case RSX_FP_OPCODE_DIV: SetDst("($0 / " + NotZero("$1.x") + ")"); return true;
// Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix). // Note: DIVSQ is not IEEE compliant. sqrt(0, 0) is 0 (Super Puzzle Fighter II Turbo HD Remix).
// sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven. // sqrt(x, 0) might be equal to some big value (in absolute) whose sign is sign(x) but it has to be proven.
case RSX_FP_OPCODE_DIVSQ: SetDst("divsq_legacy($0, sqrt($1).xxxx)"); return true; case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt(" + NotZeroPositive("$1.x") + "))"); return true;
case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true; case RSX_FP_OPCODE_DP2: SetDst(getFunction(FUNCTION::FUNCTION_DP2)); return true;
case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true; case RSX_FP_OPCODE_DP3: SetDst(getFunction(FUNCTION::FUNCTION_DP3)); return true;
case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true; case RSX_FP_OPCODE_DP4: SetDst(getFunction(FUNCTION::FUNCTION_DP4)); return true;
@ -416,10 +466,10 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true; case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); return true;
case RSX_FP_OPCODE_MOV: SetDst("$0"); return true; case RSX_FP_OPCODE_MOV: SetDst("$0"); return true;
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true; case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); return true;
case RSX_FP_OPCODE_PK2: SetDst("float(packSnorm2x16($0.xy))"); return true; case RSX_FP_OPCODE_PK2: SetDst(getFloatTypeName(4) + "(packSnorm2x16($0.xy))"); return true;
case RSX_FP_OPCODE_PK4: SetDst("float(packSnorm4x8($0))"); return true; case RSX_FP_OPCODE_PK4: SetDst(getFloatTypeName(4) + "(packSnorm4x8($0))"); return true;
case RSX_FP_OPCODE_PK16: SetDst("float(packHalf2x16($0.xy))"); return true; case RSX_FP_OPCODE_PK16: SetDst(getFloatTypeName(4) + "(packHalf2x16($0.xy))"); return true;
case RSX_FP_OPCODE_PKB: SetDst("packUnorm4x8($0 / 255.)"); return true; case RSX_FP_OPCODE_PKB: SetDst(getFloatTypeName(4) + "(packUnorm4x8($0 / 255.))"); return true;
case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); return true; case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); return true;
case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true; case RSX_FP_OPCODE_SEQ: SetDst(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); return true;
case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true; case RSX_FP_OPCODE_SFL: SetDst(getFunction(FUNCTION::FUNCTION_SFL)); return true;
@ -440,8 +490,11 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
{ {
case RSX_FP_OPCODE_DDX: SetDst(getFunction(FUNCTION::FUNCTION_DFDX)); return true; case RSX_FP_OPCODE_DDX: SetDst(getFunction(FUNCTION::FUNCTION_DFDX)); return true;
case RSX_FP_OPCODE_DDY: SetDst(getFunction(FUNCTION::FUNCTION_DFDY)); return true; case RSX_FP_OPCODE_DDY: SetDst(getFunction(FUNCTION::FUNCTION_DFDY)); return true;
case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); return true; case RSX_FP_OPCODE_NRM: SetDst("normalize($0.xyz)"); return true;
case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); return true; case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); return true;
case RSX_FP_OPCODE_TEXBEM:
//treat as TEX for now
LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TEXBEM");
case RSX_FP_OPCODE_TEX: case RSX_FP_OPCODE_TEX:
switch (m_prog.get_texture_dimension(dst.tex_num)) switch (m_prog.get_texture_dimension(dst.tex_num))
{ {
@ -462,7 +515,9 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
return true; return true;
} }
return false; return false;
case RSX_FP_OPCODE_TEXBEM: SetDst("texture($t, $0.xy, $1.x)"); return true; case RSX_FP_OPCODE_TXPBEM:
//Treat as TXP for now
LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXPBEM");
case RSX_FP_OPCODE_TXP: case RSX_FP_OPCODE_TXP:
switch (m_prog.get_texture_dimension(dst.tex_num)) switch (m_prog.get_texture_dimension(dst.tex_num))
{ {
@ -480,7 +535,6 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
return true; return true;
} }
return false; return false;
case RSX_FP_OPCODE_TXPBEM: SetDst("textureProj($t, $0.xyz, $1.x)"); return true;
case RSX_FP_OPCODE_TXD: case RSX_FP_OPCODE_TXD:
switch (m_prog.get_texture_dimension(dst.tex_num)) switch (m_prog.get_texture_dimension(dst.tex_num))
{ {
@ -498,7 +552,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
return true; return true;
} }
return false; return false;
case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); return true; case RSX_FP_OPCODE_TXB:
case RSX_FP_OPCODE_TXL: case RSX_FP_OPCODE_TXL:
switch (m_prog.get_texture_dimension(dst.tex_num)) switch (m_prog.get_texture_dimension(dst.tex_num))
{ {

View File

@ -46,6 +46,14 @@ class FragmentProgramDecompiler
std::string AddTex(); std::string AddTex();
std::string Format(const std::string& code); std::string Format(const std::string& code);
//Prevent division by zero by catching denormals
//Simpler variant where input and output are expected to be positive
std::string NotZero(const std::string& code);
std::string NotZeroPositive(const std::string& code);
//Prevents operations from overflowing the max range (tested with fp_dynamic3 autotest sample)
std::string NoOverflow(const std::string& code);
void AddCodeCond(const std::string& dst, const std::string& src); void AddCodeCond(const std::string& dst, const std::string& src);
std::string GetCond(); std::string GetCond();
template<typename T> std::string GetSRC(T src); template<typename T> std::string GetSRC(T src);

View File

@ -368,6 +368,11 @@ void VertexProgramDecompiler::SetDSTSca(const std::string& code)
SetDST(true, code); SetDST(true, code);
} }
std::string VertexProgramDecompiler::NotZeroPositive(const std::string code)
{
return "max(" + code + ", 1.E-10)";
}
std::string VertexProgramDecompiler::BuildFuncBody(const FuncInfo& func) std::string VertexProgramDecompiler::BuildFuncBody(const FuncInfo& func)
{ {
std::string result; std::string result;
@ -623,7 +628,7 @@ std::string VertexProgramDecompiler::Decompile()
case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break; case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break;
case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break; case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break;
case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break;
case RSX_SCA_OPCODE_RSQ: SetDSTSca("rsq_legacy($s)"); break; case RSX_SCA_OPCODE_RSQ: SetDSTSca("1. / " + NotZeroPositive("$s")); break;
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break; case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break; case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
case RSX_SCA_OPCODE_LIT: SetDSTSca("lit_legacy($s)"); break; case RSX_SCA_OPCODE_LIT: SetDSTSca("lit_legacy($s)"); break;
@ -663,7 +668,7 @@ std::string VertexProgramDecompiler::Decompile()
// works like BRI but shorter (RET o[1].x(TR);) // works like BRI but shorter (RET o[1].x(TR);)
AddCode("$ifcond return;"); AddCode("$ifcond return;");
break; break;
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2_legacy($s)"); break; case RSX_SCA_OPCODE_LG2: SetDSTSca("log2(" + NotZeroPositive("$s") + ")"); break;
case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break; case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break;
case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break; case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break;
case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break; case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break;

View File

@ -61,6 +61,7 @@ struct VertexProgramDecompiler
const std::vector<u32>& m_data; const std::vector<u32>& m_data;
ParamArray m_parr; ParamArray m_parr;
std::string NotZeroPositive(const std::string code);
std::string GetMask(bool is_sca); std::string GetMask(bool is_sca);
std::string GetVecMask(); std::string GetVecMask();
std::string GetScaMask(); std::string GetScaMask();

View File

@ -108,26 +108,6 @@ std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::str
void insert_d3d12_legacy_function(std::ostream& OS) void insert_d3d12_legacy_function(std::ostream& OS)
{ {
OS << "float4 divsq_legacy(float4 num, float4 denum)\n";
OS << "{\n";
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
OS << "}\n";
OS << "float4 rcp_legacy(float4 denum)\n";
OS << "{\n";
OS << " return 1. / denum;\n";
OS << "}\n";
OS << "float4 rsq_legacy(float4 val)\n";
OS << "{\n";
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
OS << "}\n\n";
OS << "float4 log2_legacy(float4 val)\n";
OS << "{\n";
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
OS << "}\n\n";
OS << "float4 lit_legacy(float4 val)"; OS << "float4 lit_legacy(float4 val)";
OS << "{\n"; OS << "{\n";
OS << " float4 clamped_val = val;\n"; OS << " float4 clamped_val = val;\n";

View File

@ -155,23 +155,28 @@ namespace
{ {
case rsx::fog_mode::linear: case rsx::fog_mode::linear:
OS << " float4 fogc = float4(fog_param1 * In.fogc + (fog_param0 - 1.), fog_param1 * In.fogc + (fog_param0 - 1.), 0., 0.);\n"; OS << " float4 fogc = float4(fog_param1 * In.fogc + (fog_param0 - 1.), fog_param1 * In.fogc + (fog_param0 - 1.), 0., 0.);\n";
return; break;
case rsx::fog_mode::exponential: case rsx::fog_mode::exponential:
OS << " float4 fogc = float4(11.084 * (fog_param1 * In.fogc + fog_param0 - 1.5), exp(11.084 * (fog_param1 * In.fogc + fog_param0 - 1.5)), 0., 0.);\n"; OS << " float4 fogc = float4(11.084 * (fog_param1 * In.fogc + fog_param0 - 1.5), exp(11.084 * (fog_param1 * In.fogc + fog_param0 - 1.5)), 0., 0.);\n";
return; break;
case rsx::fog_mode::exponential2: case rsx::fog_mode::exponential2:
OS << " float4 fogc = float4(4.709 * (fog_param1 * In.fogc + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * In.fogc + fog_param0 - 1.5)), 2.)), 0., 0.);\n"; OS << " float4 fogc = float4(4.709 * (fog_param1 * In.fogc + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * In.fogc + fog_param0 - 1.5)), 2.)), 0., 0.);\n";
return; break;
case rsx::fog_mode::linear_abs: case rsx::fog_mode::linear_abs:
OS << " float4 fogc = float4(fog_param1 * abs(In.fogc) + (fog_param0 - 1.), fog_param1 * abs(In.fogc) + (fog_param0 - 1.), 0., 0.);\n"; OS << " float4 fogc = float4(fog_param1 * abs(In.fogc) + (fog_param0 - 1.), fog_param1 * abs(In.fogc) + (fog_param0 - 1.), 0., 0.);\n";
return; break;
case rsx::fog_mode::exponential_abs: case rsx::fog_mode::exponential_abs:
OS << " float4 fogc = float4(11.084 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5)), 0., 0.);\n"; OS << " float4 fogc = float4(11.084 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5)), 0., 0.);\n";
return; break;
case rsx::fog_mode::exponential2_abs: case rsx::fog_mode::exponential2_abs:
OS << " float4 fogc = float4(4.709 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5)), 2.)), 0., 0.);\n"; OS << " float4 fogc = float4(4.709 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(In.fogc) + fog_param0 - 1.5)), 2.)), 0., 0.);\n";
break;
default:
OS << " float4 fogc = float4(0., 0., 0., 0.);\n";
return; return;
} }
OS << " fogc.y = saturate(fogc.y);\n";
} }
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index) std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
@ -302,13 +307,21 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
} }
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
{ {
/** if (m_parr.HasParam(PF_PARAM_NONE, "vec4", "r1"))
* Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader {
* but it writes depth in r1.z and not h2.z. /**
* Maybe there's a different flag for depth ? * Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
*/ * but it writes depth in r1.z and not h2.z.
// OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h2.z;") << std::endl; * Maybe there's a different flag for depth ?
OS << " Out.depth = r1.z;\n"; */
// OS << " Out.depth = " << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "r1.z;" : "h2.z;") << std::endl;
OS << " Out.depth = r1.z;\n";
}
else
{
//Input not declared. Leave commented to assist in debugging the shader
OS << " //Out.depth = r1.z;\n";
}
} }
// Shaders don't always output colors (for instance if they write to depth only) // Shaders don't always output colors (for instance if they write to depth only)
if (!first_output_name.empty()) if (!first_output_name.empty())

View File

@ -47,17 +47,17 @@ std::string getFunctionImpl(FUNCTION f)
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "textureLod($t, $0.x, $1)"; return "textureLod($t, $0.x, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
return "textureGrad($t, $0.x, $1.x, $2.y)"; return "textureGrad($t, $0.x, $1.x, $2.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
return "texture($t, $0.xy * $t_coord_scale)"; return "texture($t, $0.xy * $t_coord_scale)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "textureProj($t, $0.xyz * vec3($t_coord_scale, 1.) , $1.x)"; // Note: $1.x is bias return "textureProj($t, $0 , $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "textureLod($t, $0.xy * $t_coord_scale, $1.x)"; return "textureLod($t, $0.xy * $t_coord_scale, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
return "textureGrad($t, $0.xyz * vec3($t_coord_scale, 1.) , $1.x, $2.y)"; return "textureGrad($t, $0.xy * $t_coord_scale , $1.xy, $2.xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
return "texture($t, $0.xyz)"; return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
@ -65,7 +65,7 @@ std::string getFunctionImpl(FUNCTION f)
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "textureLod($t, $0.xyz, $1.x)"; return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
return "textureGrad($t, $0.xyzw, $1.x, $2.y)"; return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D: case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
return "texture($t, $0.xyz)"; return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
@ -73,7 +73,7 @@ std::string getFunctionImpl(FUNCTION f)
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
return "textureLod($t, $0.xyz, $1.x)"; return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD:
return "textureGrad($t, $0.xyzw, $1.x, $2.y)"; return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_DFDX: case FUNCTION::FUNCTION_DFDX:
return "dFdx($0)"; return "dFdx($0)";
case FUNCTION::FUNCTION_DFDY: case FUNCTION::FUNCTION_DFDY:
@ -107,26 +107,6 @@ std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::st
void insert_glsl_legacy_function(std::ostream& OS) void insert_glsl_legacy_function(std::ostream& OS)
{ {
OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n";
OS << "{\n";
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
OS << "}\n";
OS << "vec4 rcp_legacy(vec4 denum)\n";
OS << "{\n";
OS << " return 1. / denum;\n";
OS << "}\n";
OS << "vec4 rsq_legacy(vec4 val)\n";
OS << "{\n";
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
OS << "}\n\n";
OS << "vec4 log2_legacy(vec4 val)\n";
OS << "{\n";
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
OS << "}\n\n";
OS << "vec4 lit_legacy(vec4 val)"; OS << "vec4 lit_legacy(vec4 val)";
OS << "{\n"; OS << "{\n";
OS << " vec4 clamped_val = val;\n"; OS << " vec4 clamped_val = val;\n";

View File

@ -143,32 +143,32 @@ namespace
// But it makes more sense to compute exp of interpoled value than to interpolate exp values. // 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) void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode)
{ {
std::string fog_func = {};
switch (mode) switch (mode)
{ {
case rsx::fog_mode::linear: case rsx::fog_mode::linear:
fog_func = "fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.)"; OS << " vec4 fogc = vec4(fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.), 0., 0.);\n";
break; break;
case rsx::fog_mode::exponential: case rsx::fog_mode::exponential:
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))"; 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; break;
case rsx::fog_mode::exponential2: case rsx::fog_mode::exponential2:
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.)"; 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; break;
case rsx::fog_mode::linear_abs: case rsx::fog_mode::linear_abs:
fog_func = "fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), fog_param1 * abs(fog_c.x) + (fog_param0 - 1.)"; 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; break;
case rsx::fog_mode::exponential_abs: case rsx::fog_mode::exponential_abs:
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))"; 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; break;
case rsx::fog_mode::exponential2_abs: case rsx::fog_mode::exponential2_abs:
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.)"; 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; break;
default:
default: fog_func = "0.0, 0.0"; OS << " vec4 fogc = vec4(0.);\n";
return;
} }
OS << " vec4 fogc = clamp(vec4(" << fog_func << ", 0., 0.), 0., 1.);\n"; OS << " fogc.y = clamp(fogc.y, 0., 1.);\n";
} }
void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index) void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index)
@ -403,6 +403,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
{ {
if (m_parr.HasParam(PF_PARAM_NONE, "vec4", "r1"))
{ {
/** Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader /** Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
* but it writes depth in r1.z and not h2.z. * but it writes depth in r1.z and not h2.z.
@ -411,6 +412,11 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
//OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl; //OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl;
OS << " gl_FragDepth = r1.z;\n"; OS << " gl_FragDepth = r1.z;\n";
} }
else
{
//Input not declared. Leave commented to assist in debugging the shader
OS << " //gl_FragDepth = r1.z;\n";
}
} }
OS << "}" << std::endl; OS << "}" << std::endl;

View File

@ -54,15 +54,15 @@ namespace vk
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "textureLod($t, $0.x, $1.x)"; return "textureLod($t, $0.x, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
return "textureGrad($t, $0.x, $1.x, $2.y)"; return "textureGrad($t, $0.x, $1.x, $2.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
return "texture($t, $0.xy * texture_parameters[$_i].xy)"; return "texture($t, $0.xy * texture_parameters[$_i].xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "textureProj($t, $0.xyz, $1.x)"; // Note: $1.x is bias return "textureProj($t, $0, $1.x)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "textureLod($t, $0.xy * texture_parameters[$_i].xy, $1.x)"; return "textureLod($t, $0.xy * texture_parameters[$_i].xy, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
return "textureGrad($t, $0.xyz, $1.x, $2.y)"; // Note: $1.x is bias return "textureGrad($t, $0.xy, $1.xy, $2.xy)"; // Note: $1.x is bias
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
return "texture($t, $0.xyz)"; return "texture($t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
@ -70,7 +70,7 @@ namespace vk
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "textureLod($t, $0.xyz, $1.x)"; return "textureLod($t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD: case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
return "textureGrad($t, $0.xyzw, $1.x, $2.y)"; return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_DFDX: case FUNCTION::FUNCTION_DFDX:
return "dFdx($0)"; return "dFdx($0)";
case FUNCTION::FUNCTION_DFDY: case FUNCTION::FUNCTION_DFDY:
@ -104,26 +104,6 @@ namespace vk
void insert_glsl_legacy_function(std::ostream& OS) void insert_glsl_legacy_function(std::ostream& OS)
{ {
OS << "vec4 divsq_legacy(vec4 num, vec4 denum)\n";
OS << "{\n";
OS << " return num / sqrt(max(denum.xxxx, 1.E-10));\n";
OS << "}\n";
OS << "vec4 rcp_legacy(vec4 denum)\n";
OS << "{\n";
OS << " return 1. / denum;\n";
OS << "}\n";
OS << "vec4 rsq_legacy(vec4 val)\n";
OS << "{\n";
OS << " return float(1.0 / sqrt(max(val.x, 1.E-10))).xxxx;\n";
OS << "}\n\n";
OS << "vec4 log2_legacy(vec4 val)\n";
OS << "{\n";
OS << " return log2(max(val.x, 1.E-10)).xxxx;\n";
OS << "}\n\n";
OS << "vec4 lit_legacy(vec4 val)"; OS << "vec4 lit_legacy(vec4 val)";
OS << "{\n"; OS << "{\n";
OS << " vec4 clamped_val = val;\n"; OS << " vec4 clamped_val = val;\n";
@ -137,15 +117,24 @@ namespace vk
OS << " return result;\n"; OS << " return result;\n";
OS << "}\n\n"; OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n"; OS << "vec4 decodeLinearDepth(float depth_value)\n";
OS << "{\n"; OS << "{\n";
OS << " float depth_value = texture(tex, coord.xy).r;\n";
OS << " uint value = uint(depth_value * 16777215);\n"; OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint b = (value & 0xff);\n"; OS << " uint b = (value & 0xff);\n";
OS << " uint g = (value >> 8) & 0xff;\n"; OS << " uint g = (value >> 8) & 0xff;\n";
OS << " uint r = (value >> 16) & 0xff;\n"; OS << " uint r = (value >> 16) & 0xff;\n";
OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., 1.);\n"; OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., 1.);\n";
OS << "}\n\n"; OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n";
OS << "{\n";
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2DRect tex, vec2 coord)\n";
OS << "{\n";
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << "}\n\n";
} }
void init_default_resources(TBuiltInResource &rsc) void init_default_resources(TBuiltInResource &rsc)

View File

@ -179,23 +179,28 @@ namespace vk
{ {
case rsx::fog_mode::linear: 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"; OS << " vec4 fogc = vec4(fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.), 0., 0.);\n";
return; break;
case rsx::fog_mode::exponential: 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"; 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; break;
case rsx::fog_mode::exponential2: 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"; 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; break;
case rsx::fog_mode::linear_abs: 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"; 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; break;
case rsx::fog_mode::exponential_abs: 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"; 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; break;
case rsx::fog_mode::exponential2_abs: 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"; 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; return;
} }
OS << " fogc.y = clamp(fogc.y, 0., 1.);\n";
} }
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index) std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
@ -401,6 +406,7 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
{ {
if (m_parr.HasParam(PF_PARAM_NONE, "vec4", "r1"))
{ {
/** Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader /** Note: Naruto Shippuden : Ultimate Ninja Storm 2 sets CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS in a shader
* but it writes depth in r1.z and not h2.z. * but it writes depth in r1.z and not h2.z.
@ -409,6 +415,11 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
//OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl; //OS << ((m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h0.z;\n") << std::endl;
OS << " gl_FragDepth = r1.z;\n"; OS << " gl_FragDepth = r1.z;\n";
} }
else
{
//Input not declared. Leave commented to assist in debugging the shader
OS << " //gl_FragDepth = r1.z;\n";
}
} }
OS << "}" << std::endl; OS << "}" << std::endl;

View File

@ -112,16 +112,6 @@ rsx::comparison_function rsx::to_comparison_function(u16 in)
fmt::throw_exception("Unknown comparison function 0x%x" HERE, in); fmt::throw_exception("Unknown comparison function 0x%x" HERE, in);
} }
enum
{
CELL_GCM_FOG_MODE_LINEAR = 0x2601,
CELL_GCM_FOG_MODE_EXP = 0x0800,
CELL_GCM_FOG_MODE_EXP2 = 0x0801,
CELL_GCM_FOG_MODE_EXP_ABS = 0x0802,
CELL_GCM_FOG_MODE_EXP2_ABS = 0x0803,
CELL_GCM_FOG_MODE_LINEAR_ABS = 0x0804,
};
rsx::fog_mode rsx::to_fog_mode(u32 in) rsx::fog_mode rsx::to_fog_mode(u32 in)
{ {
switch (in) switch (in)

View File

@ -1040,3 +1040,14 @@ enum Method
RSX_METHOD_RETURN_CMD = 0x00020000, RSX_METHOD_RETURN_CMD = 0x00020000,
}; };
//Fog
enum
{
CELL_GCM_FOG_MODE_LINEAR = 0x2601,
CELL_GCM_FOG_MODE_EXP = 0x0800,
CELL_GCM_FOG_MODE_EXP2 = 0x0801,
CELL_GCM_FOG_MODE_EXP_ABS = 0x0802,
CELL_GCM_FOG_MODE_EXP2_ABS = 0x0803,
CELL_GCM_FOG_MODE_LINEAR_ABS = 0x0804,
};

View File

@ -836,7 +836,7 @@ namespace rsx
registers[NV4097_SET_LINE_WIDTH] = 1 << 3; registers[NV4097_SET_LINE_WIDTH] = 1 << 3;
// These defaults were found using After Burner Climax (which never set fog mode despite using fog input) // These defaults were found using After Burner Climax (which never set fog mode despite using fog input)
registers[NV4097_SET_FOG_MODE] = 0x2601; // rsx::fog_mode::linear; registers[NV4097_SET_FOG_MODE] = CELL_GCM_FOG_MODE_LINEAR;
(f32&)registers[NV4097_SET_FOG_PARAMS] = 1.; (f32&)registers[NV4097_SET_FOG_PARAMS] = 1.;
(f32&)registers[NV4097_SET_FOG_PARAMS + 1] = 1.; (f32&)registers[NV4097_SET_FOG_PARAMS + 1] = 1.;