diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index ffec4965d2..10c8a7d134 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -111,7 +111,7 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask) } u32 reg_index = dst.fp16 ? dst.dest_reg >> 1 : dst.dest_reg; - temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16); + temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16, dst.mask_x, dst.mask_y, dst.mask_z, dst.mask_w); } void FragmentProgramDecompiler::AddFlowOp(std::string code) @@ -283,14 +283,15 @@ std::string FragmentProgramDecompiler::Format(const std::string& code, bool igno { "$_i", [this]() -> std::string {return std::to_string(dst.tex_num);} }, { "$m", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetMask), this) }, { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } }, { "$cond", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetCond), this) }, - { "$_c", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddConst), this) } + { "$_c", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddConst), this) }, + { "$float4", [this]() -> std::string { return getFloatTypeName(4); } } }; if (!ignore_redirects) @@ -407,20 +408,13 @@ template std::string FragmentProgramDecompiler::GetSRC(T src) dst.opcode == RSX_FP_OPCODE_UPB || dst.opcode == RSX_FP_OPCODE_UPG) { - //TODO: Implement aliased gather for half floats - bool xy_read = false; - bool zw_read = false; - - if (src.swizzle_x < 2 || src.swizzle_y < 2 || src.swizzle_z < 2 || src.swizzle_w < 2) - xy_read = true; - if (src.swizzle_x > 1 || src.swizzle_y > 1 || src.swizzle_z > 1 || src.swizzle_w > 1) - zw_read = true; - auto ® = temp_registers[src.tmp_reg_index]; - if (reg.requires_gather(xy_read, zw_read)) + if (reg.requires_gather(src.swizzle_x)) { properties.has_gather_op = true; - AddCode(reg.gather_r()); + AddReg(src.tmp_reg_index, src.fp16); + ret = getFloatTypeName(4) + reg.gather_r(); + break; } } } diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h index 569d9e10c5..67d66598fb 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.h @@ -24,25 +24,41 @@ class FragmentProgramDecompiler bool aliased_r0 = false; bool aliased_h0 = false; bool aliased_h1 = false; - bool last_write_half = false; + bool last_write_half[4] = { false, false, false, false }; u32 real_index = UINT32_MAX; - void tag(u32 index, bool half_register) + void tag(u32 index, bool half_register, bool x, bool y, bool z, bool w) { if (half_register) { - last_write_half = true; - if (index & 1) + { + if (x) last_write_half[2] = true; + if (y) last_write_half[2] = true; + if (z) last_write_half[3] = true; + if (w) last_write_half[3] = true; + aliased_h1 = true; + } else + { + if (x) last_write_half[0] = true; + if (y) last_write_half[0] = true; + if (z) last_write_half[1] = true; + if (w) last_write_half[1] = true; + aliased_h0 = true; + } } else { + if (x) last_write_half[0] = false; + if (y) last_write_half[1] = false; + if (z) last_write_half[2] = false; + if (w) last_write_half[3] = false; + aliased_r0 = true; - last_write_half = false; } if (real_index == UINT32_MAX) @@ -54,12 +70,19 @@ class FragmentProgramDecompiler } } - bool requires_gather(bool xy, bool zw) const + bool requires_gather(u8 channel) const { //Data fetched from the single precision register requires merging of the two half registers - //TODO: Check individual swizzle channels - if ((aliased_h0 && xy) || (aliased_h1 && zw)) - return last_write_half; + verify(HERE), channel < 4; + if (aliased_h0 && channel < 2) + { + return last_write_half[channel]; + } + + if (aliased_h1 && channel > 1) + { + return last_write_half[channel]; + } return false; } @@ -67,7 +90,7 @@ class FragmentProgramDecompiler bool requires_split(u32 /*index*/) const { //Data fetched from any of the two half registers requires sync with the full register - if (!last_write_half && aliased_r0) + if (!(last_write_half[0] || last_write_half[1]) && aliased_r0) { //r0 has been written to //TODO: Check for specific elements in real32 register @@ -85,15 +108,12 @@ class FragmentProgramDecompiler std::string ret = "//Invalid gather"; if (aliased_h0 && aliased_h1) - ret = reg + " = gather(" + h0 + ", " + h1 + ");"; + ret = "(gather(" + h0 + ", " + h1 + "))"; else if (aliased_h0) - ret = reg + ".xy = gather(" + h0 + ");"; + ret = "(gather(" + h0 + "), " + reg + ".zw)"; else if (aliased_h1) - ret = reg + ".zw = gather(" + h1 + ");"; + ret = "(" + reg + ".xy, gather(" + h1 + "))"; - last_write_half = false; - aliased_h0 = false; - aliased_h1 = false; return ret; } };