Merge pull request #532 from bunnei/ld_c
gl_shader_decompiler: Implement LD_C instruction.
This commit is contained in:
commit
cfc9effa6c
|
@ -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