gl_shader_decompiler: Make use of fmt with the decompiler

Allows us to avoid even more string churn by allowing the AddLine
function to make use of fmt formatting so the string is formatted all at
once instead of concatenating multiple strings.

This is similar to how yuzu's decompiler works, which I've made function
the same way in the past.
This commit is contained in:
Lioncash 2020-05-04 22:40:31 -04:00
parent db5b8b9c88
commit 016d43df98
1 changed files with 125 additions and 102 deletions

View File

@ -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);
} }