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{}; | ||||
| }; | ||||
|  | ||||
| union Uniform { | ||||
|     BitField<20, 14, u64> offset; | ||||
|     BitField<34, 5, u64> index; | ||||
| }; | ||||
|  | ||||
| } // namespace Shader | ||||
| } // namespace Tegra | ||||
|  | ||||
| @@ -180,6 +175,15 @@ enum class FloatRoundingOp : u64 { | ||||
|     Trunc = 3, | ||||
| }; | ||||
|  | ||||
| enum class UniformType : u64 { | ||||
|     UnsignedByte = 0, | ||||
|     SignedByte = 1, | ||||
|     UnsignedShort = 2, | ||||
|     SignedShort = 3, | ||||
|     Single = 4, | ||||
|     Double = 5, | ||||
| }; | ||||
|  | ||||
| union Instruction { | ||||
|     Instruction& operator=(const Instruction& instr) { | ||||
|         value = instr.value; | ||||
| @@ -257,6 +261,11 @@ union Instruction { | ||||
|         BitField<49, 1, u64> negate_c; | ||||
|     } ffma; | ||||
|  | ||||
|     union { | ||||
|         BitField<48, 3, UniformType> type; | ||||
|         BitField<44, 2, u64> unknown; | ||||
|     } ld_c; | ||||
|  | ||||
|     union { | ||||
|         BitField<0, 3, u64> pred0; | ||||
|         BitField<3, 3, u64> pred3; | ||||
| @@ -354,12 +363,21 @@ union Instruction { | ||||
|         } | ||||
|     } 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<60, 1, u64> is_b_gpr; | ||||
|     BitField<59, 1, u64> is_c_gpr; | ||||
|  | ||||
|     Attribute attribute; | ||||
|     Uniform uniform; | ||||
|     Sampler sampler; | ||||
|  | ||||
|     u64 value; | ||||
| @@ -374,6 +392,7 @@ public: | ||||
|         KIL, | ||||
|         BRA, | ||||
|         LD_A, | ||||
|         LD_C, | ||||
|         ST_A, | ||||
|         TEX, | ||||
|         TEXQ, // Texture Query | ||||
| @@ -548,6 +567,7 @@ private: | ||||
|             INST("111000110011----", Id::KIL, Type::Flow, "KIL"), | ||||
|             INST("111000100100----", Id::BRA, Type::Flow, "BRA"), | ||||
|             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("1100000000111---", Id::TEX, Type::Memory, "TEX"), | ||||
|             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; | ||||
|  | ||||
|         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()); | ||||
|  | ||||
|         glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo); | ||||
|   | ||||
| @@ -20,7 +20,6 @@ using Tegra::Shader::OpCode; | ||||
| using Tegra::Shader::Register; | ||||
| using Tegra::Shader::Sampler; | ||||
| using Tegra::Shader::SubOp; | ||||
| using Tegra::Shader::Uniform; | ||||
|  | ||||
| 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. | ||||
|     std::string GetUniform(const Uniform& uniform, GLSLRegister::Type type) { | ||||
|         declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index), | ||||
|                                                       static_cast<unsigned>(uniform.offset), stage); | ||||
|         std::string value = | ||||
|             'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']'; | ||||
|     std::string GetUniform(u64 index, u64 offset, GLSLRegister::Type type) { | ||||
|         declr_const_buffers[index].MarkAsUsed(index, offset, stage); | ||||
|         std::string value = 'c' + std::to_string(index) + '[' + std::to_string(offset) + ']'; | ||||
|  | ||||
|         if (type == GLSLRegister::Type::Float) { | ||||
|             return value; | ||||
| @@ -380,10 +377,19 @@ public: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Generates code representing a uniform (C buffer) register, interpreted as the type of the | ||||
|     /// destination register. | ||||
|     std::string GetUniform(const Uniform& uniform, const Register& dest_reg) { | ||||
|         return GetUniform(uniform, regs[dest_reg].GetActiveType()); | ||||
|     std::string GetUniformIndirect(u64 index, s64 offset, const Register& index_reg, | ||||
|                                    GLSLRegister::Type type) { | ||||
|         declr_const_buffers[index].MarkAsUsedIndirect(index, stage); | ||||
|         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 | ||||
| @@ -747,7 +753,8 @@ private: | ||||
|                 if (instr.is_b_gpr) { | ||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||
|                 } 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) { | ||||
|                     op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||||
|                 } 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) { | ||||
|                     op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||||
|                 } 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()) { | ||||
|             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); | ||||
|                 break; | ||||
|             } | ||||
| @@ -964,7 +974,8 @@ private: | ||||
|             } | ||||
|             case OpCode::Id::FFMA_RC: { | ||||
|                 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; | ||||
|             } | ||||
|             case OpCode::Id::FFMA_IMM: { | ||||
| @@ -1079,6 +1090,33 @@ private: | ||||
|                                                 attribute); | ||||
|                 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: { | ||||
|                 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); | ||||
|                 regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element, | ||||
| @@ -1175,7 +1213,8 @@ private: | ||||
|                 if (instr.is_b_gpr) { | ||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||
|                 } 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) { | ||||
|                 op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed); | ||||
|             } 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; | ||||
| @@ -1262,7 +1302,8 @@ private: | ||||
|                 if (instr.is_b_gpr) { | ||||
|                     op_b += regs.GetRegisterAsFloat(instr.gpr20); | ||||
|                 } 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; | ||||
|  | ||||
| public: | ||||
|     void MarkAsUsed(unsigned index, unsigned offset, Maxwell::ShaderStage stage) { | ||||
|     void MarkAsUsed(u64 index, u64 offset, Maxwell::ShaderStage stage) { | ||||
|         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; | ||||
|         max_offset = std::max(max_offset, offset); | ||||
|     } | ||||
|  | ||||
|     bool IsUsed() const { | ||||
|         return is_used; | ||||
|     } | ||||
|  | ||||
|     bool IsIndirect() const { | ||||
|         return is_indirect; | ||||
|     } | ||||
|  | ||||
|     unsigned GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| @@ -51,6 +62,7 @@ private: | ||||
|     }; | ||||
|  | ||||
|     bool is_used{}; | ||||
|     bool is_indirect{}; | ||||
|     unsigned index{}; | ||||
|     unsigned max_offset{}; | ||||
|     Maxwell::ShaderStage stage; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user