From 1269a0cf8b3844c1a9bb06c843a7698b0a9643d5 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 30 May 2021 17:27:00 -0400 Subject: glsl: Rework variable allocator to allow for variable reuse --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 290 +++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 src/shader_recompiler/backend/glsl/var_alloc.cpp (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp new file mode 100644 index 000000000..8c6944f07 --- /dev/null +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -0,0 +1,290 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include + +#include "shader_recompiler/backend/glsl/var_alloc.h" +#include "shader_recompiler/exception.h" +#include "shader_recompiler/frontend/ir/value.h" + +namespace Shader::Backend::GLSL { +namespace { +std::string TypePrefix(GlslVarType type) { + switch (type) { + case GlslVarType::U1: + return "b_"; + case GlslVarType::F16x2: + return "f16x2_"; + case GlslVarType::U32: + return "u_"; + case GlslVarType::S32: + return "s_"; + case GlslVarType::F32: + return "f_"; + case GlslVarType::S64: + return "s64_"; + case GlslVarType::U64: + return "u64_"; + case GlslVarType::F64: + return "d_"; + case GlslVarType::U32x2: + return "u2_"; + case GlslVarType::F32x2: + return "f2_"; + case GlslVarType::U32x3: + return "u3_"; + case GlslVarType::F32x3: + return "f3_"; + case GlslVarType::U32x4: + return "u4_"; + case GlslVarType::F32x4: + return "f4_"; + case GlslVarType::Void: + return ""; + default: + throw NotImplementedException("Type {}", type); + } +} + +std::string FormatFloat(std::string_view value, IR::Type type) { + // TODO: Confirm FP64 nan/inf + if (type == IR::Type::F32) { + if (value == "nan") { + return "uintBitsToFloat(0x7fc00000)"; + } + if (value == "inf") { + return "uintBitsToFloat(0x7f800000)"; + } + if (value == "-inf") { + return "uintBitsToFloat(0xff800000)"; + } + } + if (value.find_first_of('e') != std::string_view::npos) { + // scientific notation + const auto cast{type == IR::Type::F32 ? "float" : "double"}; + return fmt::format("{}({})", cast, value); + } + const bool needs_dot{value.find_first_of('.') == std::string_view::npos}; + const bool needs_suffix{!value.ends_with('f')}; + const auto suffix{type == IR::Type::F32 ? "f" : "lf"}; + return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : ""); +} + +std::string MakeImm(const IR::Value& value) { + switch (value.Type()) { + case IR::Type::U1: + return fmt::format("{}", value.U1() ? "true" : "false"); + case IR::Type::U32: + return fmt::format("{}u", value.U32()); + case IR::Type::F32: + return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32); + case IR::Type::U64: + return fmt::format("{}ul", value.U64()); + case IR::Type::F64: + return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64); + case IR::Type::Void: + return ""; + default: + throw NotImplementedException("Immediate type {}", value.Type()); + } +} +} // Anonymous namespace + +std::string VarAlloc::Representation(u32 index, GlslVarType type) const { + const auto prefix{TypePrefix(type)}; + return fmt::format("{}{}", prefix, index); +} + +std::string VarAlloc::Representation(Id id) const { + return Representation(id.index, id.type); +} + +std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { + if (inst.HasUses()) { + inst.SetDefinition(Alloc(type)); + return Representation(inst.Definition()); + } else { + Id id{}; + id.type.Assign(type); + // id.is_null.Assign(1); + GetUseTracker(type).uses_temp = true; + inst.SetDefinition(id); + } + return Representation(inst.Definition()); +} + +std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) { + return Define(inst, RegType(type)); +} + +std::string VarAlloc::Consume(const IR::Value& value) { + return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); +} + +std::string VarAlloc::ConsumeInst(IR::Inst& inst) { + inst.DestructiveRemoveUsage(); + if (!inst.HasUses()) { + Free(inst.Definition()); + } + return Representation(inst.Definition()); +} + +std::string VarAlloc::GetGlslType(IR::Type type) const { + return GetGlslType(RegType(type)); +} + +Id VarAlloc::Alloc(GlslVarType type) { + auto& use_tracker{GetUseTracker(type)}; + if (use_tracker.num_used < NUM_VARS) { + for (size_t var = 1; var < NUM_VARS; ++var) { + if (use_tracker.var_use[var]) { + continue; + } + use_tracker.num_used = std::max(use_tracker.num_used, var + 1); + use_tracker.var_use[var] = true; + Id ret{}; + ret.is_valid.Assign(1); + ret.type.Assign(type); + ret.index.Assign(static_cast(var)); + return ret; + } + } + throw NotImplementedException("Variable spilling"); +} + +void VarAlloc::Free(Id id) { + if (id.is_valid == 0) { + // throw LogicError("Freeing invalid variable"); + return; + } + auto& use_tracker{GetUseTracker(id.type)}; + use_tracker.var_use[id.index] = false; +} + +GlslVarType VarAlloc::RegType(IR::Type type) const { + switch (type) { + case IR::Type::U1: + return GlslVarType::U1; + case IR::Type::U32: + return GlslVarType::U32; + case IR::Type::F32: + return GlslVarType::F32; + case IR::Type::U64: + return GlslVarType::U64; + case IR::Type::F64: + return GlslVarType::F64; + default: + throw NotImplementedException("IR type {}", type); + } +} + +std::string VarAlloc::GetGlslType(GlslVarType type) const { + switch (type) { + case GlslVarType::U1: + return "bool "; + case GlslVarType::F16x2: + return "f16vec2 "; + case GlslVarType::U32: + return "uint "; + case GlslVarType::S32: + return "int "; + case GlslVarType::F32: + return "float "; + case GlslVarType::S64: + return "int64_t "; + case GlslVarType::U64: + return "uint64_t "; + case GlslVarType::F64: + return "double "; + case GlslVarType::U32x2: + return "uvec2 "; + case GlslVarType::F32x2: + return "vec2 "; + case GlslVarType::U32x3: + return "uvec3 "; + case GlslVarType::F32x3: + return "vec3 "; + case GlslVarType::U32x4: + return "uvec4 "; + case GlslVarType::F32x4: + return "vec4 "; + case GlslVarType::Void: + return ""; + default: + throw NotImplementedException("Type {}", type); + } +} + +VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { + switch (type) { + case GlslVarType::U1: + return var_bool; + case GlslVarType::U32: + return var_u32; + case GlslVarType::S32: + return var_s32; + case GlslVarType::F32: + return var_f32; + case GlslVarType::S64: + return var_s64; + case GlslVarType::U64: + return var_u64; + case GlslVarType::F64: + return var_f64; + case GlslVarType::U32x2: + return var_u32x2; + case GlslVarType::F32x2: + return var_f32x2; + case GlslVarType::U32x3: + return var_u32x3; + case GlslVarType::F32x3: + return var_f32x3; + case GlslVarType::U32x4: + return var_u32x4; + case GlslVarType::F32x4: + return var_f32x4; + default: + throw NotImplementedException("Type {}", type); + } +} + +const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const { + switch (type) { + case GlslVarType::U1: + return var_bool; + case GlslVarType::F16x2: + return var_f16x2; + case GlslVarType::U32: + return var_u32; + case GlslVarType::S32: + return var_s32; + case GlslVarType::F32: + return var_f32; + case GlslVarType::S64: + return var_s64; + case GlslVarType::U64: + return var_u64; + case GlslVarType::F64: + return var_f64; + case GlslVarType::U32x2: + return var_u32x2; + case GlslVarType::F32x2: + return var_f32x2; + case GlslVarType::U32x3: + return var_u32x3; + case GlslVarType::F32x3: + return var_f32x3; + case GlslVarType::U32x4: + return var_u32x4; + case GlslVarType::F32x4: + return var_f32x4; + default: + throw NotImplementedException("Type {}", type); + } +} + +} // namespace Shader::Backend::GLSL -- cgit v1.2.3 From 9f3ffb996b0d02ca64b492d22ff158e8f3659257 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 30 May 2021 19:13:22 -0400 Subject: glsl: Rework var alloc to not assign unused results --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 8c6944f07..896457248 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -110,7 +110,6 @@ std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { } else { Id id{}; id.type.Assign(type); - // id.is_null.Assign(1); GetUseTracker(type).uses_temp = true; inst.SetDefinition(id); } @@ -121,6 +120,20 @@ std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) { return Define(inst, RegType(type)); } +std::string VarAlloc::PhiDefine(IR::Inst& inst, IR::Type type) { + return AddDefine(inst, RegType(type)); +} + +std::string VarAlloc::AddDefine(IR::Inst& inst, GlslVarType type) { + if (inst.HasUses()) { + inst.SetDefinition(Alloc(type)); + return Representation(inst.Definition()); + } else { + return ""; + } + return Representation(inst.Definition()); +} + std::string VarAlloc::Consume(const IR::Value& value) { return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); } @@ -223,6 +236,8 @@ VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { switch (type) { case GlslVarType::U1: return var_bool; + case GlslVarType::F16x2: + return var_f16x2; case GlslVarType::U32: return var_u32; case GlslVarType::S32: -- cgit v1.2.3 From e10366974edd7c75111d0bef16daf941db9e9a30 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Sun, 30 May 2021 22:44:28 -0400 Subject: glsl: Implement precise fp variable allocation --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 896457248..2ecdec7f2 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -43,6 +43,10 @@ std::string TypePrefix(GlslVarType type) { return "u4_"; case GlslVarType::F32x4: return "f4_"; + case GlslVarType::PrecF32: + return "pf_"; + case GlslVarType::PrecF64: + return "pd_"; case GlslVarType::Void: return ""; default: @@ -225,6 +229,10 @@ std::string VarAlloc::GetGlslType(GlslVarType type) const { return "uvec4 "; case GlslVarType::F32x4: return "vec4 "; + case GlslVarType::PrecF32: + return "precise float "; + case GlslVarType::PrecF64: + return "precise double "; case GlslVarType::Void: return ""; default: @@ -262,6 +270,10 @@ VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { return var_u32x4; case GlslVarType::F32x4: return var_f32x4; + case GlslVarType::PrecF32: + return var_precf32; + case GlslVarType::PrecF64: + return var_precf64; default: throw NotImplementedException("Type {}", type); } @@ -297,6 +309,10 @@ const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const { return var_u32x4; case GlslVarType::F32x4: return var_f32x4; + case GlslVarType::PrecF32: + return var_precf32; + case GlslVarType::PrecF64: + return var_precf64; default: throw NotImplementedException("Type {}", type); } -- cgit v1.2.3 From 59576b82a8c06943e6b9fafbff6ed1884a4132a7 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Tue, 1 Jun 2021 00:07:14 -0400 Subject: glsl: Fix precise variable declaration and add some more separation in the shader for better debugability when dumped --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 34 +++++++++++------------- 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 2ecdec7f2..1ab64add4 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -202,37 +202,35 @@ GlslVarType VarAlloc::RegType(IR::Type type) const { std::string VarAlloc::GetGlslType(GlslVarType type) const { switch (type) { case GlslVarType::U1: - return "bool "; + return "bool"; case GlslVarType::F16x2: - return "f16vec2 "; + return "f16vec2"; case GlslVarType::U32: - return "uint "; + return "uint"; case GlslVarType::S32: - return "int "; + return "int"; case GlslVarType::F32: - return "float "; + case GlslVarType::PrecF32: + return "float"; case GlslVarType::S64: - return "int64_t "; + return "int64_t"; case GlslVarType::U64: - return "uint64_t "; + return "uint64_t"; case GlslVarType::F64: - return "double "; + case GlslVarType::PrecF64: + return "double"; case GlslVarType::U32x2: - return "uvec2 "; + return "uvec2"; case GlslVarType::F32x2: - return "vec2 "; + return "vec2"; case GlslVarType::U32x3: - return "uvec3 "; + return "uvec3"; case GlslVarType::F32x3: - return "vec3 "; + return "vec3"; case GlslVarType::U32x4: - return "uvec4 "; + return "uvec4"; case GlslVarType::F32x4: - return "vec4 "; - case GlslVarType::PrecF32: - return "precise float "; - case GlslVarType::PrecF64: - return "precise double "; + return "vec4"; case GlslVarType::Void: return ""; default: -- cgit v1.2.3 From 8d8ce24f20649be639dbb3cc0f3edc90c6a6481e Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Thu, 3 Jun 2021 19:15:36 -0400 Subject: glsl: Implement Load/WriteGlobal along with some other misc changes and fixes --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 1ab64add4..0ae56651e 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -58,13 +58,13 @@ std::string FormatFloat(std::string_view value, IR::Type type) { // TODO: Confirm FP64 nan/inf if (type == IR::Type::F32) { if (value == "nan") { - return "uintBitsToFloat(0x7fc00000)"; + return "utof(0x7fc00000)"; } if (value == "inf") { - return "uintBitsToFloat(0x7f800000)"; + return "utof(0x7f800000)"; } if (value == "-inf") { - return "uintBitsToFloat(0xff800000)"; + return "utof(0xff800000)"; } } if (value.find_first_of('e') != std::string_view::npos) { -- cgit v1.2.3 From 258106038e921de6863d3e871a82fb7a0c77f10d Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Mon, 7 Jun 2021 18:04:01 -0400 Subject: glsl: Allow dynamic tracking of variable allocation --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 0ae56651e..95e8233e2 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -116,8 +116,8 @@ std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { id.type.Assign(type); GetUseTracker(type).uses_temp = true; inst.SetDefinition(id); + return "t" + Representation(inst.Definition()); } - return Representation(inst.Definition()); } std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) { @@ -156,21 +156,27 @@ std::string VarAlloc::GetGlslType(IR::Type type) const { Id VarAlloc::Alloc(GlslVarType type) { auto& use_tracker{GetUseTracker(type)}; - if (use_tracker.num_used < NUM_VARS) { - for (size_t var = 1; var < NUM_VARS; ++var) { - if (use_tracker.var_use[var]) { - continue; - } - use_tracker.num_used = std::max(use_tracker.num_used, var + 1); - use_tracker.var_use[var] = true; - Id ret{}; - ret.is_valid.Assign(1); - ret.type.Assign(type); - ret.index.Assign(static_cast(var)); - return ret; + const auto num_vars{use_tracker.var_use.size()}; + for (size_t var = 0; var < num_vars; ++var) { + if (use_tracker.var_use[var]) { + continue; } + use_tracker.num_used = std::max(use_tracker.num_used, var + 1); + use_tracker.var_use[var] = true; + Id ret{}; + ret.is_valid.Assign(1); + ret.type.Assign(type); + ret.index.Assign(static_cast(var)); + return ret; } - throw NotImplementedException("Variable spilling"); + // Allocate a new variable + use_tracker.var_use.push_back(true); + Id ret{}; + ret.is_valid.Assign(1); + ret.type.Assign(type); + ret.index.Assign(static_cast(use_tracker.num_used)); + ++use_tracker.num_used; + return ret; } void VarAlloc::Free(Id id) { -- cgit v1.2.3 From 4759db28d0b98c79f9a630b63ba13c4cd0df9109 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Fri, 11 Jun 2021 00:33:33 -0400 Subject: glsl: Address Rodrigo's feedback --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 95e8233e2..6a19aa549 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -116,7 +116,7 @@ std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { id.type.Assign(type); GetUseTracker(type).uses_temp = true; inst.SetDefinition(id); - return "t" + Representation(inst.Definition()); + return 't' + Representation(inst.Definition()); } } -- cgit v1.2.3 From 7d89a82a4891f78e2c068a24ad3bb56d74c92055 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Fri, 11 Jun 2021 00:41:28 -0400 Subject: glsl: Remove Signed Integer variables --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index 6a19aa549..cbf56491c 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -21,12 +21,8 @@ std::string TypePrefix(GlslVarType type) { return "f16x2_"; case GlslVarType::U32: return "u_"; - case GlslVarType::S32: - return "s_"; case GlslVarType::F32: return "f_"; - case GlslVarType::S64: - return "s64_"; case GlslVarType::U64: return "u64_"; case GlslVarType::F64: @@ -213,13 +209,9 @@ std::string VarAlloc::GetGlslType(GlslVarType type) const { return "f16vec2"; case GlslVarType::U32: return "uint"; - case GlslVarType::S32: - return "int"; case GlslVarType::F32: case GlslVarType::PrecF32: return "float"; - case GlslVarType::S64: - return "int64_t"; case GlslVarType::U64: return "uint64_t"; case GlslVarType::F64: @@ -252,12 +244,8 @@ VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { return var_f16x2; case GlslVarType::U32: return var_u32; - case GlslVarType::S32: - return var_s32; case GlslVarType::F32: return var_f32; - case GlslVarType::S64: - return var_s64; case GlslVarType::U64: return var_u64; case GlslVarType::F64: @@ -291,12 +279,8 @@ const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const { return var_f16x2; case GlslVarType::U32: return var_u32; - case GlslVarType::S32: - return var_s32; case GlslVarType::F32: return var_f32; - case GlslVarType::S64: - return var_s64; case GlslVarType::U64: return var_u64; case GlslVarType::F64: -- cgit v1.2.3 From 6eea88d6149f7122777b325c7fc8549e2a974e64 Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Mon, 14 Jun 2021 23:02:07 -0400 Subject: glsl: Cleanup/Address feedback --- src/shader_recompiler/backend/glsl/var_alloc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp') diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp index cbf56491c..194f926ca 100644 --- a/src/shader_recompiler/backend/glsl/var_alloc.cpp +++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp @@ -177,8 +177,7 @@ Id VarAlloc::Alloc(GlslVarType type) { void VarAlloc::Free(Id id) { if (id.is_valid == 0) { - // throw LogicError("Freeing invalid variable"); - return; + throw LogicError("Freeing invalid variable"); } auto& use_tracker{GetUseTracker(id.type)}; use_tracker.var_use[id.index] = false; -- cgit v1.2.3