mirror of
https://github.com/citra-emu/citra-nightly.git
synced 2024-12-25 15:05:41 +00:00
Merge pull request #5262 from lioncash/fmt
gl_shader_decompiler: Make use of fmt with the decompiler
This commit is contained in:
commit
e959d44f00
|
@ -8,6 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <nihstro/shader_bytecode.h>
|
#include <nihstro/shader_bytecode.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -196,12 +197,19 @@ private:
|
||||||
|
|
||||||
class ShaderWriter {
|
class ShaderWriter {
|
||||||
public:
|
public:
|
||||||
void AddLine(std::string_view text) {
|
// Forwards all arguments directly to libfmt.
|
||||||
|
// Note that all formatting requirements for fmt must be
|
||||||
|
// obeyed when using this function. (e.g. {{ must be used
|
||||||
|
// printing the character '{' is desirable. Ditto for }} and '}',
|
||||||
|
// etc).
|
||||||
|
template <typename... Args>
|
||||||
|
void AddLine(std::string_view text, Args&&... args) {
|
||||||
|
AddExpression(fmt::format(text, std::forward<Args>(args)...));
|
||||||
|
AddNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddNewLine() {
|
||||||
DEBUG_ASSERT(scope >= 0);
|
DEBUG_ASSERT(scope >= 0);
|
||||||
if (!text.empty()) {
|
|
||||||
shader_source.append(static_cast<std::size_t>(scope) * 4, ' ');
|
|
||||||
}
|
|
||||||
shader_source += text;
|
|
||||||
shader_source += '\n';
|
shader_source += '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +220,13 @@ public:
|
||||||
int scope = 0;
|
int scope = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void AddExpression(std::string_view text) {
|
||||||
|
if (!text.empty()) {
|
||||||
|
shader_source.append(static_cast<std::size_t>(scope) * 4, ' ');
|
||||||
|
}
|
||||||
|
shader_source += text;
|
||||||
|
}
|
||||||
|
|
||||||
std::string shader_source;
|
std::string shader_source;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,16 +237,16 @@ std::string GetSelectorSrc(const SwizzlePattern& pattern) {
|
||||||
for (std::size_t i = 0; i < 4; ++i) {
|
for (std::size_t i = 0; i < 4; ++i) {
|
||||||
switch ((pattern.*getter)(i)) {
|
switch ((pattern.*getter)(i)) {
|
||||||
case SwizzlePattern::Selector::x:
|
case SwizzlePattern::Selector::x:
|
||||||
out += "x";
|
out += 'x';
|
||||||
break;
|
break;
|
||||||
case SwizzlePattern::Selector::y:
|
case SwizzlePattern::Selector::y:
|
||||||
out += "y";
|
out += 'y';
|
||||||
break;
|
break;
|
||||||
case SwizzlePattern::Selector::z:
|
case SwizzlePattern::Selector::z:
|
||||||
out += "z";
|
out += 'z';
|
||||||
break;
|
break;
|
||||||
case SwizzlePattern::Selector::w:
|
case SwizzlePattern::Selector::w:
|
||||||
out += "w";
|
out += 'w';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -275,28 +290,28 @@ private:
|
||||||
static std::string EvaluateCondition(Instruction::FlowControlType flow_control) {
|
static std::string EvaluateCondition(Instruction::FlowControlType flow_control) {
|
||||||
using Op = Instruction::FlowControlType::Op;
|
using Op = Instruction::FlowControlType::Op;
|
||||||
|
|
||||||
std::string result_x =
|
const std::string_view result_x =
|
||||||
flow_control.refx.Value() ? "conditional_code.x" : "!conditional_code.x";
|
flow_control.refx.Value() ? "conditional_code.x" : "!conditional_code.x";
|
||||||
std::string result_y =
|
const std::string_view result_y =
|
||||||
flow_control.refy.Value() ? "conditional_code.y" : "!conditional_code.y";
|
flow_control.refy.Value() ? "conditional_code.y" : "!conditional_code.y";
|
||||||
|
|
||||||
switch (flow_control.op) {
|
switch (flow_control.op) {
|
||||||
case Op::JustX:
|
case Op::JustX:
|
||||||
return result_x;
|
return std::string(result_x);
|
||||||
case Op::JustY:
|
case Op::JustY:
|
||||||
return result_y;
|
return std::string(result_y);
|
||||||
case Op::Or:
|
case Op::Or:
|
||||||
case Op::And: {
|
case Op::And: {
|
||||||
std::string and_or = flow_control.op == Op::Or ? "any" : "all";
|
const std::string_view and_or = flow_control.op == Op::Or ? "any" : "all";
|
||||||
std::string bvec;
|
std::string bvec;
|
||||||
if (flow_control.refx.Value() && flow_control.refy.Value()) {
|
if (flow_control.refx.Value() && flow_control.refy.Value()) {
|
||||||
bvec = "conditional_code";
|
bvec = "conditional_code";
|
||||||
} else if (!flow_control.refx.Value() && !flow_control.refy.Value()) {
|
} else if (!flow_control.refx.Value() && !flow_control.refy.Value()) {
|
||||||
bvec = "not(conditional_code)";
|
bvec = "not(conditional_code)";
|
||||||
} else {
|
} else {
|
||||||
bvec = "bvec2(" + result_x + ", " + result_y + ")";
|
bvec = fmt::format("bvec2({}, {})", result_x, result_y);
|
||||||
}
|
}
|
||||||
return and_or + "(" + bvec + ")";
|
return fmt::format("{}({})", and_or, bvec);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -307,20 +322,19 @@ private:
|
||||||
/// Generates code representing a source register.
|
/// Generates code representing a source register.
|
||||||
std::string GetSourceRegister(const SourceRegister& source_reg,
|
std::string GetSourceRegister(const SourceRegister& source_reg,
|
||||||
u32 address_register_index) const {
|
u32 address_register_index) const {
|
||||||
u32 index = static_cast<u32>(source_reg.GetIndex());
|
const u32 index = static_cast<u32>(source_reg.GetIndex());
|
||||||
std::string index_str = std::to_string(index);
|
|
||||||
|
|
||||||
switch (source_reg.GetRegisterType()) {
|
switch (source_reg.GetRegisterType()) {
|
||||||
case RegisterType::Input:
|
case RegisterType::Input:
|
||||||
return inputreg_getter(index);
|
return inputreg_getter(index);
|
||||||
case RegisterType::Temporary:
|
case RegisterType::Temporary:
|
||||||
return "reg_tmp" + index_str;
|
return fmt::format("reg_tmp{}", index);
|
||||||
case RegisterType::FloatUniform:
|
case RegisterType::FloatUniform:
|
||||||
if (address_register_index != 0) {
|
if (address_register_index != 0) {
|
||||||
index_str +=
|
return fmt::format("uniforms.f[{} + address_registers.{}]", index,
|
||||||
std::string(" + address_registers.") + "xyz"[address_register_index - 1];
|
"xyz"[address_register_index - 1]);
|
||||||
}
|
}
|
||||||
return "uniforms.f[" + index_str + "]";
|
return fmt::format("uniforms.f[{}]", index);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return "";
|
return "";
|
||||||
|
@ -329,13 +343,13 @@ private:
|
||||||
|
|
||||||
/// Generates code representing a destination register.
|
/// Generates code representing a destination register.
|
||||||
std::string GetDestRegister(const DestRegister& dest_reg) const {
|
std::string GetDestRegister(const DestRegister& dest_reg) const {
|
||||||
u32 index = static_cast<u32>(dest_reg.GetIndex());
|
const u32 index = static_cast<u32>(dest_reg.GetIndex());
|
||||||
|
|
||||||
switch (dest_reg.GetRegisterType()) {
|
switch (dest_reg.GetRegisterType()) {
|
||||||
case RegisterType::Output:
|
case RegisterType::Output:
|
||||||
return outputreg_getter(index);
|
return outputreg_getter(index);
|
||||||
case RegisterType::Temporary:
|
case RegisterType::Temporary:
|
||||||
return "reg_tmp" + std::to_string(index);
|
return fmt::format("reg_tmp{}", index);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return "";
|
return "";
|
||||||
|
@ -344,7 +358,7 @@ private:
|
||||||
|
|
||||||
/// Generates code representing a bool uniform
|
/// Generates code representing a bool uniform
|
||||||
std::string GetUniformBool(u32 index) const {
|
std::string GetUniformBool(u32 index) const {
|
||||||
return "uniforms.b[" + std::to_string(index) + "]";
|
return fmt::format("uniforms.b[{}]", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -353,12 +367,12 @@ private:
|
||||||
*/
|
*/
|
||||||
void CallSubroutine(const Subroutine& subroutine) {
|
void CallSubroutine(const Subroutine& subroutine) {
|
||||||
if (subroutine.exit_method == ExitMethod::AlwaysEnd) {
|
if (subroutine.exit_method == ExitMethod::AlwaysEnd) {
|
||||||
shader.AddLine(subroutine.GetName() + "();");
|
shader.AddLine("{}();", subroutine.GetName());
|
||||||
shader.AddLine("return true;");
|
shader.AddLine("return true;");
|
||||||
} else if (subroutine.exit_method == ExitMethod::Conditional) {
|
} else if (subroutine.exit_method == ExitMethod::Conditional) {
|
||||||
shader.AddLine("if (" + subroutine.GetName() + "()) { return true; }");
|
shader.AddLine("if ({}()) {{ return true; }}", subroutine.GetName());
|
||||||
} else {
|
} else {
|
||||||
shader.AddLine(subroutine.GetName() + "();");
|
shader.AddLine("{}();", subroutine.GetName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +384,7 @@ private:
|
||||||
* @param dest_num_components number of components of the destination register.
|
* @param dest_num_components number of components of the destination register.
|
||||||
* @param value_num_components number of components of the value to assign.
|
* @param value_num_components number of components of the value to assign.
|
||||||
*/
|
*/
|
||||||
void SetDest(const SwizzlePattern& swizzle, const std::string& reg, const std::string& value,
|
void SetDest(const SwizzlePattern& swizzle, std::string_view reg, std::string_view value,
|
||||||
u32 dest_num_components, u32 value_num_components) {
|
u32 dest_num_components, u32 value_num_components) {
|
||||||
u32 dest_mask_num_components = 0;
|
u32 dest_mask_num_components = 0;
|
||||||
std::string dest_mask_swizzle = ".";
|
std::string dest_mask_swizzle = ".";
|
||||||
|
@ -387,18 +401,19 @@ private:
|
||||||
}
|
}
|
||||||
DEBUG_ASSERT(value_num_components >= dest_num_components || value_num_components == 1);
|
DEBUG_ASSERT(value_num_components >= dest_num_components || value_num_components == 1);
|
||||||
|
|
||||||
std::string dest = reg + (dest_num_components != 1 ? dest_mask_swizzle : "");
|
const std::string dest =
|
||||||
|
fmt::format("{}{}", reg, dest_num_components != 1 ? dest_mask_swizzle : "");
|
||||||
|
|
||||||
std::string src = value;
|
std::string src{value};
|
||||||
if (value_num_components == 1) {
|
if (value_num_components == 1) {
|
||||||
if (dest_mask_num_components != 1) {
|
if (dest_mask_num_components != 1) {
|
||||||
src = "vec" + std::to_string(dest_mask_num_components) + "(" + value + ")";
|
src = fmt::format("vec{}({})", dest_mask_num_components, value);
|
||||||
}
|
}
|
||||||
} else if (value_num_components != dest_mask_num_components) {
|
} else if (value_num_components != dest_mask_num_components) {
|
||||||
src = "(" + value + ")" + dest_mask_swizzle;
|
src = fmt::format("({}){}", value, dest_mask_swizzle);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.AddLine(dest + " = " + src + ";");
|
shader.AddLine("{} = {};", dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -417,7 +432,7 @@ private:
|
||||||
: instr.common.operand_desc_id;
|
: instr.common.operand_desc_id;
|
||||||
const SwizzlePattern swizzle = {swizzle_data[swizzle_offset]};
|
const SwizzlePattern swizzle = {swizzle_data[swizzle_offset]};
|
||||||
|
|
||||||
shader.AddLine("// " + std::to_string(offset) + ": " + instr.opcode.Value().GetInfo().name);
|
shader.AddLine("// {}: {}", offset, instr.opcode.Value().GetInfo().name);
|
||||||
|
|
||||||
switch (instr.opcode.Value().GetInfo().type) {
|
switch (instr.opcode.Value().GetInfo().type) {
|
||||||
case OpCode::Type::Arithmetic: {
|
case OpCode::Type::Arithmetic: {
|
||||||
|
@ -438,31 +453,32 @@ private:
|
||||||
|
|
||||||
switch (instr.opcode.Value().EffectiveOpCode()) {
|
switch (instr.opcode.Value().EffectiveOpCode()) {
|
||||||
case OpCode::Id::ADD: {
|
case OpCode::Id::ADD: {
|
||||||
SetDest(swizzle, dest_reg, src1 + " + " + src2, 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("{} + {}", src1, src2), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::MUL: {
|
case OpCode::Id::MUL: {
|
||||||
if (sanitize_mul) {
|
if (sanitize_mul) {
|
||||||
SetDest(swizzle, dest_reg, "sanitize_mul(" + src1 + ", " + src2 + ")", 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("sanitize_mul({}, {})", src1, src2), 4,
|
||||||
|
4);
|
||||||
} else {
|
} else {
|
||||||
SetDest(swizzle, dest_reg, src1 + " * " + src2, 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("{} * {}", src1, src2), 4, 4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::FLR: {
|
case OpCode::Id::FLR: {
|
||||||
SetDest(swizzle, dest_reg, "floor(" + src1 + ")", 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("floor({})", src1), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::MAX: {
|
case OpCode::Id::MAX: {
|
||||||
SetDest(swizzle, dest_reg, "max(" + src1 + ", " + src2 + ")", 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("max({}, {})", src1, src2), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::MIN: {
|
case OpCode::Id::MIN: {
|
||||||
SetDest(swizzle, dest_reg, "min(" + src1 + ", " + src2 + ")", 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("min({}, {})", src1, src2), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,18 +490,20 @@ private:
|
||||||
std::string dot;
|
std::string dot;
|
||||||
if (opcode == OpCode::Id::DP3) {
|
if (opcode == OpCode::Id::DP3) {
|
||||||
if (sanitize_mul) {
|
if (sanitize_mul) {
|
||||||
dot = "dot(vec3(sanitize_mul(" + src1 + ", " + src2 + ")), vec3(1.0))";
|
dot = fmt::format("dot(vec3(sanitize_mul({}, {})), vec3(1.0))", src1, src2);
|
||||||
} else {
|
} else {
|
||||||
dot = "dot(vec3(" + src1 + "), vec3(" + src2 + "))";
|
dot = fmt::format("dot(vec3({}), vec3({}))", src1, src2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string src1_ = (opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI)
|
|
||||||
? "vec4(" + src1 + ".xyz, 1.0)"
|
|
||||||
: src1;
|
|
||||||
if (sanitize_mul) {
|
if (sanitize_mul) {
|
||||||
dot = "dot(sanitize_mul(" + src1_ + ", " + src2 + "), vec4(1.0))";
|
const std::string src1_ =
|
||||||
|
(opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI)
|
||||||
|
? fmt::format("vec4({}.xyz, 1.0)", src1)
|
||||||
|
: std::move(src1);
|
||||||
|
|
||||||
|
dot = fmt::format("dot(sanitize_mul({}, {}), vec4(1.0))", src1_, src2);
|
||||||
} else {
|
} else {
|
||||||
dot = "dot(" + src1 + ", " + src2 + ")";
|
dot = fmt::format("dot({}, {})", src1, src2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,17 +512,17 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::RCP: {
|
case OpCode::Id::RCP: {
|
||||||
SetDest(swizzle, dest_reg, "(1.0 / " + src1 + ".x)", 4, 1);
|
SetDest(swizzle, dest_reg, fmt::format("(1.0 / {}.x)", src1), 4, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::RSQ: {
|
case OpCode::Id::RSQ: {
|
||||||
SetDest(swizzle, dest_reg, "inversesqrt(" + src1 + ".x)", 4, 1);
|
SetDest(swizzle, dest_reg, fmt::format("inversesqrt({}.x)", src1), 4, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::MOVA: {
|
case OpCode::Id::MOVA: {
|
||||||
SetDest(swizzle, "address_registers", "ivec2(" + src1 + ")", 2, 2);
|
SetDest(swizzle, "address_registers", fmt::format("ivec2({})", src1), 2, 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,26 +533,27 @@ private:
|
||||||
|
|
||||||
case OpCode::Id::SGE:
|
case OpCode::Id::SGE:
|
||||||
case OpCode::Id::SGEI: {
|
case OpCode::Id::SGEI: {
|
||||||
SetDest(swizzle, dest_reg, "vec4(greaterThanEqual(" + src1 + "," + src2 + "))", 4,
|
SetDest(swizzle, dest_reg,
|
||||||
4);
|
fmt::format("vec4(greaterThanEqual({}, {}))", src1, src2), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::SLT:
|
case OpCode::Id::SLT:
|
||||||
case OpCode::Id::SLTI: {
|
case OpCode::Id::SLTI: {
|
||||||
SetDest(swizzle, dest_reg, "vec4(lessThan(" + src1 + "," + src2 + "))", 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("vec4(lessThan({}, {}))", src1, src2), 4, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::CMP: {
|
case OpCode::Id::CMP: {
|
||||||
using CompareOp = Instruction::Common::CompareOpType::Op;
|
using CompareOp = Instruction::Common::CompareOpType::Op;
|
||||||
const std::map<CompareOp, std::pair<std::string, std::string>> cmp_ops{
|
const std::map<CompareOp, std::pair<std::string_view, std::string_view>> cmp_ops{
|
||||||
{CompareOp::Equal, {"==", "equal"}},
|
{CompareOp::Equal, {"==", "equal"}},
|
||||||
{CompareOp::NotEqual, {"!=", "notEqual"}},
|
{CompareOp::NotEqual, {"!=", "notEqual"}},
|
||||||
{CompareOp::LessThan, {"<", "lessThan"}},
|
{CompareOp::LessThan, {"<", "lessThan"}},
|
||||||
{CompareOp::LessEqual, {"<=", "lessThanEqual"}},
|
{CompareOp::LessEqual, {"<=", "lessThanEqual"}},
|
||||||
{CompareOp::GreaterThan, {">", "greaterThan"}},
|
{CompareOp::GreaterThan, {">", "greaterThan"}},
|
||||||
{CompareOp::GreaterEqual, {">=", "greaterThanEqual"}}};
|
{CompareOp::GreaterEqual, {">=", "greaterThanEqual"}},
|
||||||
|
};
|
||||||
|
|
||||||
const CompareOp op_x = instr.common.compare_op.x.Value();
|
const CompareOp op_x = instr.common.compare_op.x.Value();
|
||||||
const CompareOp op_y = instr.common.compare_op.y.Value();
|
const CompareOp op_y = instr.common.compare_op.y.Value();
|
||||||
|
@ -544,24 +563,24 @@ private:
|
||||||
} else if (cmp_ops.find(op_y) == cmp_ops.end()) {
|
} else if (cmp_ops.find(op_y) == cmp_ops.end()) {
|
||||||
LOG_ERROR(HW_GPU, "Unknown compare mode {:x}", static_cast<int>(op_y));
|
LOG_ERROR(HW_GPU, "Unknown compare mode {:x}", static_cast<int>(op_y));
|
||||||
} else if (op_x != op_y) {
|
} else if (op_x != op_y) {
|
||||||
shader.AddLine("conditional_code.x = " + src1 + ".x " +
|
shader.AddLine("conditional_code.x = {}.x {} {}.x;", src1,
|
||||||
cmp_ops.find(op_x)->second.first + " " + src2 + ".x;");
|
cmp_ops.find(op_x)->second.first, src2);
|
||||||
shader.AddLine("conditional_code.y = " + src1 + ".y " +
|
shader.AddLine("conditional_code.y = {}.y {} {}.y;", src1,
|
||||||
cmp_ops.find(op_y)->second.first + " " + src2 + ".y;");
|
cmp_ops.find(op_y)->second.first, src2);
|
||||||
} else {
|
} else {
|
||||||
shader.AddLine("conditional_code = " + cmp_ops.find(op_x)->second.second +
|
shader.AddLine("conditional_code = {}(vec2({}), vec2({}));",
|
||||||
"(vec2(" + src1 + "), vec2(" + src2 + "));");
|
cmp_ops.find(op_x)->second.second, src1, src2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::EX2: {
|
case OpCode::Id::EX2: {
|
||||||
SetDest(swizzle, dest_reg, "exp2(" + src1 + ".x)", 4, 1);
|
SetDest(swizzle, dest_reg, fmt::format("exp2({}.x)", src1), 4, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::LG2: {
|
case OpCode::Id::LG2: {
|
||||||
SetDest(swizzle, dest_reg, "log2(" + src1 + ".x)", 4, 1);
|
SetDest(swizzle, dest_reg, fmt::format("log2({}.x)", src1), 4, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,10 +623,10 @@ private:
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
if (sanitize_mul) {
|
if (sanitize_mul) {
|
||||||
SetDest(swizzle, dest_reg, "sanitize_mul(" + src1 + ", " + src2 + ") + " + src3,
|
SetDest(swizzle, dest_reg,
|
||||||
4, 4);
|
fmt::format("sanitize_mul({}, {}) + {}", src1, src2, src3), 4, 4);
|
||||||
} else {
|
} else {
|
||||||
SetDest(swizzle, dest_reg, src1 + " * " + src2 + " + " + src3, 4, 4);
|
SetDest(swizzle, dest_reg, fmt::format("{} * {} + {}", src1, src2, src3), 4, 4);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(HW_GPU, "Unhandled multiply-add instruction: 0x{:02x} ({}): 0x{:08x}",
|
LOG_ERROR(HW_GPU, "Unhandled multiply-add instruction: 0x{:02x} ({}): 0x{:08x}",
|
||||||
|
@ -637,13 +656,13 @@ private:
|
||||||
GetUniformBool(instr.flow_control.bool_uniform_id);
|
GetUniformBool(instr.flow_control.bool_uniform_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.AddLine("if (" + condition + ") {");
|
shader.AddLine("if ({}) {{", condition);
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
shader.AddLine("{ jmp_to = " + std::to_string(instr.flow_control.dest_offset) +
|
shader.AddLine("{{ jmp_to = {}u; break; }}",
|
||||||
"u; break; }");
|
instr.flow_control.dest_offset.Value());
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,7 +676,11 @@ private:
|
||||||
condition = GetUniformBool(instr.flow_control.bool_uniform_id);
|
condition = GetUniformBool(instr.flow_control.bool_uniform_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.AddLine(condition.empty() ? "{" : "if (" + condition + ") {");
|
if (condition.empty()) {
|
||||||
|
shader.AddLine("{{");
|
||||||
|
} else {
|
||||||
|
shader.AddLine("if ({}) {{", condition);
|
||||||
|
}
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
auto& call_sub = GetSubroutine(instr.flow_control.dest_offset,
|
auto& call_sub = GetSubroutine(instr.flow_control.dest_offset,
|
||||||
|
@ -671,7 +694,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,7 +716,7 @@ private:
|
||||||
const u32 endif_offset =
|
const u32 endif_offset =
|
||||||
instr.flow_control.dest_offset + instr.flow_control.num_instructions;
|
instr.flow_control.dest_offset + instr.flow_control.num_instructions;
|
||||||
|
|
||||||
shader.AddLine("if (" + condition + ") {");
|
shader.AddLine("if ({}) {{", condition);
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
auto& if_sub = GetSubroutine(if_offset, else_offset);
|
auto& if_sub = GetSubroutine(if_offset, else_offset);
|
||||||
|
@ -702,7 +725,7 @@ private:
|
||||||
|
|
||||||
if (instr.flow_control.num_instructions != 0) {
|
if (instr.flow_control.num_instructions != 0) {
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("} else {");
|
shader.AddLine("}} else {{");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
auto& else_sub = GetSubroutine(else_offset, endif_offset);
|
auto& else_sub = GetSubroutine(else_offset, endif_offset);
|
||||||
|
@ -716,20 +739,20 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::LOOP: {
|
case OpCode::Id::LOOP: {
|
||||||
std::string int_uniform =
|
const std::string int_uniform =
|
||||||
"uniforms.i[" + std::to_string(instr.flow_control.int_uniform_id) + "]";
|
fmt::format("uniforms.i[{}]", instr.flow_control.int_uniform_id.Value());
|
||||||
|
|
||||||
shader.AddLine("address_registers.z = int(" + int_uniform + ".y);");
|
shader.AddLine("address_registers.z = int({}.y);", int_uniform);
|
||||||
|
|
||||||
std::string loop_var = "loop" + std::to_string(offset);
|
const std::string loop_var = fmt::format("loop{}", offset);
|
||||||
shader.AddLine("for (uint " + loop_var + " = 0u; " + loop_var +
|
shader.AddLine(
|
||||||
" <= " + int_uniform + ".x; address_registers.z += int(" +
|
"for (uint {} = 0u; {} <= {}.x; address_registers.z += int({}.z), ++{}) {{",
|
||||||
int_uniform + ".z), ++" + loop_var + ") {");
|
loop_var, loop_var, int_uniform, int_uniform, loop_var);
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
auto& loop_sub = GetSubroutine(offset + 1, instr.flow_control.dest_offset + 1);
|
auto& loop_sub = GetSubroutine(offset + 1, instr.flow_control.dest_offset + 1);
|
||||||
|
@ -737,7 +760,7 @@ private:
|
||||||
offset = instr.flow_control.dest_offset;
|
offset = instr.flow_control.dest_offset;
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
|
|
||||||
if (loop_sub.exit_method == ExitMethod::AlwaysEnd) {
|
if (loop_sub.exit_method == ExitMethod::AlwaysEnd) {
|
||||||
offset = PROGRAM_END - 1;
|
offset = PROGRAM_END - 1;
|
||||||
|
@ -782,41 +805,41 @@ private:
|
||||||
|
|
||||||
void Generate() {
|
void Generate() {
|
||||||
if (sanitize_mul) {
|
if (sanitize_mul) {
|
||||||
shader.AddLine("vec4 sanitize_mul(vec4 lhs, vec4 rhs) {");
|
shader.AddLine("vec4 sanitize_mul(vec4 lhs, vec4 rhs) {{");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
shader.AddLine("vec4 product = lhs * rhs;");
|
shader.AddLine("vec4 product = lhs * rhs;");
|
||||||
shader.AddLine("return mix(product, mix(mix(vec4(0.0), product, isnan(rhs)), product, "
|
shader.AddLine("return mix(product, mix(mix(vec4(0.0), product, isnan(rhs)), product, "
|
||||||
"isnan(lhs)), isnan(product));");
|
"isnan(lhs)), isnan(product));");
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}\n");
|
shader.AddLine("}}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add declarations for registers
|
// Add declarations for registers
|
||||||
shader.AddLine("bvec2 conditional_code = bvec2(false);");
|
shader.AddLine("bvec2 conditional_code = bvec2(false);");
|
||||||
shader.AddLine("ivec3 address_registers = ivec3(0);");
|
shader.AddLine("ivec3 address_registers = ivec3(0);");
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
shader.AddLine("vec4 reg_tmp" + std::to_string(i) + " = vec4(0.0, 0.0, 0.0, 1.0);");
|
shader.AddLine("vec4 reg_tmp{} = vec4(0.0, 0.0, 0.0, 1.0);", i);
|
||||||
}
|
}
|
||||||
shader.AddLine("");
|
shader.AddNewLine();
|
||||||
|
|
||||||
// Add declarations for all subroutines
|
// Add declarations for all subroutines
|
||||||
for (const auto& subroutine : subroutines) {
|
for (const auto& subroutine : subroutines) {
|
||||||
shader.AddLine("bool " + subroutine.GetName() + "();");
|
shader.AddLine("bool {}();", subroutine.GetName());
|
||||||
}
|
}
|
||||||
shader.AddLine("");
|
shader.AddNewLine();
|
||||||
|
|
||||||
// Add the main entry point
|
// Add the main entry point
|
||||||
shader.AddLine("bool exec_shader() {");
|
shader.AddLine("bool exec_shader() {{");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
CallSubroutine(GetSubroutine(main_offset, PROGRAM_END));
|
CallSubroutine(GetSubroutine(main_offset, PROGRAM_END));
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}\n");
|
shader.AddLine("}}\n");
|
||||||
|
|
||||||
// Add definitions for all subroutines
|
// Add definitions for all subroutines
|
||||||
for (const auto& subroutine : subroutines) {
|
for (const auto& subroutine : subroutines) {
|
||||||
std::set<u32> labels = subroutine.labels;
|
std::set<u32> labels = subroutine.labels;
|
||||||
|
|
||||||
shader.AddLine("bool " + subroutine.GetName() + "() {");
|
shader.AddLine("bool {}() {{", subroutine.GetName());
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
if (labels.empty()) {
|
if (labels.empty()) {
|
||||||
|
@ -825,14 +848,14 @@ private:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
labels.insert(subroutine.begin);
|
labels.insert(subroutine.begin);
|
||||||
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
|
shader.AddLine("uint jmp_to = {}u;", subroutine.begin);
|
||||||
shader.AddLine("while (true) {");
|
shader.AddLine("while (true) {{");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
shader.AddLine("switch (jmp_to) {");
|
shader.AddLine("switch (jmp_to) {{");
|
||||||
|
|
||||||
for (auto label : labels) {
|
for (auto label : labels) {
|
||||||
shader.AddLine("case " + std::to_string(label) + "u: {");
|
shader.AddLine("case {}u: {{", label);
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
auto next_it = labels.lower_bound(label + 1);
|
auto next_it = labels.lower_bound(label + 1);
|
||||||
|
@ -841,25 +864,25 @@ private:
|
||||||
u32 compile_end = CompileRange(label, next_label);
|
u32 compile_end = CompileRange(label, next_label);
|
||||||
if (compile_end > next_label && compile_end != PROGRAM_END) {
|
if (compile_end > next_label && compile_end != PROGRAM_END) {
|
||||||
// This happens only when there is a label inside a IF/LOOP block
|
// This happens only when there is a label inside a IF/LOOP block
|
||||||
shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }");
|
shader.AddLine("{{ jmp_to = {}u; break; }}", compile_end);
|
||||||
labels.emplace(compile_end);
|
labels.emplace(compile_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.AddLine("default: return false;");
|
shader.AddLine("default: return false;");
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}");
|
shader.AddLine("}}");
|
||||||
|
|
||||||
shader.AddLine("return false;");
|
shader.AddLine("return false;");
|
||||||
}
|
}
|
||||||
|
|
||||||
--shader.scope;
|
--shader.scope;
|
||||||
shader.AddLine("}\n");
|
shader.AddLine("}}\n");
|
||||||
|
|
||||||
DEBUG_ASSERT(shader.scope == 0);
|
DEBUG_ASSERT(shader.scope == 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue