Merge pull request #532 from bunnei/ld_c
gl_shader_decompiler: Implement LD_C instruction.
This commit is contained in:
		| @@ -109,11 +109,6 @@ union Sampler { | |||||||
|     u64 value{}; |     u64 value{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| union Uniform { |  | ||||||
|     BitField<20, 14, u64> offset; |  | ||||||
|     BitField<34, 5, u64> index; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| } // namespace Shader | } // namespace Shader | ||||||
| } // namespace Tegra | } // namespace Tegra | ||||||
|  |  | ||||||
| @@ -180,6 +175,15 @@ enum class FloatRoundingOp : u64 { | |||||||
|     Trunc = 3, |     Trunc = 3, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum class UniformType : u64 { | ||||||
|  |     UnsignedByte = 0, | ||||||
|  |     SignedByte = 1, | ||||||
|  |     UnsignedShort = 2, | ||||||
|  |     SignedShort = 3, | ||||||
|  |     Single = 4, | ||||||
|  |     Double = 5, | ||||||
|  | }; | ||||||
|  |  | ||||||
| union Instruction { | union Instruction { | ||||||
|     Instruction& operator=(const Instruction& instr) { |     Instruction& operator=(const Instruction& instr) { | ||||||
|         value = instr.value; |         value = instr.value; | ||||||
| @@ -257,6 +261,11 @@ union Instruction { | |||||||
|         BitField<49, 1, u64> negate_c; |         BitField<49, 1, u64> negate_c; | ||||||
|     } ffma; |     } ffma; | ||||||
|  |  | ||||||
|  |     union { | ||||||
|  |         BitField<48, 3, UniformType> type; | ||||||
|  |         BitField<44, 2, u64> unknown; | ||||||
|  |     } ld_c; | ||||||
|  |  | ||||||
|     union { |     union { | ||||||
|         BitField<0, 3, u64> pred0; |         BitField<0, 3, u64> pred0; | ||||||
|         BitField<3, 3, u64> pred3; |         BitField<3, 3, u64> pred3; | ||||||
| @@ -354,12 +363,21 @@ union Instruction { | |||||||
|         } |         } | ||||||
|     } bra; |     } bra; | ||||||
|  |  | ||||||
|  |     union { | ||||||
|  |         BitField<20, 14, u64> offset; | ||||||
|  |         BitField<34, 5, u64> index; | ||||||
|  |     } cbuf34; | ||||||
|  |  | ||||||
|  |     union { | ||||||
|  |         BitField<20, 16, s64> offset; | ||||||
|  |         BitField<36, 5, u64> index; | ||||||
|  |     } cbuf36; | ||||||
|  |  | ||||||
|     BitField<61, 1, u64> is_b_imm; |     BitField<61, 1, u64> is_b_imm; | ||||||
|     BitField<60, 1, u64> is_b_gpr; |     BitField<60, 1, u64> is_b_gpr; | ||||||
|     BitField<59, 1, u64> is_c_gpr; |     BitField<59, 1, u64> is_c_gpr; | ||||||
|  |  | ||||||
|     Attribute attribute; |     Attribute attribute; | ||||||
|     Uniform uniform; |  | ||||||
|     Sampler sampler; |     Sampler sampler; | ||||||
|  |  | ||||||
|     u64 value; |     u64 value; | ||||||
| @@ -374,6 +392,7 @@ public: | |||||||
|         KIL, |         KIL, | ||||||
|         BRA, |         BRA, | ||||||
|         LD_A, |         LD_A, | ||||||
|  |         LD_C, | ||||||
|         ST_A, |         ST_A, | ||||||
|         TEX, |         TEX, | ||||||
|         TEXQ, // Texture Query |         TEXQ, // Texture Query | ||||||
| @@ -548,6 +567,7 @@ private: | |||||||
|             INST("111000110011----", Id::KIL, Type::Flow, "KIL"), |             INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | ||||||
|             INST("111000100100----", Id::BRA, Type::Flow, "BRA"), |             INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | ||||||
|             INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), |             INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), | ||||||
|  |             INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), | ||||||
|             INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), |             INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), | ||||||
|             INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), |             INST("1100000000111---", Id::TEX, Type::Memory, "TEX"), | ||||||
|             INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), |             INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), | ||||||
|   | |||||||
| @@ -654,7 +654,16 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr | |||||||
|         buffer_draw_state.bindpoint = current_bindpoint + bindpoint; |         buffer_draw_state.bindpoint = current_bindpoint + bindpoint; | ||||||
|  |  | ||||||
|         boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); |         boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address); | ||||||
|         std::vector<u8> data(used_buffer.GetSize() * sizeof(float)); |  | ||||||
|  |         std::vector<u8> data; | ||||||
|  |         if (used_buffer.IsIndirect()) { | ||||||
|  |             // Buffer is accessed indirectly, so upload the entire thing | ||||||
|  |             data.resize(buffer.size * sizeof(float)); | ||||||
|  |         } else { | ||||||
|  |             // Buffer is accessed directly, upload just what we use | ||||||
|  |             data.resize(used_buffer.GetSize() * sizeof(float)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         Memory::ReadBlock(*addr, data.data(), data.size()); |         Memory::ReadBlock(*addr, data.data(), data.size()); | ||||||
|  |  | ||||||
|         glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); |         glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ using Tegra::Shader::OpCode; | |||||||
| using Tegra::Shader::Register; | using Tegra::Shader::Register; | ||||||
| using Tegra::Shader::Sampler; | using Tegra::Shader::Sampler; | ||||||
| using Tegra::Shader::SubOp; | using Tegra::Shader::SubOp; | ||||||
| using Tegra::Shader::Uniform; |  | ||||||
|  |  | ||||||
| constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; | constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; | ||||||
|  |  | ||||||
| @@ -365,11 +364,9 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Generates code representing a uniform (C buffer) register, interpreted as the input type. |     /// Generates code representing a uniform (C buffer) register, interpreted as the input type. | ||||||
|     std::string GetUniform(const Uniform& uniform, GLSLRegister::Type type) { |     std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) { | ||||||
|         declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index), |         declr_const_buffers[index].MarkAsUsed(index, offset, stage); | ||||||
|                                                       static_cast<unsigned>(uniform.offset), stage); |         std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset) + ']'; | ||||||
|         std::string value = |  | ||||||
|             'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']'; |  | ||||||
|  |  | ||||||
|         if (type == GLSLRegister::Type::Float) { |         if (type == GLSLRegister::Type::Float) { | ||||||
|             return value; |             return value; | ||||||
| @@ -380,10 +377,19 @@ public: | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Generates code representing a uniform (C buffer) register, interpreted as the type of the |     std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg, | ||||||
|     /// destination register. |                                    GLSLRegister::Type type) { | ||||||
|     std::string GetUniform(const Uniform& uniform, const Register& dest_reg) { |         declr_const_buffers[index].MarkAsUsedIndirect(index, stage); | ||||||
|         return GetUniform(uniform, regs[dest_reg].GetActiveType()); |         std::string value = 'c' + std::to_string(index) + "[(floatBitsToInt(" + | ||||||
|  |                             GetRegister(index_reg, 0) + ") + " + std::to_string(offset) + ") / 4]"; | ||||||
|  |  | ||||||
|  |         if (type == GLSLRegister::Type::Float) { | ||||||
|  |             return value; | ||||||
|  |         } else if (type == GLSLRegister::Type::Integer) { | ||||||
|  |             return "floatBitsToInt(" + value + ')'; | ||||||
|  |         } else { | ||||||
|  |             UNREACHABLE(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Add declarations for registers |     /// Add declarations for registers | ||||||
| @@ -747,7 +753,8 @@ private: | |||||||
|                 if (instr.is_b_gpr) { |                 if (instr.is_b_gpr) { | ||||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); |                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||||
|                 } else { |                 } else { | ||||||
|                     op_b += regs.GetUniform(instr.uniform, instr.gpr0); |                     op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                             GLSLRegister::Type::Float); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -904,7 +911,8 @@ private: | |||||||
|                 if (instr.is_b_gpr) { |                 if (instr.is_b_gpr) { | ||||||
|                     op_b += regs.GetRegisterAsInteger(instr.gpr20); |                     op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||||||
|                 } else { |                 } else { | ||||||
|                     op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); |                     op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                             GLSLRegister::Type::Integer); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -936,7 +944,8 @@ private: | |||||||
|                 if (instr.is_b_gpr) { |                 if (instr.is_b_gpr) { | ||||||
|                     op_b += regs.GetRegisterAsInteger(instr.gpr20); |                     op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||||||
|                 } else { |                 } else { | ||||||
|                     op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); |                     op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                             GLSLRegister::Type::Integer); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -953,7 +962,8 @@ private: | |||||||
|  |  | ||||||
|             switch (opcode->GetId()) { |             switch (opcode->GetId()) { | ||||||
|             case OpCode::Id::FFMA_CR: { |             case OpCode::Id::FFMA_CR: { | ||||||
|                 op_b += regs.GetUniform(instr.uniform, instr.gpr0); |                 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                         GLSLRegister::Type::Float); | ||||||
|                 op_c += regs.GetRegisterAsFloat(instr.gpr39); |                 op_c += regs.GetRegisterAsFloat(instr.gpr39); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| @@ -964,7 +974,8 @@ private: | |||||||
|             } |             } | ||||||
|             case OpCode::Id::FFMA_RC: { |             case OpCode::Id::FFMA_RC: { | ||||||
|                 op_b += regs.GetRegisterAsFloat(instr.gpr39); |                 op_b += regs.GetRegisterAsFloat(instr.gpr39); | ||||||
|                 op_c += regs.GetUniform(instr.uniform, instr.gpr0); |                 op_c += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                         GLSLRegister::Type::Float); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             case OpCode::Id::FFMA_IMM: { |             case OpCode::Id::FFMA_IMM: { | ||||||
| @@ -1079,6 +1090,33 @@ private: | |||||||
|                                                 attribute); |                                                 attribute); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|  |             case OpCode::Id::LD_C: { | ||||||
|  |                 ASSERT_MSG(instr.ld_c.unknown == 0, "Unimplemented"); | ||||||
|  |  | ||||||
|  |                 std::string op_a = | ||||||
|  |                     regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 0, instr.gpr8, | ||||||
|  |                                             GLSLRegister::Type::Float); | ||||||
|  |                 std::string op_b = | ||||||
|  |                     regs.GetUniformIndirect(instr.cbuf36.index, instr.cbuf36.offset + 4, instr.gpr8, | ||||||
|  |                                             GLSLRegister::Type::Float); | ||||||
|  |  | ||||||
|  |                 switch (instr.ld_c.type.Value()) { | ||||||
|  |                 case Tegra::Shader::UniformType::Single: | ||||||
|  |                     regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 case Tegra::Shader::UniformType::Double: | ||||||
|  |                     regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); | ||||||
|  |                     regs.SetRegisterToFloat(instr.gpr0.Value() + 1, 0, op_b, 1, 1); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 default: | ||||||
|  |                     NGLOG_CRITICAL(HW_GPU, "Unhandled type: {}", | ||||||
|  |                                    static_cast<unsigned>(instr.ld_c.type.Value())); | ||||||
|  |                     UNREACHABLE(); | ||||||
|  |                 } | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|             case OpCode::Id::ST_A: { |             case OpCode::Id::ST_A: { | ||||||
|                 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); |                 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); | ||||||
|                 regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element, |                 regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element, | ||||||
| @@ -1175,7 +1213,8 @@ private: | |||||||
|                 if (instr.is_b_gpr) { |                 if (instr.is_b_gpr) { | ||||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); |                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||||
|                 } else { |                 } else { | ||||||
|                     op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float); |                     op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                             GLSLRegister::Type::Float); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -1216,7 +1255,8 @@ private: | |||||||
|             if (instr.is_b_gpr) { |             if (instr.is_b_gpr) { | ||||||
|                 op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed); |                 op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed); | ||||||
|             } else { |             } else { | ||||||
|                 op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); |                 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                         GLSLRegister::Type::Integer); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             using Tegra::Shader::Pred; |             using Tegra::Shader::Pred; | ||||||
| @@ -1262,7 +1302,8 @@ private: | |||||||
|                 if (instr.is_b_gpr) { |                 if (instr.is_b_gpr) { | ||||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); |                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||||
|                 } else { |                 } else { | ||||||
|                     op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float); |                     op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, | ||||||
|  |                                             GLSLRegister::Type::Float); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,17 +22,28 @@ class ConstBufferEntry { | |||||||
|     using Maxwell = Tegra::Engines::Maxwell3D::Regs; |     using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     void MarkAsUsed(unsigned index, unsigned offset, Maxwell::ShaderStage stage) { |     void MarkAsUsed(u64 index, u64 offset, Maxwell::ShaderStage stage) { | ||||||
|         is_used = true; |         is_used = true; | ||||||
|         this->index = index; |         this->index = static_cast<unsigned>(index); | ||||||
|  |         this->stage = stage; | ||||||
|  |         max_offset = std::max(max_offset, static_cast<unsigned>(offset)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void MarkAsUsedIndirect(u64 index, Maxwell::ShaderStage stage) { | ||||||
|  |         is_used = true; | ||||||
|  |         is_indirect = true; | ||||||
|  |         this->index = static_cast<unsigned>(index); | ||||||
|         this->stage = stage; |         this->stage = stage; | ||||||
|         max_offset = std::max(max_offset, offset); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool IsUsed() const { |     bool IsUsed() const { | ||||||
|         return is_used; |         return is_used; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     bool IsIndirect() const { | ||||||
|  |         return is_indirect; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     unsigned GetIndex() const { |     unsigned GetIndex() const { | ||||||
|         return index; |         return index; | ||||||
|     } |     } | ||||||
| @@ -51,6 +62,7 @@ private: | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     bool is_used{}; |     bool is_used{}; | ||||||
|  |     bool is_indirect{}; | ||||||
|     unsigned index{}; |     unsigned index{}; | ||||||
|     unsigned max_offset{}; |     unsigned max_offset{}; | ||||||
|     Maxwell::ShaderStage stage; |     Maxwell::ShaderStage stage; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user