diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index e1ceec268..4ed1429b0 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -193,6 +193,11 @@ union Instruction { BitField<50, 1, u64> abs_d; BitField<56, 1, u64> negate_imm; + union { + BitField<39, 3, u64> pred; + BitField<42, 1, u64> negate_pred; + } fmnmx; + float GetImm20_19() const { float result{}; u32 imm{static_cast(imm20_19)}; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index abbf0893d..1aa24da46 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -580,14 +580,17 @@ private: * @param instr Instruction to generate the if condition for. * @returns string containing the predicate condition. */ - std::string GetPredicateCondition(Instruction instr) const { + std::string GetPredicateCondition(u64 index, bool negate) const { using Tegra::Shader::Pred; - ASSERT(instr.pred.pred_index != static_cast(Pred::UnusedIndex)); + std::string variable; - std::string variable = - 'p' + std::to_string(static_cast(instr.pred.pred_index.Value())); + // Index 7 is used as an 'Always True' condition. + if (index == static_cast(Pred::UnusedIndex)) + variable = "true"; + else + variable = 'p' + std::to_string(index); - if (instr.negate_pred) { + if (negate) { return "!(" + variable + ')'; } @@ -634,7 +637,9 @@ private: "NeverExecute predicate not implemented"); if (instr.pred.pred_index != static_cast(Pred::UnusedIndex)) { - shader.AddLine("if (" + GetPredicateCondition(instr) + ')'); + shader.AddLine("if (" + + GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) + + ')'); shader.AddLine('{'); ++shader.scope; } @@ -730,6 +735,16 @@ private: } break; } + case OpCode::Id::FMNMX: { + std::string condition = + GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); + std::string parameters = op_a + ',' + op_b; + regs.SetRegisterToFloat(instr.gpr0, 0, + '(' + condition + ") ? min(" + parameters + ") : max(" + + parameters + ')', + 1, 1); + break; + } case OpCode::Id::RRO: { NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction"); break;