summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-04-26 05:55:21 +0200
committerbunnei <bunneidev@gmail.com>2018-04-26 20:38:42 +0200
commitc9d7abe9c9be3e3654b47623602770c9be9ee88f (patch)
tree81a6cda909f1fe18f6a5ff31321369418bd3337b
parentgl_shader_decompiler: Move color output to EXIT instruction. (diff)
downloadyuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.gz
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.bz2
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.lz
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.xz
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.zst
yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.zip
-rw-r--r--src/video_core/engines/shader_bytecode.h10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp107
2 files changed, 111 insertions, 6 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index f4d11fa5d..f3ca30cfa 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -19,7 +19,10 @@ namespace Tegra {
namespace Shader {
struct Register {
- // Register 255 is special cased to always be 0
+ /// Number of registers
+ static constexpr size_t NumRegisters = 256;
+
+ /// Register 255 is special cased to always be 0
static constexpr size_t ZeroIndex = 255;
constexpr Register() = default;
@@ -48,6 +51,11 @@ struct Register {
return ~value;
}
+ u64 GetSwizzledIndex(u64 elem) const {
+ elem = (value + elem) & 3;
+ return (value & ~3) + elem;
+ }
+
private:
u64 value{};
};
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 82fd7a0de..3716bb782 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -146,6 +146,90 @@ private:
std::string shader_source;
};
+/**
+ * Represents an emulated shader register, used to track the state of that register for emulation
+ * with GLSL. At this time, a register can be used as a float or an integer. This class is used for
+ * bookkeeping within the GLSL program.
+ */
+class GLSLRegister {
+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)} {}
+
+ /// Returns a GLSL string representing the current state of the register
+ const std::string& GetActiveString() {
+ declr_type.insert(active_type);
+
+ switch (active_type) {
+ case Type::Float:
+ return float_str;
+ case Type::Integer:
+ return integer_str;
+ }
+
+ 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 + ");");
+ }
+
+ /// 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();
+ }
+
+ /// 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();
+ }
+
+private:
+ enum class Type {
+ Float,
+ Integer,
+ };
+
+ const size_t index;
+ const std::string float_str;
+ const std::string integer_str;
+ ShaderWriter& shader;
+ Type active_type{Type::Float};
+ std::set<Type> declr_type;
+};
+
class GLSLGenerator {
public:
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
@@ -153,6 +237,7 @@ public:
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
stage(stage) {
+ BuildRegisterList();
Generate();
}
@@ -166,6 +251,13 @@ public:
}
private:
+ /// Build the GLSL register list
+ void BuildRegisterList() {
+ for (size_t index = 0; index < Register::NumRegisters; ++index) {
+ regs.emplace_back(index, shader);
+ }
+ }
+
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine& GetSubroutine(u32 begin, u32 end) const {
auto iter = subroutines.find(Subroutine{begin, end});
@@ -224,8 +316,8 @@ private:
if (reg == Register::ZeroIndex) {
return "0";
}
- return *declr_register.insert("register_" + std::to_string(reg.GetSwizzledIndex(elem)))
- .first;
+
+ return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
}
/// Generates code representing a uniform (C buffer) register.
@@ -761,8 +853,13 @@ private:
/// Add declarations for registers
void GenerateDeclarations() {
- for (const auto& reg : declr_register) {
- declarations.AddLine("float " + reg + " = 0.0;");
+ for (const auto& reg : regs) {
+ if (reg.IsFloatUsed()) {
+ declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
+ }
+ if (reg.IsIntegerUsed()) {
+ declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
+ }
}
declarations.AddNewLine();
@@ -809,9 +906,9 @@ private:
ShaderWriter shader;
ShaderWriter declarations;
+ std::vector<GLSLRegister> regs;
// Declarations
- std::set<std::string> declr_register;
std::set<std::string> declr_predicates;
std::set<Attribute::Index> declr_input_attribute;
std::set<Attribute::Index> declr_output_attribute;