From 86135864da9bbbd5906e96862994bd24f3cd4da5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 9 Apr 2018 23:39:44 -0400 Subject: [PATCH] gl_shader_decompiler: Implement negate, abs, etc. and lots of cleanup. --- src/video_core/engines/shader_bytecode.h | 59 +++++++++----- .../renderer_opengl/gl_shader_decompiler.cpp | 81 ++++++++++++++----- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index a4d02e5729..dbcd237552 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -56,15 +56,18 @@ union Attribute { Attribute_0 = 8, }; - constexpr Index GetIndex() const { - return index; - } + union { + BitField<22, 2, u64> element; + BitField<24, 6, Index> index; + BitField<47, 3, u64> size; + } fmt20; + + union { + BitField<30, 2, u64> element; + BitField<32, 6, Index> index; + } fmt28; -public: - BitField<24, 6, Index> index; - BitField<22, 2, u64> element; BitField<39, 8, u64> reg; - BitField<47, 3, u64> size; u64 value; }; @@ -104,6 +107,7 @@ union OpCode { enum class Type { Trivial, Arithmetic, + Ffma, Flow, Memory, Unknown, @@ -210,12 +214,11 @@ union OpCode { info_table[Id::TEXS] = {Type::Memory, "texs"}; info_table[Id::LD_A] = {Type::Memory, "ld_a"}; info_table[Id::ST_A] = {Type::Memory, "st_a"}; - info_table[Id::IPA] = {Type::Arithmetic, "ipa"}; info_table[Id::MUFU] = {Type::Arithmetic, "mufu"}; - info_table[Id::FFMA_IMM] = {Type::Arithmetic, "ffma_imm"}; - info_table[Id::FFMA_CR] = {Type::Arithmetic, "ffma_cr"}; - info_table[Id::FFMA_RC] = {Type::Arithmetic, "ffma_rc"}; - info_table[Id::FFMA_RR] = {Type::Arithmetic, "ffma_rr"}; + info_table[Id::FFMA_IMM] = {Type::Ffma, "ffma_imm"}; + info_table[Id::FFMA_CR] = {Type::Ffma, "ffma_cr"}; + info_table[Id::FFMA_RC] = {Type::Ffma, "ffma_rc"}; + info_table[Id::FFMA_RR] = {Type::Ffma, "ffma_rr"}; info_table[Id::FADD_R] = {Type::Arithmetic, "fadd_r"}; info_table[Id::FADD_C] = {Type::Arithmetic, "fadd_c"}; info_table[Id::FADD_IMM] = {Type::Arithmetic, "fadd_imm"}; @@ -225,6 +228,7 @@ union OpCode { info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"}; info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"}; info_table[Id::EXIT] = {Type::Trivial, "exit"}; + info_table[Id::IPA] = {Type::Trivial, "ipa"}; info_table[Id::KIL] = {Type::Flow, "kil"}; return info_table; } @@ -285,16 +289,31 @@ union Instruction { } OpCode opcode; - BitField<0, 8, Register> gpr1; - BitField<8, 8, Register> gpr2; + BitField<0, 8, Register> gpr0; + BitField<8, 8, Register> gpr8; BitField<16, 4, Pred> pred; + BitField<20, 8, Register> gpr20; BitField<20, 7, SubOp> sub_op; - BitField<39, 8, Register> gpr3; - BitField<45, 1, u64> nb; - BitField<46, 1, u64> aa; - BitField<48, 1, u64> na; - BitField<49, 1, u64> ab; - BitField<50, 1, u64> ad; + BitField<28, 8, Register> gpr28; + BitField<36, 13, u64> imm36; + BitField<39, 8, Register> gpr39; + + union { + BitField<45, 1, u64> negate_b; + BitField<46, 1, u64> abs_a; + BitField<48, 1, u64> negate_a; + BitField<49, 1, u64> abs_b; + BitField<50, 1, u64> abs_d; + } alu; + + union { + BitField<48, 1, u64> negate_b; + BitField<49, 1, u64> negate_c; + } ffma; + + BitField<60, 1, u64> is_b_gpr; + BitField<59, 1, u64> is_c_gpr; + Attribute attribute; Uniform uniform; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 704b24307d..792b4b12e7 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -17,6 +17,7 @@ using Tegra::Shader::Attribute; using Tegra::Shader::Instruction; using Tegra::Shader::OpCode; using Tegra::Shader::Register; +using Tegra::Shader::SubOp; using Tegra::Shader::Uniform; constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; @@ -235,27 +236,34 @@ private: switch (OpCode::GetInfo(instr.opcode).type) { case OpCode::Type::Arithmetic: { - ASSERT(!instr.nb); - ASSERT(!instr.aa); - ASSERT(!instr.na); - ASSERT(!instr.ab); - ASSERT(!instr.ad); + ASSERT(!instr.alu.abs_d, "unimplemented"); - std::string gpr1 = GetRegister(instr.gpr1); - std::string gpr2 = GetRegister(instr.gpr2); - std::string uniform = GetUniform(instr.uniform); + std::string dest = GetRegister(instr.gpr0); + std::string op_a = instr.alu.negate_a ? "-" : ""; + op_a += GetRegister(instr.gpr8); + if (instr.alu.abs_a) { + op_a = "abs(" + op_a + ")"; + } + + std::string op_b = instr.alu.negate_b ? "-" : ""; + if (instr.is_b_gpr) { + op_b += GetRegister(instr.gpr20); + } else { + op_b += GetUniform(instr.uniform); + } + if (instr.alu.abs_b) { + op_b = "abs(" + op_b + ")"; + } switch (instr.opcode.EffectiveOpCode()) { - case OpCode::Id::FMUL_C: { - SetDest(0, gpr1, gpr2 + " * " + uniform, 1, 1); + case OpCode::Id::FMUL_C: + case OpCode::Id::FMUL_R: { + SetDest(0, dest, op_a + " * " + op_b, 1, 1); break; } - case OpCode::Id::FADD_C: { - SetDest(0, gpr1, gpr2 + " + " + uniform, 1, 1); - break; - } - case OpCode::Id::FFMA_CR: { - SetDest(0, gpr1, gpr2 + " * " + uniform + " + " + GetRegister(instr.gpr3), 1, 1); + case OpCode::Id::FADD_C: + case OpCode::Id::FADD_R: { + SetDest(0, dest, op_a + " + " + op_b, 1, 1); break; } default: { @@ -268,19 +276,48 @@ private: } break; } - case OpCode::Type::Memory: { - ASSERT(instr.attribute.size == 0); + case OpCode::Type::Ffma: { + ASSERT_MSG(!instr.ffma.negate_b, "untested"); + ASSERT_MSG(!instr.ffma.negate_c, "untested"); - std::string gpr1 = GetRegister(instr.gpr1); - const Attribute::Index attribute = instr.attribute.GetIndex(); + std::string dest = GetRegister(instr.gpr0); + std::string op_a = GetRegister(instr.gpr8); + + std::string op_b = instr.ffma.negate_b ? "-" : ""; + op_b += GetUniform(instr.uniform); + + std::string op_c = instr.ffma.negate_c ? "-" : ""; + op_c += GetRegister(instr.gpr39); + + switch (instr.opcode.EffectiveOpCode()) { + case OpCode::Id::FFMA_CR: { + SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); + break; + } + + default: { + LOG_ERROR(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x", + (int)instr.opcode.EffectiveOpCode(), OpCode::GetInfo(instr.opcode).name, + instr.hex); + throw DecompileFail("Unhandled instruction"); + break; + } + } + break; + } + case OpCode::Type::Memory: { + std::string gpr0 = GetRegister(instr.gpr0); + const Attribute::Index attribute = instr.attribute.fmt20.index; switch (instr.opcode.EffectiveOpCode()) { case OpCode::Id::LD_A: { - SetDest(instr.attribute.element, gpr1, GetInputAttribute(attribute), 1, 4); + ASSERT(instr.attribute.fmt20.size == 0); + SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); break; } case OpCode::Id::ST_A: { - SetDest(instr.attribute.element, GetOutputAttribute(attribute), gpr1, 4, 1); + ASSERT(instr.attribute.fmt20.size == 0); + SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); break; } default: {