diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 10c8a7d134..2c31f31a90 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -496,79 +496,6 @@ template 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 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);