|
@@ -153,85 +153,61 @@ private:
|
|
|
*/
|
|
*/
|
|
|
class GLSLRegister {
|
|
class GLSLRegister {
|
|
|
public:
|
|
public:
|
|
|
- GLSLRegister(size_t index, ShaderWriter& shader)
|
|
|
|
|
- : index{index}, shader{shader}, float_str{"freg_" + std::to_string(index)},
|
|
|
|
|
- integer_str{"ireg_" + std::to_string(index)} {}
|
|
|
|
|
|
|
+ enum class Type {
|
|
|
|
|
+ Float,
|
|
|
|
|
+ Integer,
|
|
|
|
|
+ UnsignedInteger,
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- /// Returns a GLSL string representing the current state of the register
|
|
|
|
|
- const std::string& GetActiveString() {
|
|
|
|
|
- declr_type.insert(active_type);
|
|
|
|
|
|
|
+ GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
|
|
|
|
|
|
|
|
- switch (active_type) {
|
|
|
|
|
|
|
+ /// Gets the GLSL type string for a register
|
|
|
|
|
+ static std::string GetTypeString(Type type) {
|
|
|
|
|
+ switch (type) {
|
|
|
case Type::Float:
|
|
case Type::Float:
|
|
|
- return float_str;
|
|
|
|
|
|
|
+ return "float";
|
|
|
case Type::Integer:
|
|
case Type::Integer:
|
|
|
- return integer_str;
|
|
|
|
|
|
|
+ return "int";
|
|
|
|
|
+ case Type::UnsignedInteger:
|
|
|
|
|
+ return "uint";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
UNREACHABLE();
|
|
UNREACHABLE();
|
|
|
- return float_str;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Returns a GLSL string representing the register as a float
|
|
|
|
|
- const std::string& GetFloatString() const {
|
|
|
|
|
- ASSERT(IsFloatUsed());
|
|
|
|
|
- return float_str;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Returns a GLSL string representing the register as an integer
|
|
|
|
|
- const std::string& GetIntegerString() const {
|
|
|
|
|
- ASSERT(IsIntegerUsed());
|
|
|
|
|
- return integer_str;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Convert the current register state from float to integer
|
|
|
|
|
- void FloatToInteger() {
|
|
|
|
|
- ASSERT(active_type == Type::Float);
|
|
|
|
|
-
|
|
|
|
|
- const std::string src = GetActiveString();
|
|
|
|
|
- active_type = Type::Integer;
|
|
|
|
|
- const std::string dest = GetActiveString();
|
|
|
|
|
-
|
|
|
|
|
- shader.AddLine(dest + " = floatBitsToInt(" + src + ");");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Convert the current register state from integer to float
|
|
|
|
|
- void IntegerToFloat() {
|
|
|
|
|
- ASSERT(active_type == Type::Integer);
|
|
|
|
|
-
|
|
|
|
|
- const std::string src = GetActiveString();
|
|
|
|
|
- active_type = Type::Float;
|
|
|
|
|
- const std::string dest = GetActiveString();
|
|
|
|
|
-
|
|
|
|
|
- shader.AddLine(dest + " = intBitsToFloat(" + src + ");");
|
|
|
|
|
|
|
+ return {};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Returns true if the register was ever used as a float, used for register declarations
|
|
|
|
|
- bool IsFloatUsed() const {
|
|
|
|
|
- return declr_type.find(Type::Float) != declr_type.end();
|
|
|
|
|
|
|
+ /// Gets the GLSL register prefix string, used for declarations and referencing
|
|
|
|
|
+ static std::string GetPrefixString(Type type) {
|
|
|
|
|
+ return "reg_" + GetTypeString(type) + '_';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Returns true if the register was ever used as an integer, used for register declarations
|
|
|
|
|
- bool IsIntegerUsed() const {
|
|
|
|
|
- return declr_type.find(Type::Integer) != declr_type.end();
|
|
|
|
|
|
|
+ /// Returns a GLSL string representing the current state of the register
|
|
|
|
|
+ const std::string GetActiveString() {
|
|
|
|
|
+ declr_type.insert(active_type);
|
|
|
|
|
+ return GetPrefixString(active_type) + std::to_string(index);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Returns true if the active type is float
|
|
|
|
|
|
|
+ /// Returns true if the active type is a float
|
|
|
bool IsFloat() const {
|
|
bool IsFloat() const {
|
|
|
return active_type == Type::Float;
|
|
return active_type == Type::Float;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Returns true if the active type is integer
|
|
|
|
|
|
|
+ /// Returns true if the active type is an integer
|
|
|
bool IsInteger() const {
|
|
bool IsInteger() const {
|
|
|
return active_type == Type::Integer;
|
|
return active_type == Type::Integer;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-private:
|
|
|
|
|
- enum class Type {
|
|
|
|
|
- Float,
|
|
|
|
|
- Integer,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ /// Returns the index of the register
|
|
|
|
|
+ size_t GetIndex() const {
|
|
|
|
|
+ return index;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ /// Returns a set of the declared types of the register
|
|
|
|
|
+ const std::set<Type>& DeclaredTypes() const {
|
|
|
|
|
+ return declr_type;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+private:
|
|
|
const size_t index;
|
|
const size_t index;
|
|
|
const std::string float_str;
|
|
const std::string float_str;
|
|
|
const std::string integer_str;
|
|
const std::string integer_str;
|
|
@@ -254,18 +230,35 @@ public:
|
|
|
BuildRegisterList();
|
|
BuildRegisterList();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Generates code representing a temporary (GPR) register.
|
|
|
|
|
- std::string GetRegister(const Register& reg, unsigned elem = 0) {
|
|
|
|
|
- if (reg == Register::ZeroIndex) {
|
|
|
|
|
- return "0";
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Gets a register as an float.
|
|
|
|
|
+ * @param reg The register to get.
|
|
|
|
|
+ * @param elem The element to use for the operation.
|
|
|
|
|
+ * @returns GLSL string corresponding to the register as a float.
|
|
|
|
|
+ */
|
|
|
|
|
+ std::string GetRegisterAsFloat(const Register& reg, unsigned elem = 0) {
|
|
|
|
|
+ ASSERT(regs[reg].IsFloat());
|
|
|
|
|
+ return GetRegister(reg, elem);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Gets a register as an integer.
|
|
|
|
|
+ * @param reg The register to get.
|
|
|
|
|
+ * @param elem The element to use for the operation.
|
|
|
|
|
+ * @param is_signed Whether to get the register as a signed (or unsigned) integer.
|
|
|
|
|
+ * @returns GLSL string corresponding to the register as an integer.
|
|
|
|
|
+ */
|
|
|
|
|
+ std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0,
|
|
|
|
|
+ bool is_signed = true) {
|
|
|
|
|
+ const std::string func = GetGLSLConversionFunc(
|
|
|
|
|
+ GLSLRegister::Type::Float,
|
|
|
|
|
+ is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger);
|
|
|
|
|
+
|
|
|
|
|
+ return func + '(' + GetRegister(reg, elem) + ')';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * Writes code that does a register assignment to float value operation. Should only be used
|
|
|
|
|
- * with shader instructions that deal with floats.
|
|
|
|
|
|
|
+ * Writes code that does a register assignment to float value operation.
|
|
|
* @param reg The destination register to use.
|
|
* @param reg The destination register to use.
|
|
|
* @param elem The element to use for the operation.
|
|
* @param elem The element to use for the operation.
|
|
|
* @param value The code representing the value to assign.
|
|
* @param value The code representing the value to assign.
|
|
@@ -277,21 +270,28 @@ public:
|
|
|
void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
|
|
void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
|
|
|
u64 dest_num_components, u64 value_num_components, bool is_abs = false,
|
|
u64 dest_num_components, u64 value_num_components, bool is_abs = false,
|
|
|
u64 dest_elem = 0) {
|
|
u64 dest_elem = 0) {
|
|
|
- ASSERT(regs[reg].IsFloat());
|
|
|
|
|
-
|
|
|
|
|
- std::string dest = GetRegister(reg, dest_elem);
|
|
|
|
|
- if (dest_num_components > 1) {
|
|
|
|
|
- dest += GetSwizzle(elem);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- std::string src = '(' + value + ')';
|
|
|
|
|
- if (value_num_components > 1) {
|
|
|
|
|
- src += GetSwizzle(elem);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- src = is_abs ? "abs(" + src + ')' : src;
|
|
|
|
|
|
|
+ SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- shader.AddLine(dest + " = " + src + ';');
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Writes code that does a register assignment to integer value operation.
|
|
|
|
|
+ * @param reg The destination register to use.
|
|
|
|
|
+ * @param elem The element to use for the operation.
|
|
|
|
|
+ * @param value The code representing the value to assign.
|
|
|
|
|
+ * @param dest_num_components Number of components in the destination.
|
|
|
|
|
+ * @param value_num_components Number of components in the value.
|
|
|
|
|
+ * @param is_abs Optional, when True, applies absolute value to output.
|
|
|
|
|
+ * @param dest_elem Optional, the destination element to use for the operation.
|
|
|
|
|
+ */
|
|
|
|
|
+ void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
|
|
|
|
|
+ const std::string& value, u64 dest_num_components,
|
|
|
|
|
+ u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) {
|
|
|
|
|
+ const std::string func = GetGLSLConversionFunc(
|
|
|
|
|
+ is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
|
|
|
|
|
+ GLSLRegister::Type::Float);
|
|
|
|
|
+
|
|
|
|
|
+ SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
|
|
|
|
|
+ is_abs, dest_elem);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -302,7 +302,7 @@ public:
|
|
|
* @param attribute The input attibute to use as the source value.
|
|
* @param attribute The input attibute to use as the source value.
|
|
|
*/
|
|
*/
|
|
|
void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
|
|
void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
|
|
|
- std::string dest = GetRegister(reg);
|
|
|
|
|
|
|
+ std::string dest = GetRegisterAsFloat(reg);
|
|
|
std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
|
|
std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
|
|
|
|
|
|
|
|
if (regs[reg].IsFloat()) {
|
|
if (regs[reg].IsFloat()) {
|
|
@@ -323,7 +323,7 @@ public:
|
|
|
*/
|
|
*/
|
|
|
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
|
|
void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
|
|
|
std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
|
|
std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
|
|
|
- std::string src = GetRegister(reg);
|
|
|
|
|
|
|
+ std::string src = GetRegisterAsFloat(reg);
|
|
|
ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
|
|
ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
|
|
|
shader.AddLine(dest + " = " + src + ';');
|
|
shader.AddLine(dest + " = " + src + ';');
|
|
|
}
|
|
}
|
|
@@ -347,11 +347,10 @@ public:
|
|
|
/// Add declarations for registers
|
|
/// Add declarations for registers
|
|
|
void GenerateDeclarations() {
|
|
void GenerateDeclarations() {
|
|
|
for (const auto& reg : regs) {
|
|
for (const auto& reg : regs) {
|
|
|
- if (reg.IsFloatUsed()) {
|
|
|
|
|
- declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
|
|
|
|
|
- }
|
|
|
|
|
- if (reg.IsIntegerUsed()) {
|
|
|
|
|
- declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
|
|
|
|
|
|
|
+ for (const auto& type : reg.DeclaredTypes()) {
|
|
|
|
|
+ declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
|
|
|
|
|
+ GLSLRegister::GetPrefixString(type) +
|
|
|
|
|
+ std::to_string(reg.GetIndex()) + " = 0;");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
declarations.AddNewLine();
|
|
declarations.AddNewLine();
|
|
@@ -395,6 +394,51 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
|
|
+ /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc.
|
|
|
|
|
+ const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const {
|
|
|
|
|
+ const std::string src_type = GLSLRegister::GetTypeString(src);
|
|
|
|
|
+ std::string dest_type = GLSLRegister::GetTypeString(dest);
|
|
|
|
|
+ dest_type[0] = toupper(dest_type[0]);
|
|
|
|
|
+ return src_type + "BitsTo" + dest_type;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Generates code representing a temporary (GPR) register.
|
|
|
|
|
+ std::string GetRegister(const Register& reg, unsigned elem) {
|
|
|
|
|
+ if (reg == Register::ZeroIndex) {
|
|
|
|
|
+ return "0";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Writes code that does a register assignment to value operation.
|
|
|
|
|
+ * @param reg The destination register to use.
|
|
|
|
|
+ * @param elem The element to use for the operation.
|
|
|
|
|
+ * @param value The code representing the value to assign.
|
|
|
|
|
+ * @param dest_num_components Number of components in the destination.
|
|
|
|
|
+ * @param value_num_components Number of components in the value.
|
|
|
|
|
+ * @param is_abs Optional, when True, applies absolute value to output.
|
|
|
|
|
+ * @param dest_elem Optional, the destination element to use for the operation.
|
|
|
|
|
+ */
|
|
|
|
|
+ void SetRegister(const Register& reg, u64 elem, const std::string& value,
|
|
|
|
|
+ u64 dest_num_components, u64 value_num_components, bool is_abs,
|
|
|
|
|
+ u64 dest_elem) {
|
|
|
|
|
+ std::string dest = GetRegister(reg, dest_elem);
|
|
|
|
|
+ if (dest_num_components > 1) {
|
|
|
|
|
+ dest += GetSwizzle(elem);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ std::string src = '(' + value + ')';
|
|
|
|
|
+ if (value_num_components > 1) {
|
|
|
|
|
+ src += GetSwizzle(elem);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ src = is_abs ? "abs(" + src + ')' : src;
|
|
|
|
|
+
|
|
|
|
|
+ shader.AddLine(dest + " = " + src + ';');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// Build the GLSL register list.
|
|
/// Build the GLSL register list.
|
|
|
void BuildRegisterList() {
|
|
void BuildRegisterList() {
|
|
|
for (size_t index = 0; index < Register::NumRegisters; ++index) {
|
|
for (size_t index = 0; index < Register::NumRegisters; ++index) {
|
|
@@ -598,7 +642,7 @@ private:
|
|
|
switch (opcode->GetType()) {
|
|
switch (opcode->GetType()) {
|
|
|
case OpCode::Type::Arithmetic: {
|
|
case OpCode::Type::Arithmetic: {
|
|
|
std::string op_a = instr.alu.negate_a ? "-" : "";
|
|
std::string op_a = instr.alu.negate_a ? "-" : "";
|
|
|
- op_a += regs.GetRegister(instr.gpr8);
|
|
|
|
|
|
|
+ op_a += regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
if (instr.alu.abs_a) {
|
|
if (instr.alu.abs_a) {
|
|
|
op_a = "abs(" + op_a + ')';
|
|
op_a = "abs(" + op_a + ')';
|
|
|
}
|
|
}
|
|
@@ -609,7 +653,7 @@ private:
|
|
|
op_b += GetImmediate19(instr);
|
|
op_b += GetImmediate19(instr);
|
|
|
} else {
|
|
} else {
|
|
|
if (instr.is_b_gpr) {
|
|
if (instr.is_b_gpr) {
|
|
|
- op_b += regs.GetRegister(instr.gpr20);
|
|
|
|
|
|
|
+ op_b += regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
} else {
|
|
} else {
|
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
|
}
|
|
}
|
|
@@ -620,6 +664,11 @@ private:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
switch (opcode->GetId()) {
|
|
switch (opcode->GetId()) {
|
|
|
|
|
+ case OpCode::Id::MOV32_IMM: {
|
|
|
|
|
+ // mov32i doesn't have abs or neg bits.
|
|
|
|
|
+ regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
case OpCode::Id::FMUL_C:
|
|
case OpCode::Id::FMUL_C:
|
|
|
case OpCode::Id::FMUL_R:
|
|
case OpCode::Id::FMUL_R:
|
|
|
case OpCode::Id::FMUL_IMM: {
|
|
case OpCode::Id::FMUL_IMM: {
|
|
@@ -629,8 +678,8 @@ private:
|
|
|
case OpCode::Id::FMUL32_IMM: {
|
|
case OpCode::Id::FMUL32_IMM: {
|
|
|
// fmul32i doesn't have abs or neg bits.
|
|
// fmul32i doesn't have abs or neg bits.
|
|
|
regs.SetRegisterToFloat(
|
|
regs.SetRegisterToFloat(
|
|
|
- instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1,
|
|
|
|
|
- 1);
|
|
|
|
|
|
|
+ instr.gpr0, 0,
|
|
|
|
|
+ regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case OpCode::Id::FADD_C:
|
|
case OpCode::Id::FADD_C:
|
|
@@ -687,29 +736,29 @@ private:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case OpCode::Type::Ffma: {
|
|
case OpCode::Type::Ffma: {
|
|
|
- std::string op_a = regs.GetRegister(instr.gpr8);
|
|
|
|
|
|
|
+ std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
std::string op_b = instr.ffma.negate_b ? "-" : "";
|
|
std::string op_b = instr.ffma.negate_b ? "-" : "";
|
|
|
std::string op_c = instr.ffma.negate_c ? "-" : "";
|
|
std::string op_c = instr.ffma.negate_c ? "-" : "";
|
|
|
|
|
|
|
|
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.uniform, instr.gpr0);
|
|
|
- op_c += regs.GetRegister(instr.gpr39);
|
|
|
|
|
|
|
+ op_c += regs.GetRegisterAsFloat(instr.gpr39);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case OpCode::Id::FFMA_RR: {
|
|
case OpCode::Id::FFMA_RR: {
|
|
|
- op_b += regs.GetRegister(instr.gpr20);
|
|
|
|
|
- op_c += regs.GetRegister(instr.gpr39);
|
|
|
|
|
|
|
+ op_b += regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
+ op_c += regs.GetRegisterAsFloat(instr.gpr39);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case OpCode::Id::FFMA_RC: {
|
|
case OpCode::Id::FFMA_RC: {
|
|
|
- op_b += regs.GetRegister(instr.gpr39);
|
|
|
|
|
|
|
+ op_b += regs.GetRegisterAsFloat(instr.gpr39);
|
|
|
op_c += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
op_c += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case OpCode::Id::FFMA_IMM: {
|
|
case OpCode::Id::FFMA_IMM: {
|
|
|
op_b += GetImmediate19(instr);
|
|
op_b += GetImmediate19(instr);
|
|
|
- op_c += regs.GetRegister(instr.gpr39);
|
|
|
|
|
|
|
+ op_c += regs.GetRegisterAsFloat(instr.gpr39);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
default: {
|
|
default: {
|
|
@@ -721,6 +770,32 @@ private:
|
|
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
|
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
+ case OpCode::Type::Conversion: {
|
|
|
|
|
+ ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
|
|
|
|
|
+ ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
|
|
|
|
|
+ ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
|
|
|
|
|
+ ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
|
|
|
|
|
+
|
|
|
|
|
+ switch (opcode->GetId()) {
|
|
|
|
|
+ case OpCode::Id::I2I_R:
|
|
|
|
|
+ case OpCode::Id::I2F_R: {
|
|
|
|
|
+ std::string op_a =
|
|
|
|
|
+ regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
|
|
|
|
|
+
|
|
|
|
|
+ if (instr.conversion.abs_a) {
|
|
|
|
|
+ op_a = "abs(" + op_a + ')';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ default: {
|
|
|
|
|
+ NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
|
|
|
|
|
+ UNREACHABLE();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
case OpCode::Type::Memory: {
|
|
case OpCode::Type::Memory: {
|
|
|
const Attribute::Index attribute = instr.attribute.fmt20.index;
|
|
const Attribute::Index attribute = instr.attribute.fmt20.index;
|
|
|
|
|
|
|
@@ -739,8 +814,8 @@ private:
|
|
|
}
|
|
}
|
|
|
case OpCode::Id::TEXS: {
|
|
case OpCode::Id::TEXS: {
|
|
|
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
|
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
|
|
- const std::string op_a = regs.GetRegister(instr.gpr8);
|
|
|
|
|
- const std::string op_b = regs.GetRegister(instr.gpr20);
|
|
|
|
|
|
|
+ const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
+ const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
const std::string sampler = GetSampler(instr.sampler);
|
|
const std::string sampler = GetSampler(instr.sampler);
|
|
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
|
// Add an extra scope and declare the texture coords inside to prevent overwriting
|
|
// Add an extra scope and declare the texture coords inside to prevent overwriting
|
|
@@ -765,7 +840,7 @@ private:
|
|
|
}
|
|
}
|
|
|
case OpCode::Type::FloatSetPredicate: {
|
|
case OpCode::Type::FloatSetPredicate: {
|
|
|
std::string op_a = instr.fsetp.neg_a ? "-" : "";
|
|
std::string op_a = instr.fsetp.neg_a ? "-" : "";
|
|
|
- op_a += regs.GetRegister(instr.gpr8);
|
|
|
|
|
|
|
+ op_a += regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
|
|
|
if (instr.fsetp.abs_a) {
|
|
if (instr.fsetp.abs_a) {
|
|
|
op_a = "abs(" + op_a + ')';
|
|
op_a = "abs(" + op_a + ')';
|
|
@@ -781,7 +856,7 @@ private:
|
|
|
op_b += '(' + GetImmediate19(instr) + ')';
|
|
op_b += '(' + GetImmediate19(instr) + ')';
|
|
|
} else {
|
|
} else {
|
|
|
if (instr.is_b_gpr) {
|
|
if (instr.is_b_gpr) {
|
|
|
- op_b += regs.GetRegister(instr.gpr20);
|
|
|
|
|
|
|
+ op_b += regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
} else {
|
|
} else {
|
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
|
}
|
|
}
|
|
@@ -816,7 +891,7 @@ private:
|
|
|
}
|
|
}
|
|
|
case OpCode::Type::FloatSet: {
|
|
case OpCode::Type::FloatSet: {
|
|
|
std::string op_a = instr.fset.neg_a ? "-" : "";
|
|
std::string op_a = instr.fset.neg_a ? "-" : "";
|
|
|
- op_a += regs.GetRegister(instr.gpr8);
|
|
|
|
|
|
|
+ op_a += regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
|
|
|
if (instr.fset.abs_a) {
|
|
if (instr.fset.abs_a) {
|
|
|
op_a = "abs(" + op_a + ')';
|
|
op_a = "abs(" + op_a + ')';
|
|
@@ -832,7 +907,7 @@ private:
|
|
|
op_b += imm;
|
|
op_b += imm;
|
|
|
} else {
|
|
} else {
|
|
|
if (instr.is_b_gpr) {
|
|
if (instr.is_b_gpr) {
|
|
|
- op_b += regs.GetRegister(instr.gpr20);
|
|
|
|
|
|
|
+ op_b += regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
} else {
|
|
} else {
|
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
op_b += regs.GetUniform(instr.uniform, instr.gpr0);
|
|
|
}
|
|
}
|
|
@@ -877,10 +952,10 @@ private:
|
|
|
|
|
|
|
|
// Final color output is currently hardcoded to GPR0-3 for fragment shaders
|
|
// Final color output is currently hardcoded to GPR0-3 for fragment shaders
|
|
|
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
|
|
if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
|
|
|
- shader.AddLine("color.r = " + regs.GetRegister(0) + ';');
|
|
|
|
|
- shader.AddLine("color.g = " + regs.GetRegister(1) + ';');
|
|
|
|
|
- shader.AddLine("color.b = " + regs.GetRegister(2) + ';');
|
|
|
|
|
- shader.AddLine("color.a = " + regs.GetRegister(3) + ';');
|
|
|
|
|
|
|
+ shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';');
|
|
|
|
|
+ shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';');
|
|
|
|
|
+ shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';');
|
|
|
|
|
+ shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
shader.AddLine("return true;");
|
|
shader.AddLine("return true;");
|