mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-06 00:40:11 +00:00
rsx/fp: Color output registers are always present and zero initialized
- According to NV_fragment_program spec, registers are zero initialized always - A program even without writing to these registers will have black (0, 0, 0, 0) output Confirmed behaviour with MotorStorm games. Their engine uses this quirk to clear color buffers when doing depth replace Might be an unfixed game bug
This commit is contained in:
parent
4804efc17d
commit
d41b49d8b4
@ -496,79 +496,6 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
|
||||
std::string FragmentProgramDecompiler::BuildCode()
|
||||
{
|
||||
//Scan if any outputs are available
|
||||
const bool use_32_bit_exports = !!(m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS);
|
||||
const bool exports_depth = !!(m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT);
|
||||
const std::set<std::string> output_values =
|
||||
{
|
||||
(use_32_bit_exports) ? "r0" : "h0",
|
||||
"r1",
|
||||
(use_32_bit_exports) ? "r2" : "h4",
|
||||
(use_32_bit_exports) ? "r3" : "h6",
|
||||
(use_32_bit_exports) ? "r4" : "h8",
|
||||
};
|
||||
|
||||
bool gather_output_registers = true;
|
||||
const auto float4_name = getFloatTypeName(4);
|
||||
for (auto &v : output_values)
|
||||
{
|
||||
if (m_parr.HasParam(PF_PARAM_NONE, float4_name, v))
|
||||
{
|
||||
gather_output_registers = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Explicitly discard on encountering null shaders
|
||||
if (gather_output_registers)
|
||||
{
|
||||
bool has_any_output = false;
|
||||
bool first_output_exists = false;
|
||||
|
||||
if (use_32_bit_exports || exports_depth)
|
||||
{
|
||||
for (int reg = 0; reg < 5; ++reg)
|
||||
{
|
||||
if (reg == 1 && !exports_depth)
|
||||
continue;
|
||||
|
||||
const std::string half_register = "h" + std::to_string(reg + 1);
|
||||
if (m_parr.HasParam(PF_PARAM_NONE, float4_name, half_register))
|
||||
{
|
||||
has_any_output = true;
|
||||
if (!reg) first_output_exists = true;
|
||||
|
||||
const std::string this_register = "r" + std::to_string(reg);
|
||||
AddReg(reg, 0);
|
||||
AddCode("//Register gather because output was not specified");
|
||||
AddCode(this_register + ".zw = gather(" + half_register + ");");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_any_output)
|
||||
{
|
||||
properties.has_no_output = true;
|
||||
|
||||
LOG_ERROR(RSX, "Invalid fragment shader: No output register was updated!");
|
||||
|
||||
//Comment out main block as it is now useless
|
||||
main = "/*\n" + main + "*/\n";
|
||||
AddCode("//No output, manually abort writes (nvidia+vulkan writes garbage otherwise)");
|
||||
AddCode("discard;");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Requires gather operation for output...
|
||||
properties.has_gather_op = true;
|
||||
|
||||
if (!first_output_exists)
|
||||
{
|
||||
LOG_WARNING(RSX, "Fragment shader does not write to first RTT and has no explicit output registers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream OS;
|
||||
insertHeader(OS);
|
||||
OS << "\n";
|
||||
@ -830,10 +757,27 @@ std::string FragmentProgramDecompiler::Decompile()
|
||||
|
||||
int forced_unit = FORCE_NONE;
|
||||
|
||||
//Add the output registers. They are statically written to and have guaranteed initialization (except r1.z which == wpos.z)
|
||||
//This can be used instead of an explicit clear pass in some games (Motorstorm)
|
||||
if (m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS)
|
||||
{
|
||||
AddReg(0, CELL_GCM_FALSE);
|
||||
AddReg(2, CELL_GCM_FALSE);
|
||||
AddReg(3, CELL_GCM_FALSE);
|
||||
AddReg(4, CELL_GCM_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddReg(0, CELL_GCM_TRUE);
|
||||
AddReg(4, CELL_GCM_TRUE);
|
||||
AddReg(6, CELL_GCM_TRUE);
|
||||
AddReg(8, CELL_GCM_TRUE);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
|
||||
found != m_end_offsets.end();
|
||||
found != m_end_offsets.end();
|
||||
found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
|
||||
{
|
||||
m_end_offsets.erase(found);
|
||||
@ -843,7 +787,7 @@ std::string FragmentProgramDecompiler::Decompile()
|
||||
}
|
||||
|
||||
for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
|
||||
found != m_else_offsets.end();
|
||||
found != m_else_offsets.end();
|
||||
found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
|
||||
{
|
||||
m_else_offsets.erase(found);
|
||||
|
Loading…
x
Reference in New Issue
Block a user