summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/glsl/emit_glsl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend/glsl/emit_glsl.cpp')
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
new file mode 100644
index 000000000..bb1d8b272
--- /dev/null
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -0,0 +1,156 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6#include <tuple>
7
8#include "shader_recompiler/backend/bindings.h"
9#include "shader_recompiler/backend/glsl/emit_context.h"
10#include "shader_recompiler/backend/glsl/emit_glsl.h"
11#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
12#include "shader_recompiler/frontend/ir/program.h"
13#include "shader_recompiler/profile.h"
14
15#pragma optimize("", off)
16namespace Shader::Backend::GLSL {
17namespace {
18template <class Func>
19struct FuncTraits {};
20
21template <class ReturnType_, class... Args>
22struct FuncTraits<ReturnType_ (*)(Args...)> {
23 using ReturnType = ReturnType_;
24
25 static constexpr size_t NUM_ARGS = sizeof...(Args);
26
27 template <size_t I>
28 using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
29};
30
31template <auto func, typename... Args>
32void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) {
33 inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...));
34}
35
36template <typename ArgType>
37ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
38 if constexpr (std::is_same_v<ArgType, std::string_view>) {
39 return ctx.reg_alloc.Consume(arg);
40 } else if constexpr (std::is_same_v<ArgType, IR::Inst&>) {
41 return *arg.Inst();
42 } else if constexpr (std::is_same_v<ArgType, const IR::Value&>) {
43 return arg;
44 } else if constexpr (std::is_same_v<ArgType, u32>) {
45 return arg.U32();
46 } else if constexpr (std::is_same_v<ArgType, IR::Attribute>) {
47 return arg.Attribute();
48 } else if constexpr (std::is_same_v<ArgType, IR::Patch>) {
49 return arg.Patch();
50 } else if constexpr (std::is_same_v<ArgType, IR::Reg>) {
51 return arg.Reg();
52 }
53}
54
55template <auto func, bool is_first_arg_inst, size_t... I>
56void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) {
57 using Traits = FuncTraits<decltype(func)>;
58 if constexpr (std::is_same_v<typename Traits::ReturnType, Id>) {
59 if constexpr (is_first_arg_inst) {
60 SetDefinition<func>(
61 ctx, inst, inst,
62 Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I))...);
63 } else {
64 SetDefinition<func>(
65 ctx, inst, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I))...);
66 }
67 } else {
68 if constexpr (is_first_arg_inst) {
69 func(ctx, inst, Arg<typename Traits::template ArgType<I + 2>>(ctx, inst->Arg(I))...);
70 } else {
71 func(ctx, Arg<typename Traits::template ArgType<I + 1>>(ctx, inst->Arg(I))...);
72 }
73 }
74}
75
76template <auto func>
77void Invoke(EmitContext& ctx, IR::Inst* inst) {
78 using Traits = FuncTraits<decltype(func)>;
79 static_assert(Traits::NUM_ARGS >= 1, "Insufficient arguments");
80 if constexpr (Traits::NUM_ARGS == 1) {
81 Invoke<func, false>(ctx, inst, std::make_index_sequence<0>{});
82 } else {
83 using FirstArgType = typename Traits::template ArgType<1>;
84 static constexpr bool is_first_arg_inst = std::is_same_v<FirstArgType, IR::Inst*>;
85 using Indices = std::make_index_sequence<Traits::NUM_ARGS - (is_first_arg_inst ? 2 : 1)>;
86 Invoke<func, is_first_arg_inst>(ctx, inst, Indices{});
87 }
88}
89
90void EmitInst(EmitContext& ctx, IR::Inst* inst) {
91 switch (inst->GetOpcode()) {
92#define OPCODE(name, result_type, ...) \
93 case IR::Opcode::name: \
94 return Invoke<&Emit##name>(ctx, inst);
95#include "shader_recompiler/frontend/ir/opcodes.inc"
96#undef OPCODE
97 }
98 throw LogicError("Invalid opcode {}", inst->GetOpcode());
99}
100
101void EmitCode(EmitContext& ctx, const IR::Program& program) {
102 for (const IR::AbstractSyntaxNode& node : program.syntax_list) {
103 switch (node.type) {
104 case IR::AbstractSyntaxNode::Type::Block:
105 for (IR::Inst& inst : node.data.block->Instructions()) {
106 EmitInst(ctx, &inst);
107 }
108 break;
109 case IR::AbstractSyntaxNode::Type::If:
110 ctx.Add("if (");
111 break;
112 case IR::AbstractSyntaxNode::Type::EndIf:
113 ctx.Add("){{");
114 break;
115 case IR::AbstractSyntaxNode::Type::Loop:
116 ctx.Add("while (");
117 break;
118 case IR::AbstractSyntaxNode::Type::Repeat:
119 if (node.data.repeat.cond.IsImmediate()) {
120 if (node.data.repeat.cond.U1()) {
121 ctx.Add("ENDREP;");
122 } else {
123 ctx.Add("BRK;"
124 "ENDREP;");
125 }
126 }
127 break;
128 case IR::AbstractSyntaxNode::Type::Break:
129 if (node.data.break_node.cond.IsImmediate()) {
130 if (node.data.break_node.cond.U1()) {
131 ctx.Add("break;");
132 }
133 }
134 break;
135 case IR::AbstractSyntaxNode::Type::Return:
136 case IR::AbstractSyntaxNode::Type::Unreachable:
137 ctx.Add("return;");
138 break;
139 default:
140 ctx.Add("UNAHNDLED {}", node.type);
141 break;
142 }
143 }
144}
145
146} // Anonymous namespace
147
148std::string EmitGLSL(const Profile& profile, IR::Program& program, Bindings& bindings) {
149 EmitContext ctx{program, bindings, profile};
150 // ctx.SetupBuffers();
151 EmitCode(ctx, program);
152 ctx.code += "}";
153 return ctx.code;
154}
155
156} // namespace Shader::Backend::GLSL