summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-09-04 17:42:13 -0400
committerGravatar GitHub2019-09-04 17:42:13 -0400
commite77d2b2103edac8eef9e3a37ee35e6b470b0c975 (patch)
treebe491f6f0d7c72b9925ffbbbedc3002f0178cabd /src
parentAM: Stub IApplicationFunctions::GetGpuErrorDetectedSystemEvent (#2827) (diff)
parentgl_shader_decompiler: Fixup slow path (diff)
downloadyuzu-e77d2b2103edac8eef9e3a37ee35e6b470b0c975.tar.gz
yuzu-e77d2b2103edac8eef9e3a37ee35e6b470b0c975.tar.xz
yuzu-e77d2b2103edac8eef9e3a37ee35e6b470b0c975.zip
Merge pull request #2801 from ReinUsesLisp/typed-decompiler
gl_shader_decompiler: Rework GLSL decompiler type system
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp43
-rw-r--r--src/video_core/renderer_opengl/gl_device.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp930
3 files changed, 548 insertions, 431 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 03d434b28..4f59a87b4 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -14,12 +14,22 @@
14namespace OpenGL { 14namespace OpenGL {
15 15
16namespace { 16namespace {
17
17template <typename T> 18template <typename T>
18T GetInteger(GLenum pname) { 19T GetInteger(GLenum pname) {
19 GLint temporary; 20 GLint temporary;
20 glGetIntegerv(pname, &temporary); 21 glGetIntegerv(pname, &temporary);
21 return static_cast<T>(temporary); 22 return static_cast<T>(temporary);
22} 23}
24
25bool TestProgram(const GLchar* glsl) {
26 const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl)};
27 GLint link_status;
28 glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
29 glDeleteProgram(shader);
30 return link_status == GL_TRUE;
31}
32
23} // Anonymous namespace 33} // Anonymous namespace
24 34
25Device::Device() { 35Device::Device() {
@@ -32,6 +42,11 @@ Device::Device() {
32 has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; 42 has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
33 has_variable_aoffi = TestVariableAoffi(); 43 has_variable_aoffi = TestVariableAoffi();
34 has_component_indexing_bug = TestComponentIndexingBug(); 44 has_component_indexing_bug = TestComponentIndexingBug();
45 has_precise_bug = TestPreciseBug();
46
47 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", has_variable_aoffi);
48 LOG_INFO(Render_OpenGL, "Renderer_ComponentIndexingBug: {}", has_component_indexing_bug);
49 LOG_INFO(Render_OpenGL, "Renderer_PreciseBug: {}", has_precise_bug);
35} 50}
36 51
37Device::Device(std::nullptr_t) { 52Device::Device(std::nullptr_t) {
@@ -42,30 +57,21 @@ Device::Device(std::nullptr_t) {
42 has_vertex_viewport_layer = true; 57 has_vertex_viewport_layer = true;
43 has_variable_aoffi = true; 58 has_variable_aoffi = true;
44 has_component_indexing_bug = false; 59 has_component_indexing_bug = false;
60 has_precise_bug = false;
45} 61}
46 62
47bool Device::TestVariableAoffi() { 63bool Device::TestVariableAoffi() {
48 const GLchar* AOFFI_TEST = R"(#version 430 core 64 return TestProgram(R"(#version 430 core
49// This is a unit test, please ignore me on apitrace bug reports. 65// This is a unit test, please ignore me on apitrace bug reports.
50uniform sampler2D tex; 66uniform sampler2D tex;
51uniform ivec2 variable_offset; 67uniform ivec2 variable_offset;
52out vec4 output_attribute; 68out vec4 output_attribute;
53void main() { 69void main() {
54 output_attribute = textureOffset(tex, vec2(0), variable_offset); 70 output_attribute = textureOffset(tex, vec2(0), variable_offset);
55} 71})");
56)";
57 const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &AOFFI_TEST)};
58 GLint link_status{};
59 glGetProgramiv(shader, GL_LINK_STATUS, &link_status);
60 glDeleteProgram(shader);
61
62 const bool supported{link_status == GL_TRUE};
63 LOG_INFO(Render_OpenGL, "Renderer_VariableAOFFI: {}", supported);
64 return supported;
65} 72}
66 73
67bool Device::TestComponentIndexingBug() { 74bool Device::TestComponentIndexingBug() {
68 constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";
69 const GLchar* COMPONENT_TEST = R"(#version 430 core 75 const GLchar* COMPONENT_TEST = R"(#version 430 core
70layout (std430, binding = 0) buffer OutputBuffer { 76layout (std430, binding = 0) buffer OutputBuffer {
71 uint output_value; 77 uint output_value;
@@ -105,12 +111,21 @@ void main() {
105 GLuint result; 111 GLuint result;
106 glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result); 112 glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
107 if (result != values.at(index)) { 113 if (result != values.at(index)) {
108 LOG_INFO(Render_OpenGL, log_message, true);
109 return true; 114 return true;
110 } 115 }
111 } 116 }
112 LOG_INFO(Render_OpenGL, log_message, false);
113 return false; 117 return false;
114} 118}
115 119
120bool Device::TestPreciseBug() {
121 return !TestProgram(R"(#version 430 core
122in vec3 coords;
123out float out_value;
124uniform sampler2DShadow tex;
125void main() {
126 precise float tmp_value = vec4(texture(tex, coords)).x;
127 out_value = tmp_value;
128})");
129}
130
116} // namespace OpenGL 131} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index 3ef7c6dd8..ba6dcd3be 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -46,9 +46,14 @@ public:
46 return has_component_indexing_bug; 46 return has_component_indexing_bug;
47 } 47 }
48 48
49 bool HasPreciseBug() const {
50 return has_precise_bug;
51 }
52
49private: 53private:
50 static bool TestVariableAoffi(); 54 static bool TestVariableAoffi();
51 static bool TestComponentIndexingBug(); 55 static bool TestComponentIndexingBug();
56 static bool TestPreciseBug();
52 57
53 std::size_t uniform_buffer_alignment{}; 58 std::size_t uniform_buffer_alignment{};
54 std::size_t shader_storage_alignment{}; 59 std::size_t shader_storage_alignment{};
@@ -58,6 +63,7 @@ private:
58 bool has_vertex_viewport_layer{}; 63 bool has_vertex_viewport_layer{};
59 bool has_variable_aoffi{}; 64 bool has_variable_aoffi{};
60 bool has_component_indexing_bug{}; 65 bool has_component_indexing_bug{};
66 bool has_precise_bug{};
61}; 67};
62 68
63} // namespace OpenGL 69} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 359d58cbe..a5cc1a86f 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -39,7 +39,7 @@ using namespace VideoCommon::Shader;
39using Maxwell = Tegra::Engines::Maxwell3D::Regs; 39using Maxwell = Tegra::Engines::Maxwell3D::Regs;
40using Operation = const OperationNode&; 40using Operation = const OperationNode&;
41 41
42enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; 42enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
43 43
44struct TextureAoffi {}; 44struct TextureAoffi {};
45using TextureArgument = std::pair<Type, Node>; 45using TextureArgument = std::pair<Type, Node>;
@@ -48,7 +48,7 @@ using TextureIR = std::variant<TextureAoffi, TextureArgument>;
48constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 48constexpr u32 MAX_CONSTBUFFER_ELEMENTS =
49 static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float)); 49 static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float));
50 50
51class ShaderWriter { 51class ShaderWriter final {
52public: 52public:
53 void AddExpression(std::string_view text) { 53 void AddExpression(std::string_view text) {
54 DEBUG_ASSERT(scope >= 0); 54 DEBUG_ASSERT(scope >= 0);
@@ -93,9 +93,157 @@ private:
93 u32 temporary_index = 1; 93 u32 temporary_index = 1;
94}; 94};
95 95
96class Expression final {
97public:
98 Expression(std::string code, Type type) : code{std::move(code)}, type{type} {
99 ASSERT(type != Type::Void);
100 }
101 Expression() : type{Type::Void} {}
102
103 Type GetType() const {
104 return type;
105 }
106
107 std::string GetCode() const {
108 return code;
109 }
110
111 void CheckVoid() const {
112 ASSERT(type == Type::Void);
113 }
114
115 std::string As(Type type) const {
116 switch (type) {
117 case Type::Bool:
118 return AsBool();
119 case Type::Bool2:
120 return AsBool2();
121 case Type::Float:
122 return AsFloat();
123 case Type::Int:
124 return AsInt();
125 case Type::Uint:
126 return AsUint();
127 case Type::HalfFloat:
128 return AsHalfFloat();
129 default:
130 UNREACHABLE_MSG("Invalid type");
131 return code;
132 }
133 }
134
135 std::string AsBool() const {
136 switch (type) {
137 case Type::Bool:
138 return code;
139 default:
140 UNREACHABLE_MSG("Incompatible types");
141 return code;
142 }
143 }
144
145 std::string AsBool2() const {
146 switch (type) {
147 case Type::Bool2:
148 return code;
149 default:
150 UNREACHABLE_MSG("Incompatible types");
151 return code;
152 }
153 }
154
155 std::string AsFloat() const {
156 switch (type) {
157 case Type::Float:
158 return code;
159 case Type::Uint:
160 return fmt::format("utof({})", code);
161 case Type::Int:
162 return fmt::format("itof({})", code);
163 case Type::HalfFloat:
164 return fmt::format("utof(packHalf2x16({}))", code);
165 default:
166 UNREACHABLE_MSG("Incompatible types");
167 return code;
168 }
169 }
170
171 std::string AsInt() const {
172 switch (type) {
173 case Type::Float:
174 return fmt::format("ftoi({})", code);
175 case Type::Uint:
176 return fmt::format("int({})", code);
177 case Type::Int:
178 return code;
179 case Type::HalfFloat:
180 return fmt::format("int(packHalf2x16({}))", code);
181 default:
182 UNREACHABLE_MSG("Incompatible types");
183 return code;
184 }
185 }
186
187 std::string AsUint() const {
188 switch (type) {
189 case Type::Float:
190 return fmt::format("ftou({})", code);
191 case Type::Uint:
192 return code;
193 case Type::Int:
194 return fmt::format("uint({})", code);
195 case Type::HalfFloat:
196 return fmt::format("packHalf2x16({})", code);
197 default:
198 UNREACHABLE_MSG("Incompatible types");
199 return code;
200 }
201 }
202
203 std::string AsHalfFloat() const {
204 switch (type) {
205 case Type::Float:
206 return fmt::format("unpackHalf2x16(ftou({}))", code);
207 case Type::Uint:
208 return fmt::format("unpackHalf2x16({})", code);
209 case Type::Int:
210 return fmt::format("unpackHalf2x16(int({}))", code);
211 case Type::HalfFloat:
212 return code;
213 default:
214 UNREACHABLE_MSG("Incompatible types");
215 return code;
216 }
217 }
218
219private:
220 std::string code;
221 Type type{};
222};
223
224constexpr const char* GetTypeString(Type type) {
225 switch (type) {
226 case Type::Bool:
227 return "bool";
228 case Type::Bool2:
229 return "bvec2";
230 case Type::Float:
231 return "float";
232 case Type::Int:
233 return "int";
234 case Type::Uint:
235 return "uint";
236 case Type::HalfFloat:
237 return "vec2";
238 default:
239 UNREACHABLE_MSG("Invalid type");
240 return "<invalid type>";
241 }
242}
243
96/// Generates code to use for a swizzle operation. 244/// Generates code to use for a swizzle operation.
97constexpr const char* GetSwizzle(u32 element) { 245constexpr const char* GetSwizzle(u32 element) {
98 constexpr std::array<const char*, 4> swizzle = {".x", ".y", ".z", ".w"}; 246 constexpr std::array swizzle = {".x", ".y", ".z", ".w"};
99 return swizzle.at(element); 247 return swizzle.at(element);
100} 248}
101 249
@@ -134,8 +282,8 @@ constexpr bool IsGenericAttribute(Attribute::Index index) {
134 return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31; 282 return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31;
135} 283}
136 284
137constexpr Attribute::Index ToGenericAttribute(u32 value) { 285constexpr Attribute::Index ToGenericAttribute(u64 value) {
138 return static_cast<Attribute::Index>(value + static_cast<u32>(Attribute::Index::Attribute_0)); 286 return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0));
139} 287}
140 288
141u32 GetGenericAttributeIndex(Attribute::Index index) { 289u32 GetGenericAttributeIndex(Attribute::Index index) {
@@ -191,7 +339,7 @@ public:
191 339
192 // VM's program counter 340 // VM's program counter
193 const auto first_address = ir.GetBasicBlocks().begin()->first; 341 const auto first_address = ir.GetBasicBlocks().begin()->first;
194 code.AddLine("uint jmp_to = {}u;", first_address); 342 code.AddLine("uint jmp_to = {}U;", first_address);
195 343
196 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems 344 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
197 // unlikely that shaders will use 20 nested SSYs and PBKs. 345 // unlikely that shaders will use 20 nested SSYs and PBKs.
@@ -199,7 +347,7 @@ public:
199 constexpr u32 FLOW_STACK_SIZE = 20; 347 constexpr u32 FLOW_STACK_SIZE = 20;
200 for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { 348 for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
201 code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); 349 code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
202 code.AddLine("uint {} = 0u;", FlowStackTopName(stack)); 350 code.AddLine("uint {} = 0U;", FlowStackTopName(stack));
203 } 351 }
204 } 352 }
205 353
@@ -210,7 +358,7 @@ public:
210 358
211 for (const auto& pair : ir.GetBasicBlocks()) { 359 for (const auto& pair : ir.GetBasicBlocks()) {
212 const auto [address, bb] = pair; 360 const auto [address, bb] = pair;
213 code.AddLine("case 0x{:x}u: {{", address); 361 code.AddLine("case 0x{:X}U: {{", address);
214 ++code.scope; 362 ++code.scope;
215 363
216 VisitBlock(bb); 364 VisitBlock(bb);
@@ -322,7 +470,7 @@ private:
322 void DeclareRegisters() { 470 void DeclareRegisters() {
323 const auto& registers = ir.GetRegisters(); 471 const auto& registers = ir.GetRegisters();
324 for (const u32 gpr : registers) { 472 for (const u32 gpr : registers) {
325 code.AddLine("float {} = 0;", GetRegister(gpr)); 473 code.AddLine("float {} = 0.0f;", GetRegister(gpr));
326 } 474 }
327 if (!registers.empty()) { 475 if (!registers.empty()) {
328 code.AddNewLine(); 476 code.AddNewLine();
@@ -348,7 +496,7 @@ private:
348 return; 496 return;
349 } 497 }
350 const auto element_count = Common::AlignUp(local_memory_size, 4) / 4; 498 const auto element_count = Common::AlignUp(local_memory_size, 4) / 4;
351 code.AddLine("float {}[{}];", GetLocalMemory(), element_count); 499 code.AddLine("uint {}[{}];", GetLocalMemory(), element_count);
352 code.AddNewLine(); 500 code.AddNewLine();
353 } 501 }
354 502
@@ -371,8 +519,6 @@ private:
371 return "noperspective "; 519 return "noperspective ";
372 default: 520 default:
373 case AttributeUse::Unused: 521 case AttributeUse::Unused:
374 UNREACHABLE_MSG("Unused attribute being fetched");
375 return {};
376 UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<u32>(attribute)); 522 UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<u32>(attribute));
377 return {}; 523 return {};
378 } 524 }
@@ -449,7 +595,7 @@ private:
449 const auto [index, size] = entry; 595 const auto [index, size] = entry;
450 code.AddLine("layout (std140, binding = CBUF_BINDING_{}) uniform {} {{", index, 596 code.AddLine("layout (std140, binding = CBUF_BINDING_{}) uniform {} {{", index,
451 GetConstBufferBlock(index)); 597 GetConstBufferBlock(index));
452 code.AddLine(" vec4 {}[MAX_CONSTBUFFER_ELEMENTS];", GetConstBuffer(index)); 598 code.AddLine(" uvec4 {}[{}];", GetConstBuffer(index), MAX_CONSTBUFFER_ELEMENTS);
453 code.AddLine("}};"); 599 code.AddLine("}};");
454 code.AddNewLine(); 600 code.AddNewLine();
455 } 601 }
@@ -470,7 +616,7 @@ private:
470 616
471 code.AddLine("layout (std430, binding = GMEM_BINDING_{}_{}) {} buffer {} {{", 617 code.AddLine("layout (std430, binding = GMEM_BINDING_{}_{}) {} buffer {} {{",
472 base.cbuf_index, base.cbuf_offset, qualifier, GetGlobalMemoryBlock(base)); 618 base.cbuf_index, base.cbuf_offset, qualifier, GetGlobalMemoryBlock(base));
473 code.AddLine(" float {}[];", GetGlobalMemory(base)); 619 code.AddLine(" uint {}[];", GetGlobalMemory(base));
474 code.AddLine("}};"); 620 code.AddLine("}};");
475 code.AddNewLine(); 621 code.AddNewLine();
476 } 622 }
@@ -528,7 +674,7 @@ private:
528 if (!ir.HasPhysicalAttributes()) { 674 if (!ir.HasPhysicalAttributes()) {
529 return; 675 return;
530 } 676 }
531 code.AddLine("float readPhysicalAttribute(uint physical_address) {{"); 677 code.AddLine("float ReadPhysicalAttribute(uint physical_address) {{");
532 ++code.scope; 678 ++code.scope;
533 code.AddLine("switch (physical_address) {{"); 679 code.AddLine("switch (physical_address) {{");
534 680
@@ -537,15 +683,16 @@ private:
537 for (u32 index = 0; index < num_attributes; ++index) { 683 for (u32 index = 0; index < num_attributes; ++index) {
538 const auto attribute{ToGenericAttribute(index)}; 684 const auto attribute{ToGenericAttribute(index)};
539 for (u32 element = 0; element < 4; ++element) { 685 for (u32 element = 0; element < 4; ++element) {
540 constexpr u32 generic_base{0x80}; 686 constexpr u32 generic_base = 0x80;
541 constexpr u32 generic_stride{16}; 687 constexpr u32 generic_stride = 16;
542 constexpr u32 element_stride{4}; 688 constexpr u32 element_stride = 4;
543 const u32 address{generic_base + index * generic_stride + element * element_stride}; 689 const u32 address{generic_base + index * generic_stride + element * element_stride};
544 690
545 const bool declared{stage != ProgramType::Fragment || 691 const bool declared = stage != ProgramType::Fragment ||
546 header.ps.GetAttributeUse(index) != AttributeUse::Unused}; 692 header.ps.GetAttributeUse(index) != AttributeUse::Unused;
547 const std::string value{declared ? ReadAttribute(attribute, element) : "0"}; 693 const std::string value =
548 code.AddLine("case 0x{:x}: return {};", address, value); 694 declared ? ReadAttribute(attribute, element).AsFloat() : "0.0f";
695 code.AddLine("case 0x{:X}U: return {};", address, value);
549 } 696 }
550 } 697 }
551 698
@@ -590,13 +737,11 @@ private:
590 737
591 void VisitBlock(const NodeBlock& bb) { 738 void VisitBlock(const NodeBlock& bb) {
592 for (const auto& node : bb) { 739 for (const auto& node : bb) {
593 if (const std::string expr = Visit(node); !expr.empty()) { 740 Visit(node).CheckVoid();
594 code.AddLine(expr);
595 }
596 } 741 }
597 } 742 }
598 743
599 std::string Visit(const Node& node) { 744 Expression Visit(const Node& node) {
600 if (const auto operation = std::get_if<OperationNode>(&*node)) { 745 if (const auto operation = std::get_if<OperationNode>(&*node)) {
601 const auto operation_index = static_cast<std::size_t>(operation->GetCode()); 746 const auto operation_index = static_cast<std::size_t>(operation->GetCode());
602 if (operation_index >= operation_decompilers.size()) { 747 if (operation_index >= operation_decompilers.size()) {
@@ -614,18 +759,18 @@ private:
614 if (const auto gpr = std::get_if<GprNode>(&*node)) { 759 if (const auto gpr = std::get_if<GprNode>(&*node)) {
615 const u32 index = gpr->GetIndex(); 760 const u32 index = gpr->GetIndex();
616 if (index == Register::ZeroIndex) { 761 if (index == Register::ZeroIndex) {
617 return "0"; 762 return {"0U", Type::Uint};
618 } 763 }
619 return GetRegister(index); 764 return {GetRegister(index), Type::Float};
620 } 765 }
621 766
622 if (const auto immediate = std::get_if<ImmediateNode>(&*node)) { 767 if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
623 const u32 value = immediate->GetValue(); 768 const u32 value = immediate->GetValue();
624 if (value < 10) { 769 if (value < 10) {
625 // For eyecandy avoid using hex numbers on single digits 770 // For eyecandy avoid using hex numbers on single digits
626 return fmt::format("utof({}u)", immediate->GetValue()); 771 return {fmt::format("{}U", immediate->GetValue()), Type::Uint};
627 } 772 }
628 return fmt::format("utof(0x{:x}u)", immediate->GetValue()); 773 return {fmt::format("0x{:X}U", immediate->GetValue()), Type::Uint};
629 } 774 }
630 775
631 if (const auto predicate = std::get_if<PredicateNode>(&*node)) { 776 if (const auto predicate = std::get_if<PredicateNode>(&*node)) {
@@ -640,17 +785,18 @@ private:
640 } 785 }
641 }(); 786 }();
642 if (predicate->IsNegated()) { 787 if (predicate->IsNegated()) {
643 return fmt::format("!({})", value); 788 return {fmt::format("!({})", value), Type::Bool};
644 } 789 }
645 return value; 790 return {value, Type::Bool};
646 } 791 }
647 792
648 if (const auto abuf = std::get_if<AbufNode>(&*node)) { 793 if (const auto abuf = std::get_if<AbufNode>(&*node)) {
649 UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ProgramType::Geometry, 794 UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ProgramType::Geometry,
650 "Physical attributes in geometry shaders are not implemented"); 795 "Physical attributes in geometry shaders are not implemented");
651 if (abuf->IsPhysicalBuffer()) { 796 if (abuf->IsPhysicalBuffer()) {
652 return fmt::format("readPhysicalAttribute(ftou({}))", 797 return {fmt::format("ReadPhysicalAttribute({})",
653 Visit(abuf->GetPhysicalAddress())); 798 Visit(abuf->GetPhysicalAddress()).AsUint()),
799 Type::Float};
654 } 800 }
655 return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); 801 return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer());
656 } 802 }
@@ -661,59 +807,64 @@ private:
661 // Direct access 807 // Direct access
662 const u32 offset_imm = immediate->GetValue(); 808 const u32 offset_imm = immediate->GetValue();
663 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); 809 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access");
664 return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), 810 return {fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()),
665 offset_imm / (4 * 4), (offset_imm / 4) % 4); 811 offset_imm / (4 * 4), (offset_imm / 4) % 4),
812 Type::Uint};
666 } 813 }
667 814
668 if (std::holds_alternative<OperationNode>(*offset)) { 815 if (std::holds_alternative<OperationNode>(*offset)) {
669 // Indirect access 816 // Indirect access
670 const std::string final_offset = code.GenerateTemporary(); 817 const std::string final_offset = code.GenerateTemporary();
671 code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset)); 818 code.AddLine("uint {} = {} >> 2;", final_offset, Visit(offset).AsUint());
672 819
673 if (!device.HasComponentIndexingBug()) { 820 if (!device.HasComponentIndexingBug()) {
674 return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()), 821 return {fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()),
675 final_offset, final_offset); 822 final_offset, final_offset),
823 Type::Uint};
676 } 824 }
677 825
678 // AMD's proprietary GLSL compiler emits ill code for variable component access. 826 // AMD's proprietary GLSL compiler emits ill code for variable component access.
679 // To bypass this driver bug generate 4 ifs, one per each component. 827 // To bypass this driver bug generate 4 ifs, one per each component.
680 const std::string pack = code.GenerateTemporary(); 828 const std::string pack = code.GenerateTemporary();
681 code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()), 829 code.AddLine("uvec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()),
682 final_offset); 830 final_offset);
683 831
684 const std::string result = code.GenerateTemporary(); 832 const std::string result = code.GenerateTemporary();
685 code.AddLine("float {};", result); 833 code.AddLine("uint {};", result);
686 for (u32 swizzle = 0; swizzle < 4; ++swizzle) { 834 for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
687 code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result, 835 code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result,
688 pack, GetSwizzle(swizzle)); 836 pack, GetSwizzle(swizzle));
689 } 837 }
690 return result; 838 return {result, Type::Uint};
691 } 839 }
692 840
693 UNREACHABLE_MSG("Unmanaged offset node type"); 841 UNREACHABLE_MSG("Unmanaged offset node type");
694 } 842 }
695 843
696 if (const auto gmem = std::get_if<GmemNode>(&*node)) { 844 if (const auto gmem = std::get_if<GmemNode>(&*node)) {
697 const std::string real = Visit(gmem->GetRealAddress()); 845 const std::string real = Visit(gmem->GetRealAddress()).AsUint();
698 const std::string base = Visit(gmem->GetBaseAddress()); 846 const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
699 const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); 847 const std::string final_offset = fmt::format("({} - {}) >> 2", real, base);
700 return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); 848 return {fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset),
849 Type::Uint};
701 } 850 }
702 851
703 if (const auto lmem = std::get_if<LmemNode>(&*node)) { 852 if (const auto lmem = std::get_if<LmemNode>(&*node)) {
704 if (stage == ProgramType::Compute) { 853 if (stage == ProgramType::Compute) {
705 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders"); 854 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders");
706 } 855 }
707 return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); 856 return {
857 fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
858 Type::Uint};
708 } 859 }
709 860
710 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { 861 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
711 return GetInternalFlag(internal_flag->GetFlag()); 862 return {GetInternalFlag(internal_flag->GetFlag()), Type::Bool};
712 } 863 }
713 864
714 if (const auto conditional = std::get_if<ConditionalNode>(&*node)) { 865 if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
715 // It's invalid to call conditional on nested nodes, use an operation instead 866 // It's invalid to call conditional on nested nodes, use an operation instead
716 code.AddLine("if ({}) {{", Visit(conditional->GetCondition())); 867 code.AddLine("if ({}) {{", Visit(conditional->GetCondition()).AsBool());
717 ++code.scope; 868 ++code.scope;
718 869
719 VisitBlock(conditional->GetCode()); 870 VisitBlock(conditional->GetCode());
@@ -724,20 +875,21 @@ private:
724 } 875 }
725 876
726 if (const auto comment = std::get_if<CommentNode>(&*node)) { 877 if (const auto comment = std::get_if<CommentNode>(&*node)) {
727 return "// " + comment->GetText(); 878 code.AddLine("// " + comment->GetText());
879 return {};
728 } 880 }
729 881
730 UNREACHABLE(); 882 UNREACHABLE();
731 return {}; 883 return {};
732 } 884 }
733 885
734 std::string ReadAttribute(Attribute::Index attribute, u32 element, const Node& buffer = {}) { 886 Expression ReadAttribute(Attribute::Index attribute, u32 element, const Node& buffer = {}) {
735 const auto GeometryPass = [&](std::string_view name) { 887 const auto GeometryPass = [&](std::string_view name) {
736 if (stage == ProgramType::Geometry && buffer) { 888 if (stage == ProgramType::Geometry && buffer) {
737 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games 889 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
738 // set an 0x80000000 index for those and the shader fails to build. Find out why 890 // set an 0x80000000 index for those and the shader fails to build. Find out why
739 // this happens and what's its intent. 891 // this happens and what's its intent.
740 return fmt::format("gs_{}[ftou({}) % MAX_VERTEX_INPUT]", name, Visit(buffer)); 892 return fmt::format("gs_{}[{} % MAX_VERTEX_INPUT]", name, Visit(buffer).AsUint());
741 } 893 }
742 return std::string(name); 894 return std::string(name);
743 }; 895 };
@@ -746,25 +898,27 @@ private:
746 case Attribute::Index::Position: 898 case Attribute::Index::Position:
747 switch (stage) { 899 switch (stage) {
748 case ProgramType::Geometry: 900 case ProgramType::Geometry:
749 return fmt::format("gl_in[ftou({})].gl_Position{}", Visit(buffer), 901 return {fmt::format("gl_in[{}].gl_Position{}", Visit(buffer).AsUint(),
750 GetSwizzle(element)); 902 GetSwizzle(element)),
903 Type::Float};
751 case ProgramType::Fragment: 904 case ProgramType::Fragment:
752 return element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element)); 905 return {element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element)),
906 Type::Float};
753 default: 907 default:
754 UNREACHABLE(); 908 UNREACHABLE();
755 } 909 }
756 case Attribute::Index::PointCoord: 910 case Attribute::Index::PointCoord:
757 switch (element) { 911 switch (element) {
758 case 0: 912 case 0:
759 return "gl_PointCoord.x"; 913 return {"gl_PointCoord.x", Type::Float};
760 case 1: 914 case 1:
761 return "gl_PointCoord.y"; 915 return {"gl_PointCoord.y", Type::Float};
762 case 2: 916 case 2:
763 case 3: 917 case 3:
764 return "0"; 918 return {"0.0f", Type::Float};
765 } 919 }
766 UNREACHABLE(); 920 UNREACHABLE();
767 return "0"; 921 return {"0", Type::Int};
768 case Attribute::Index::TessCoordInstanceIDVertexID: 922 case Attribute::Index::TessCoordInstanceIDVertexID:
769 // TODO(Subv): Find out what the values are for the first two elements when inside a 923 // TODO(Subv): Find out what the values are for the first two elements when inside a
770 // vertex shader, and what's the value of the fourth element when inside a Tess Eval 924 // vertex shader, and what's the value of the fourth element when inside a Tess Eval
@@ -773,44 +927,49 @@ private:
773 switch (element) { 927 switch (element) {
774 case 2: 928 case 2:
775 // Config pack's first value is instance_id. 929 // Config pack's first value is instance_id.
776 return "uintBitsToFloat(config_pack[0])"; 930 return {"config_pack[0]", Type::Uint};
777 case 3: 931 case 3:
778 return "uintBitsToFloat(gl_VertexID)"; 932 return {"gl_VertexID", Type::Int};
779 } 933 }
780 UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); 934 UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element);
781 return "0"; 935 return {"0", Type::Int};
782 case Attribute::Index::FrontFacing: 936 case Attribute::Index::FrontFacing:
783 // TODO(Subv): Find out what the values are for the other elements. 937 // TODO(Subv): Find out what the values are for the other elements.
784 ASSERT(stage == ProgramType::Fragment); 938 ASSERT(stage == ProgramType::Fragment);
785 switch (element) { 939 switch (element) {
786 case 3: 940 case 3:
787 return "itof(gl_FrontFacing ? -1 : 0)"; 941 return {"(gl_FrontFacing ? -1 : 0)", Type::Int};
788 } 942 }
789 UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); 943 UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element);
790 return "0"; 944 return {"0", Type::Int};
791 default: 945 default:
792 if (IsGenericAttribute(attribute)) { 946 if (IsGenericAttribute(attribute)) {
793 return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); 947 return {GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element),
948 Type::Float};
794 } 949 }
795 break; 950 break;
796 } 951 }
797 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); 952 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
798 return "0"; 953 return {"0", Type::Int};
799 } 954 }
800 955
801 std::string ApplyPrecise(Operation operation, const std::string& value) { 956 Expression ApplyPrecise(Operation operation, std::string value, Type type) {
802 if (!IsPrecise(operation)) { 957 if (!IsPrecise(operation)) {
803 return value; 958 return {std::move(value), type};
804 } 959 }
805 // There's a bug in NVidia's proprietary drivers that makes precise fail on fragment shaders 960 // Old Nvidia drivers have a bug with precise and texture sampling. These are more likely to
806 const std::string precise = stage != ProgramType::Fragment ? "precise " : ""; 961 // be found in fragment shaders, so we disable precise there. There are vertex shaders that
962 // also fail to build but nobody seems to care about those.
963 // Note: Only bugged drivers will skip precise.
964 const bool disable_precise = device.HasPreciseBug() && stage == ProgramType::Fragment;
807 965
808 const std::string temporary = code.GenerateTemporary(); 966 std::string temporary = code.GenerateTemporary();
809 code.AddLine("{}float {} = {};", precise, temporary, value); 967 code.AddLine("{}{} {} = {};", disable_precise ? "" : "precise ", GetTypeString(type),
810 return temporary; 968 temporary, value);
969 return {std::move(temporary), type};
811 } 970 }
812 971
813 std::string VisitOperand(Operation operation, std::size_t operand_index) { 972 Expression VisitOperand(Operation operation, std::size_t operand_index) {
814 const auto& operand = operation[operand_index]; 973 const auto& operand = operation[operand_index];
815 const bool parent_precise = IsPrecise(operation); 974 const bool parent_precise = IsPrecise(operation);
816 const bool child_precise = IsPrecise(operand); 975 const bool child_precise = IsPrecise(operand);
@@ -819,19 +978,16 @@ private:
819 return Visit(operand); 978 return Visit(operand);
820 } 979 }
821 980
822 const std::string temporary = code.GenerateTemporary(); 981 Expression value = Visit(operand);
823 code.AddLine("float {} = {};", temporary, Visit(operand)); 982 std::string temporary = code.GenerateTemporary();
824 return temporary; 983 code.AddLine("{} {} = {};", GetTypeString(value.GetType()), temporary, value.GetCode());
825 } 984 return {std::move(temporary), value.GetType()};
826
827 std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) {
828 return CastOperand(VisitOperand(operation, operand_index), type);
829 } 985 }
830 986
831 std::optional<std::pair<std::string, bool>> GetOutputAttribute(const AbufNode* abuf) { 987 Expression GetOutputAttribute(const AbufNode* abuf) {
832 switch (const auto attribute = abuf->GetIndex()) { 988 switch (const auto attribute = abuf->GetIndex()) {
833 case Attribute::Index::Position: 989 case Attribute::Index::Position:
834 return std::make_pair("gl_Position"s + GetSwizzle(abuf->GetElement()), false); 990 return {"gl_Position"s + GetSwizzle(abuf->GetElement()), Type::Float};
835 case Attribute::Index::LayerViewportPointSize: 991 case Attribute::Index::LayerViewportPointSize:
836 switch (abuf->GetElement()) { 992 switch (abuf->GetElement()) {
837 case 0: 993 case 0:
@@ -841,119 +997,79 @@ private:
841 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) { 997 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
842 return {}; 998 return {};
843 } 999 }
844 return std::make_pair("gl_Layer", true); 1000 return {"gl_Layer", Type::Int};
845 case 2: 1001 case 2:
846 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) { 1002 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
847 return {}; 1003 return {};
848 } 1004 }
849 return std::make_pair("gl_ViewportIndex", true); 1005 return {"gl_ViewportIndex", Type::Int};
850 case 3: 1006 case 3:
851 UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader"); 1007 UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader");
852 return std::make_pair("gl_PointSize", false); 1008 return {"gl_PointSize", Type::Float};
853 } 1009 }
854 return {}; 1010 return {};
855 case Attribute::Index::ClipDistances0123: 1011 case Attribute::Index::ClipDistances0123:
856 return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), false); 1012 return {fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), Type::Float};
857 case Attribute::Index::ClipDistances4567: 1013 case Attribute::Index::ClipDistances4567:
858 return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), 1014 return {fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float};
859 false);
860 default: 1015 default:
861 if (IsGenericAttribute(attribute)) { 1016 if (IsGenericAttribute(attribute)) {
862 return std::make_pair( 1017 return {GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()),
863 GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), false); 1018 Type::Float};
864 } 1019 }
865 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); 1020 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
866 return {}; 1021 return {};
867 } 1022 }
868 } 1023 }
869 1024
870 std::string CastOperand(const std::string& value, Type type) const { 1025 Expression GenerateUnary(Operation operation, std::string_view func, Type result_type,
871 switch (type) { 1026 Type type_a) {
872 case Type::Bool: 1027 std::string op_str = fmt::format("{}({})", func, VisitOperand(operation, 0).As(type_a));
873 case Type::Bool2: 1028 return ApplyPrecise(operation, std::move(op_str), result_type);
874 case Type::Float:
875 return value;
876 case Type::Int:
877 return fmt::format("ftoi({})", value);
878 case Type::Uint:
879 return fmt::format("ftou({})", value);
880 case Type::HalfFloat:
881 return fmt::format("toHalf2({})", value);
882 }
883 UNREACHABLE();
884 return value;
885 } 1029 }
886 1030
887 std::string BitwiseCastResult(const std::string& value, Type type, 1031 Expression GenerateBinaryInfix(Operation operation, std::string_view func, Type result_type,
888 bool needs_parenthesis = false) { 1032 Type type_a, Type type_b) {
889 switch (type) { 1033 const std::string op_a = VisitOperand(operation, 0).As(type_a);
890 case Type::Bool: 1034 const std::string op_b = VisitOperand(operation, 1).As(type_b);
891 case Type::Bool2: 1035 std::string op_str = fmt::format("({} {} {})", op_a, func, op_b);
892 case Type::Float:
893 if (needs_parenthesis) {
894 return fmt::format("({})", value);
895 }
896 return value;
897 case Type::Int:
898 return fmt::format("itof({})", value);
899 case Type::Uint:
900 return fmt::format("utof({})", value);
901 case Type::HalfFloat:
902 return fmt::format("fromHalf2({})", value);
903 }
904 UNREACHABLE();
905 return value;
906 }
907
908 std::string GenerateUnary(Operation operation, const std::string& func, Type result_type,
909 Type type_a, bool needs_parenthesis = true) {
910 const std::string op_str = fmt::format("{}({})", func, VisitOperand(operation, 0, type_a));
911
912 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type, needs_parenthesis));
913 }
914
915 std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type,
916 Type type_a, Type type_b) {
917 const std::string op_a = VisitOperand(operation, 0, type_a);
918 const std::string op_b = VisitOperand(operation, 1, type_b);
919 const std::string op_str = fmt::format("({} {} {})", op_a, func, op_b);
920 1036
921 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1037 return ApplyPrecise(operation, std::move(op_str), result_type);
922 } 1038 }
923 1039
924 std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, 1040 Expression GenerateBinaryCall(Operation operation, std::string_view func, Type result_type,
925 Type type_a, Type type_b) { 1041 Type type_a, Type type_b) {
926 const std::string op_a = VisitOperand(operation, 0, type_a); 1042 const std::string op_a = VisitOperand(operation, 0).As(type_a);
927 const std::string op_b = VisitOperand(operation, 1, type_b); 1043 const std::string op_b = VisitOperand(operation, 1).As(type_b);
928 const std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b); 1044 std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b);
929 1045
930 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1046 return ApplyPrecise(operation, std::move(op_str), result_type);
931 } 1047 }
932 1048
933 std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, 1049 Expression GenerateTernary(Operation operation, std::string_view func, Type result_type,
934 Type type_a, Type type_b, Type type_c) { 1050 Type type_a, Type type_b, Type type_c) {
935 const std::string op_a = VisitOperand(operation, 0, type_a); 1051 const std::string op_a = VisitOperand(operation, 0).As(type_a);
936 const std::string op_b = VisitOperand(operation, 1, type_b); 1052 const std::string op_b = VisitOperand(operation, 1).As(type_b);
937 const std::string op_c = VisitOperand(operation, 2, type_c); 1053 const std::string op_c = VisitOperand(operation, 2).As(type_c);
938 const std::string op_str = fmt::format("{}({}, {}, {})", func, op_a, op_b, op_c); 1054 std::string op_str = fmt::format("{}({}, {}, {})", func, op_a, op_b, op_c);
939 1055
940 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1056 return ApplyPrecise(operation, std::move(op_str), result_type);
941 } 1057 }
942 1058
943 std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, 1059 Expression GenerateQuaternary(Operation operation, const std::string& func, Type result_type,
944 Type type_a, Type type_b, Type type_c, Type type_d) { 1060 Type type_a, Type type_b, Type type_c, Type type_d) {
945 const std::string op_a = VisitOperand(operation, 0, type_a); 1061 const std::string op_a = VisitOperand(operation, 0).As(type_a);
946 const std::string op_b = VisitOperand(operation, 1, type_b); 1062 const std::string op_b = VisitOperand(operation, 1).As(type_b);
947 const std::string op_c = VisitOperand(operation, 2, type_c); 1063 const std::string op_c = VisitOperand(operation, 2).As(type_c);
948 const std::string op_d = VisitOperand(operation, 3, type_d); 1064 const std::string op_d = VisitOperand(operation, 3).As(type_d);
949 const std::string op_str = fmt::format("{}({}, {}, {}, {})", func, op_a, op_b, op_c, op_d); 1065 std::string op_str = fmt::format("{}({}, {}, {}, {})", func, op_a, op_b, op_c, op_d);
950 1066
951 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1067 return ApplyPrecise(operation, std::move(op_str), result_type);
952 } 1068 }
953 1069
954 std::string GenerateTexture(Operation operation, const std::string& function_suffix, 1070 std::string GenerateTexture(Operation operation, const std::string& function_suffix,
955 const std::vector<TextureIR>& extras) { 1071 const std::vector<TextureIR>& extras) {
956 constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; 1072 constexpr std::array coord_constructors = {"float", "vec2", "vec3", "vec4"};
957 1073
958 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1074 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
959 ASSERT(meta); 1075 ASSERT(meta);
@@ -970,17 +1086,17 @@ private:
970 expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1); 1086 expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1);
971 expr += '('; 1087 expr += '(';
972 for (std::size_t i = 0; i < count; ++i) { 1088 for (std::size_t i = 0; i < count; ++i) {
973 expr += Visit(operation[i]); 1089 expr += Visit(operation[i]).AsFloat();
974 1090
975 const std::size_t next = i + 1; 1091 const std::size_t next = i + 1;
976 if (next < count) 1092 if (next < count)
977 expr += ", "; 1093 expr += ", ";
978 } 1094 }
979 if (has_array) { 1095 if (has_array) {
980 expr += ", float(ftoi(" + Visit(meta->array) + "))"; 1096 expr += ", float(" + Visit(meta->array).AsInt() + ')';
981 } 1097 }
982 if (has_shadow) { 1098 if (has_shadow) {
983 expr += ", " + Visit(meta->depth_compare); 1099 expr += ", " + Visit(meta->depth_compare).AsFloat();
984 } 1100 }
985 expr += ')'; 1101 expr += ')';
986 1102
@@ -1011,11 +1127,11 @@ private:
1011 // required to be constant) 1127 // required to be constant)
1012 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 1128 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
1013 } else { 1129 } else {
1014 expr += fmt::format("ftoi({})", Visit(operand)); 1130 expr += Visit(operand).AsInt();
1015 } 1131 }
1016 break; 1132 break;
1017 case Type::Float: 1133 case Type::Float:
1018 expr += Visit(operand); 1134 expr += Visit(operand).AsFloat();
1019 break; 1135 break;
1020 default: { 1136 default: {
1021 const auto type_int = static_cast<u32>(type); 1137 const auto type_int = static_cast<u32>(type);
@@ -1031,7 +1147,7 @@ private:
1031 if (aoffi.empty()) { 1147 if (aoffi.empty()) {
1032 return {}; 1148 return {};
1033 } 1149 }
1034 constexpr std::array<const char*, 3> coord_constructors = {"int", "ivec2", "ivec3"}; 1150 constexpr std::array coord_constructors = {"int", "ivec2", "ivec3"};
1035 std::string expr = ", "; 1151 std::string expr = ", ";
1036 expr += coord_constructors.at(aoffi.size() - 1); 1152 expr += coord_constructors.at(aoffi.size() - 1);
1037 expr += '('; 1153 expr += '(';
@@ -1044,7 +1160,7 @@ private:
1044 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 1160 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
1045 } else if (device.HasVariableAoffi()) { 1161 } else if (device.HasVariableAoffi()) {
1046 // Avoid using variable AOFFI on unsupported devices. 1162 // Avoid using variable AOFFI on unsupported devices.
1047 expr += fmt::format("ftoi({})", Visit(operand)); 1163 expr += Visit(operand).AsInt();
1048 } else { 1164 } else {
1049 // Insert 0 on devices not supporting variable AOFFI. 1165 // Insert 0 on devices not supporting variable AOFFI.
1050 expr += '0'; 1166 expr += '0';
@@ -1058,328 +1174,314 @@ private:
1058 return expr; 1174 return expr;
1059 } 1175 }
1060 1176
1061 std::string Assign(Operation operation) { 1177 Expression Assign(Operation operation) {
1062 const Node& dest = operation[0]; 1178 const Node& dest = operation[0];
1063 const Node& src = operation[1]; 1179 const Node& src = operation[1];
1064 1180
1065 std::string target; 1181 Expression target;
1066 bool is_integer = false;
1067
1068 if (const auto gpr = std::get_if<GprNode>(&*dest)) { 1182 if (const auto gpr = std::get_if<GprNode>(&*dest)) {
1069 if (gpr->GetIndex() == Register::ZeroIndex) { 1183 if (gpr->GetIndex() == Register::ZeroIndex) {
1070 // Writing to Register::ZeroIndex is a no op 1184 // Writing to Register::ZeroIndex is a no op
1071 return {}; 1185 return {};
1072 } 1186 }
1073 target = GetRegister(gpr->GetIndex()); 1187 target = {GetRegister(gpr->GetIndex()), Type::Float};
1074 } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { 1188 } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
1075 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); 1189 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
1076 const auto result = GetOutputAttribute(abuf); 1190 target = GetOutputAttribute(abuf);
1077 if (!result) {
1078 return {};
1079 }
1080 target = result->first;
1081 is_integer = result->second;
1082 } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) { 1191 } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
1083 if (stage == ProgramType::Compute) { 1192 if (stage == ProgramType::Compute) {
1084 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders"); 1193 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders");
1085 } 1194 }
1086 target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); 1195 target = {
1196 fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
1197 Type::Uint};
1087 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { 1198 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
1088 const std::string real = Visit(gmem->GetRealAddress()); 1199 const std::string real = Visit(gmem->GetRealAddress()).AsUint();
1089 const std::string base = Visit(gmem->GetBaseAddress()); 1200 const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
1090 const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); 1201 const std::string final_offset = fmt::format("({} - {}) >> 2", real, base);
1091 target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); 1202 target = {fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset),
1203 Type::Uint};
1092 } else { 1204 } else {
1093 UNREACHABLE_MSG("Assign called without a proper target"); 1205 UNREACHABLE_MSG("Assign called without a proper target");
1094 } 1206 }
1095 1207
1096 if (is_integer) { 1208 code.AddLine("{} = {};", target.GetCode(), Visit(src).As(target.GetType()));
1097 code.AddLine("{} = ftoi({});", target, Visit(src));
1098 } else {
1099 code.AddLine("{} = {};", target, Visit(src));
1100 }
1101 return {}; 1209 return {};
1102 } 1210 }
1103 1211
1104 template <Type type> 1212 template <Type type>
1105 std::string Add(Operation operation) { 1213 Expression Add(Operation operation) {
1106 return GenerateBinaryInfix(operation, "+", type, type, type); 1214 return GenerateBinaryInfix(operation, "+", type, type, type);
1107 } 1215 }
1108 1216
1109 template <Type type> 1217 template <Type type>
1110 std::string Mul(Operation operation) { 1218 Expression Mul(Operation operation) {
1111 return GenerateBinaryInfix(operation, "*", type, type, type); 1219 return GenerateBinaryInfix(operation, "*", type, type, type);
1112 } 1220 }
1113 1221
1114 template <Type type> 1222 template <Type type>
1115 std::string Div(Operation operation) { 1223 Expression Div(Operation operation) {
1116 return GenerateBinaryInfix(operation, "/", type, type, type); 1224 return GenerateBinaryInfix(operation, "/", type, type, type);
1117 } 1225 }
1118 1226
1119 template <Type type> 1227 template <Type type>
1120 std::string Fma(Operation operation) { 1228 Expression Fma(Operation operation) {
1121 return GenerateTernary(operation, "fma", type, type, type, type); 1229 return GenerateTernary(operation, "fma", type, type, type, type);
1122 } 1230 }
1123 1231
1124 template <Type type> 1232 template <Type type>
1125 std::string Negate(Operation operation) { 1233 Expression Negate(Operation operation) {
1126 return GenerateUnary(operation, "-", type, type, true); 1234 return GenerateUnary(operation, "-", type, type);
1127 } 1235 }
1128 1236
1129 template <Type type> 1237 template <Type type>
1130 std::string Absolute(Operation operation) { 1238 Expression Absolute(Operation operation) {
1131 return GenerateUnary(operation, "abs", type, type, false); 1239 return GenerateUnary(operation, "abs", type, type);
1132 } 1240 }
1133 1241
1134 std::string FClamp(Operation operation) { 1242 Expression FClamp(Operation operation) {
1135 return GenerateTernary(operation, "clamp", Type::Float, Type::Float, Type::Float, 1243 return GenerateTernary(operation, "clamp", Type::Float, Type::Float, Type::Float,
1136 Type::Float); 1244 Type::Float);
1137 } 1245 }
1138 1246
1139 std::string FCastHalf0(Operation operation) { 1247 Expression FCastHalf0(Operation operation) {
1140 const std::string op_a = VisitOperand(operation, 0, Type::HalfFloat); 1248 return {fmt::format("({})[0]", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1141 return fmt::format("({})[0]", op_a);
1142 } 1249 }
1143 1250
1144 std::string FCastHalf1(Operation operation) { 1251 Expression FCastHalf1(Operation operation) {
1145 const std::string op_a = VisitOperand(operation, 0, Type::HalfFloat); 1252 return {fmt::format("({})[1]", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1146 return fmt::format("({})[1]", op_a);
1147 } 1253 }
1148 1254
1149 template <Type type> 1255 template <Type type>
1150 std::string Min(Operation operation) { 1256 Expression Min(Operation operation) {
1151 return GenerateBinaryCall(operation, "min", type, type, type); 1257 return GenerateBinaryCall(operation, "min", type, type, type);
1152 } 1258 }
1153 1259
1154 template <Type type> 1260 template <Type type>
1155 std::string Max(Operation operation) { 1261 Expression Max(Operation operation) {
1156 return GenerateBinaryCall(operation, "max", type, type, type); 1262 return GenerateBinaryCall(operation, "max", type, type, type);
1157 } 1263 }
1158 1264
1159 std::string Select(Operation operation) { 1265 Expression Select(Operation operation) {
1160 const std::string condition = Visit(operation[0]); 1266 const std::string condition = Visit(operation[0]).AsBool();
1161 const std::string true_case = Visit(operation[1]); 1267 const std::string true_case = Visit(operation[1]).AsUint();
1162 const std::string false_case = Visit(operation[2]); 1268 const std::string false_case = Visit(operation[2]).AsUint();
1163 const std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case); 1269 std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case);
1164 1270
1165 return ApplyPrecise(operation, op_str); 1271 return ApplyPrecise(operation, std::move(op_str), Type::Uint);
1166 } 1272 }
1167 1273
1168 std::string FCos(Operation operation) { 1274 Expression FCos(Operation operation) {
1169 return GenerateUnary(operation, "cos", Type::Float, Type::Float, false); 1275 return GenerateUnary(operation, "cos", Type::Float, Type::Float);
1170 } 1276 }
1171 1277
1172 std::string FSin(Operation operation) { 1278 Expression FSin(Operation operation) {
1173 return GenerateUnary(operation, "sin", Type::Float, Type::Float, false); 1279 return GenerateUnary(operation, "sin", Type::Float, Type::Float);
1174 } 1280 }
1175 1281
1176 std::string FExp2(Operation operation) { 1282 Expression FExp2(Operation operation) {
1177 return GenerateUnary(operation, "exp2", Type::Float, Type::Float, false); 1283 return GenerateUnary(operation, "exp2", Type::Float, Type::Float);
1178 } 1284 }
1179 1285
1180 std::string FLog2(Operation operation) { 1286 Expression FLog2(Operation operation) {
1181 return GenerateUnary(operation, "log2", Type::Float, Type::Float, false); 1287 return GenerateUnary(operation, "log2", Type::Float, Type::Float);
1182 } 1288 }
1183 1289
1184 std::string FInverseSqrt(Operation operation) { 1290 Expression FInverseSqrt(Operation operation) {
1185 return GenerateUnary(operation, "inversesqrt", Type::Float, Type::Float, false); 1291 return GenerateUnary(operation, "inversesqrt", Type::Float, Type::Float);
1186 } 1292 }
1187 1293
1188 std::string FSqrt(Operation operation) { 1294 Expression FSqrt(Operation operation) {
1189 return GenerateUnary(operation, "sqrt", Type::Float, Type::Float, false); 1295 return GenerateUnary(operation, "sqrt", Type::Float, Type::Float);
1190 } 1296 }
1191 1297
1192 std::string FRoundEven(Operation operation) { 1298 Expression FRoundEven(Operation operation) {
1193 return GenerateUnary(operation, "roundEven", Type::Float, Type::Float, false); 1299 return GenerateUnary(operation, "roundEven", Type::Float, Type::Float);
1194 } 1300 }
1195 1301
1196 std::string FFloor(Operation operation) { 1302 Expression FFloor(Operation operation) {
1197 return GenerateUnary(operation, "floor", Type::Float, Type::Float, false); 1303 return GenerateUnary(operation, "floor", Type::Float, Type::Float);
1198 } 1304 }
1199 1305
1200 std::string FCeil(Operation operation) { 1306 Expression FCeil(Operation operation) {
1201 return GenerateUnary(operation, "ceil", Type::Float, Type::Float, false); 1307 return GenerateUnary(operation, "ceil", Type::Float, Type::Float);
1202 } 1308 }
1203 1309
1204 std::string FTrunc(Operation operation) { 1310 Expression FTrunc(Operation operation) {
1205 return GenerateUnary(operation, "trunc", Type::Float, Type::Float, false); 1311 return GenerateUnary(operation, "trunc", Type::Float, Type::Float);
1206 } 1312 }
1207 1313
1208 template <Type type> 1314 template <Type type>
1209 std::string FCastInteger(Operation operation) { 1315 Expression FCastInteger(Operation operation) {
1210 return GenerateUnary(operation, "float", Type::Float, type, false); 1316 return GenerateUnary(operation, "float", Type::Float, type);
1211 } 1317 }
1212 1318
1213 std::string ICastFloat(Operation operation) { 1319 Expression ICastFloat(Operation operation) {
1214 return GenerateUnary(operation, "int", Type::Int, Type::Float, false); 1320 return GenerateUnary(operation, "int", Type::Int, Type::Float);
1215 } 1321 }
1216 1322
1217 std::string ICastUnsigned(Operation operation) { 1323 Expression ICastUnsigned(Operation operation) {
1218 return GenerateUnary(operation, "int", Type::Int, Type::Uint, false); 1324 return GenerateUnary(operation, "int", Type::Int, Type::Uint);
1219 } 1325 }
1220 1326
1221 template <Type type> 1327 template <Type type>
1222 std::string LogicalShiftLeft(Operation operation) { 1328 Expression LogicalShiftLeft(Operation operation) {
1223 return GenerateBinaryInfix(operation, "<<", type, type, Type::Uint); 1329 return GenerateBinaryInfix(operation, "<<", type, type, Type::Uint);
1224 } 1330 }
1225 1331
1226 std::string ILogicalShiftRight(Operation operation) { 1332 Expression ILogicalShiftRight(Operation operation) {
1227 const std::string op_a = VisitOperand(operation, 0, Type::Uint); 1333 const std::string op_a = VisitOperand(operation, 0).AsUint();
1228 const std::string op_b = VisitOperand(operation, 1, Type::Uint); 1334 const std::string op_b = VisitOperand(operation, 1).AsUint();
1229 const std::string op_str = fmt::format("int({} >> {})", op_a, op_b); 1335 std::string op_str = fmt::format("int({} >> {})", op_a, op_b);
1230 1336
1231 return ApplyPrecise(operation, BitwiseCastResult(op_str, Type::Int)); 1337 return ApplyPrecise(operation, std::move(op_str), Type::Int);
1232 } 1338 }
1233 1339
1234 std::string IArithmeticShiftRight(Operation operation) { 1340 Expression IArithmeticShiftRight(Operation operation) {
1235 return GenerateBinaryInfix(operation, ">>", Type::Int, Type::Int, Type::Uint); 1341 return GenerateBinaryInfix(operation, ">>", Type::Int, Type::Int, Type::Uint);
1236 } 1342 }
1237 1343
1238 template <Type type> 1344 template <Type type>
1239 std::string BitwiseAnd(Operation operation) { 1345 Expression BitwiseAnd(Operation operation) {
1240 return GenerateBinaryInfix(operation, "&", type, type, type); 1346 return GenerateBinaryInfix(operation, "&", type, type, type);
1241 } 1347 }
1242 1348
1243 template <Type type> 1349 template <Type type>
1244 std::string BitwiseOr(Operation operation) { 1350 Expression BitwiseOr(Operation operation) {
1245 return GenerateBinaryInfix(operation, "|", type, type, type); 1351 return GenerateBinaryInfix(operation, "|", type, type, type);
1246 } 1352 }
1247 1353
1248 template <Type type> 1354 template <Type type>
1249 std::string BitwiseXor(Operation operation) { 1355 Expression BitwiseXor(Operation operation) {
1250 return GenerateBinaryInfix(operation, "^", type, type, type); 1356 return GenerateBinaryInfix(operation, "^", type, type, type);
1251 } 1357 }
1252 1358
1253 template <Type type> 1359 template <Type type>
1254 std::string BitwiseNot(Operation operation) { 1360 Expression BitwiseNot(Operation operation) {
1255 return GenerateUnary(operation, "~", type, type, false); 1361 return GenerateUnary(operation, "~", type, type);
1256 } 1362 }
1257 1363
1258 std::string UCastFloat(Operation operation) { 1364 Expression UCastFloat(Operation operation) {
1259 return GenerateUnary(operation, "uint", Type::Uint, Type::Float, false); 1365 return GenerateUnary(operation, "uint", Type::Uint, Type::Float);
1260 } 1366 }
1261 1367
1262 std::string UCastSigned(Operation operation) { 1368 Expression UCastSigned(Operation operation) {
1263 return GenerateUnary(operation, "uint", Type::Uint, Type::Int, false); 1369 return GenerateUnary(operation, "uint", Type::Uint, Type::Int);
1264 } 1370 }
1265 1371
1266 std::string UShiftRight(Operation operation) { 1372 Expression UShiftRight(Operation operation) {
1267 return GenerateBinaryInfix(operation, ">>", Type::Uint, Type::Uint, Type::Uint); 1373 return GenerateBinaryInfix(operation, ">>", Type::Uint, Type::Uint, Type::Uint);
1268 } 1374 }
1269 1375
1270 template <Type type> 1376 template <Type type>
1271 std::string BitfieldInsert(Operation operation) { 1377 Expression BitfieldInsert(Operation operation) {
1272 return GenerateQuaternary(operation, "bitfieldInsert", type, type, type, Type::Int, 1378 return GenerateQuaternary(operation, "bitfieldInsert", type, type, type, Type::Int,
1273 Type::Int); 1379 Type::Int);
1274 } 1380 }
1275 1381
1276 template <Type type> 1382 template <Type type>
1277 std::string BitfieldExtract(Operation operation) { 1383 Expression BitfieldExtract(Operation operation) {
1278 return GenerateTernary(operation, "bitfieldExtract", type, type, Type::Int, Type::Int); 1384 return GenerateTernary(operation, "bitfieldExtract", type, type, Type::Int, Type::Int);
1279 } 1385 }
1280 1386
1281 template <Type type> 1387 template <Type type>
1282 std::string BitCount(Operation operation) { 1388 Expression BitCount(Operation operation) {
1283 return GenerateUnary(operation, "bitCount", type, type, false); 1389 return GenerateUnary(operation, "bitCount", type, type);
1284 } 1390 }
1285 1391
1286 std::string HNegate(Operation operation) { 1392 Expression HNegate(Operation operation) {
1287 const auto GetNegate = [&](std::size_t index) { 1393 const auto GetNegate = [&](std::size_t index) {
1288 return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; 1394 return VisitOperand(operation, index).AsBool() + " ? -1 : 1";
1289 }; 1395 };
1290 const std::string value = 1396 return {fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0).AsHalfFloat(),
1291 fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0, Type::HalfFloat), 1397 GetNegate(1), GetNegate(2)),
1292 GetNegate(1), GetNegate(2)); 1398 Type::HalfFloat};
1293 return BitwiseCastResult(value, Type::HalfFloat); 1399 }
1294 } 1400
1295 1401 Expression HClamp(Operation operation) {
1296 std::string HClamp(Operation operation) { 1402 const std::string value = VisitOperand(operation, 0).AsHalfFloat();
1297 const std::string value = VisitOperand(operation, 0, Type::HalfFloat); 1403 const std::string min = VisitOperand(operation, 1).AsFloat();
1298 const std::string min = VisitOperand(operation, 1, Type::Float); 1404 const std::string max = VisitOperand(operation, 2).AsFloat();
1299 const std::string max = VisitOperand(operation, 2, Type::Float); 1405 std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max);
1300 const std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max); 1406
1301 1407 return ApplyPrecise(operation, std::move(clamped), Type::HalfFloat);
1302 return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); 1408 }
1303 } 1409
1304 1410 Expression HCastFloat(Operation operation) {
1305 std::string HCastFloat(Operation operation) { 1411 return {fmt::format("vec2({})", VisitOperand(operation, 0).AsFloat()), Type::HalfFloat};
1306 const std::string op_a = VisitOperand(operation, 0, Type::Float); 1412 }
1307 return fmt::format("fromHalf2(vec2({}, 0.0f))", op_a); 1413
1308 } 1414 Expression HUnpack(Operation operation) {
1309 1415 Expression operand = VisitOperand(operation, 0);
1310 std::string HUnpack(Operation operation) { 1416 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) {
1311 const std::string operand{VisitOperand(operation, 0, Type::HalfFloat)}; 1417 case Tegra::Shader::HalfType::H0_H1:
1312 const auto value = [&]() -> std::string { 1418 return operand;
1313 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { 1419 case Tegra::Shader::HalfType::F32:
1314 case Tegra::Shader::HalfType::H0_H1: 1420 return {fmt::format("vec2({})", operand.AsFloat()), Type::HalfFloat};
1315 return operand; 1421 case Tegra::Shader::HalfType::H0_H0:
1316 case Tegra::Shader::HalfType::F32: 1422 return {fmt::format("vec2({}[0])", operand.AsHalfFloat()), Type::HalfFloat};
1317 return fmt::format("vec2(fromHalf2({}))", operand); 1423 case Tegra::Shader::HalfType::H1_H1:
1318 case Tegra::Shader::HalfType::H0_H0: 1424 return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat};
1319 return fmt::format("vec2({}[0])", operand); 1425 }
1320 case Tegra::Shader::HalfType::H1_H1:
1321 return fmt::format("vec2({}[1])", operand);
1322 }
1323 UNREACHABLE();
1324 return "0";
1325 }();
1326 return fmt::format("fromHalf2({})", value);
1327 } 1426 }
1328 1427
1329 std::string HMergeF32(Operation operation) { 1428 Expression HMergeF32(Operation operation) {
1330 return fmt::format("float(toHalf2({})[0])", Visit(operation[0])); 1429 return {fmt::format("float({}[0])", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1331 } 1430 }
1332 1431
1333 std::string HMergeH0(Operation operation) { 1432 Expression HMergeH0(Operation operation) {
1334 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[1]), 1433 std::string dest = VisitOperand(operation, 0).AsUint();
1335 Visit(operation[0])); 1434 std::string src = VisitOperand(operation, 1).AsUint();
1435 return {fmt::format("(({} & 0x0000FFFFU) | ({} & 0xFFFF0000U))", src, dest), Type::Uint};
1336 } 1436 }
1337 1437
1338 std::string HMergeH1(Operation operation) { 1438 Expression HMergeH1(Operation operation) {
1339 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[0]), 1439 std::string dest = VisitOperand(operation, 0).AsUint();
1340 Visit(operation[1])); 1440 std::string src = VisitOperand(operation, 1).AsUint();
1441 return {fmt::format("(({} & 0x0000FFFFU) | ({} & 0xFFFF0000U))", dest, src), Type::Uint};
1341 } 1442 }
1342 1443
1343 std::string HPack2(Operation operation) { 1444 Expression HPack2(Operation operation) {
1344 return fmt::format("utof(packHalf2x16(vec2({}, {})))", Visit(operation[0]), 1445 return {fmt::format("vec2({}, {})", VisitOperand(operation, 0).AsFloat(),
1345 Visit(operation[1])); 1446 VisitOperand(operation, 1).AsFloat()),
1447 Type::HalfFloat};
1346 } 1448 }
1347 1449
1348 template <Type type> 1450 template <Type type>
1349 std::string LogicalLessThan(Operation operation) { 1451 Expression LogicalLessThan(Operation operation) {
1350 return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); 1452 return GenerateBinaryInfix(operation, "<", Type::Bool, type, type);
1351 } 1453 }
1352 1454
1353 template <Type type> 1455 template <Type type>
1354 std::string LogicalEqual(Operation operation) { 1456 Expression LogicalEqual(Operation operation) {
1355 return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); 1457 return GenerateBinaryInfix(operation, "==", Type::Bool, type, type);
1356 } 1458 }
1357 1459
1358 template <Type type> 1460 template <Type type>
1359 std::string LogicalLessEqual(Operation operation) { 1461 Expression LogicalLessEqual(Operation operation) {
1360 return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); 1462 return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type);
1361 } 1463 }
1362 1464
1363 template <Type type> 1465 template <Type type>
1364 std::string LogicalGreaterThan(Operation operation) { 1466 Expression LogicalGreaterThan(Operation operation) {
1365 return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); 1467 return GenerateBinaryInfix(operation, ">", Type::Bool, type, type);
1366 } 1468 }
1367 1469
1368 template <Type type> 1470 template <Type type>
1369 std::string LogicalNotEqual(Operation operation) { 1471 Expression LogicalNotEqual(Operation operation) {
1370 return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); 1472 return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type);
1371 } 1473 }
1372 1474
1373 template <Type type> 1475 template <Type type>
1374 std::string LogicalGreaterEqual(Operation operation) { 1476 Expression LogicalGreaterEqual(Operation operation) {
1375 return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); 1477 return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type);
1376 } 1478 }
1377 1479
1378 std::string LogicalFIsNan(Operation operation) { 1480 Expression LogicalFIsNan(Operation operation) {
1379 return GenerateUnary(operation, "isnan", Type::Bool, Type::Float, false); 1481 return GenerateUnary(operation, "isnan", Type::Bool, Type::Float);
1380 } 1482 }
1381 1483
1382 std::string LogicalAssign(Operation operation) { 1484 Expression LogicalAssign(Operation operation) {
1383 const Node& dest = operation[0]; 1485 const Node& dest = operation[0];
1384 const Node& src = operation[1]; 1486 const Node& src = operation[1];
1385 1487
@@ -1400,78 +1502,80 @@ private:
1400 target = GetInternalFlag(flag->GetFlag()); 1502 target = GetInternalFlag(flag->GetFlag());
1401 } 1503 }
1402 1504
1403 code.AddLine("{} = {};", target, Visit(src)); 1505 code.AddLine("{} = {};", target, Visit(src).AsBool());
1404 return {}; 1506 return {};
1405 } 1507 }
1406 1508
1407 std::string LogicalAnd(Operation operation) { 1509 Expression LogicalAnd(Operation operation) {
1408 return GenerateBinaryInfix(operation, "&&", Type::Bool, Type::Bool, Type::Bool); 1510 return GenerateBinaryInfix(operation, "&&", Type::Bool, Type::Bool, Type::Bool);
1409 } 1511 }
1410 1512
1411 std::string LogicalOr(Operation operation) { 1513 Expression LogicalOr(Operation operation) {
1412 return GenerateBinaryInfix(operation, "||", Type::Bool, Type::Bool, Type::Bool); 1514 return GenerateBinaryInfix(operation, "||", Type::Bool, Type::Bool, Type::Bool);
1413 } 1515 }
1414 1516
1415 std::string LogicalXor(Operation operation) { 1517 Expression LogicalXor(Operation operation) {
1416 return GenerateBinaryInfix(operation, "^^", Type::Bool, Type::Bool, Type::Bool); 1518 return GenerateBinaryInfix(operation, "^^", Type::Bool, Type::Bool, Type::Bool);
1417 } 1519 }
1418 1520
1419 std::string LogicalNegate(Operation operation) { 1521 Expression LogicalNegate(Operation operation) {
1420 return GenerateUnary(operation, "!", Type::Bool, Type::Bool, false); 1522 return GenerateUnary(operation, "!", Type::Bool, Type::Bool);
1421 } 1523 }
1422 1524
1423 std::string LogicalPick2(Operation operation) { 1525 Expression LogicalPick2(Operation operation) {
1424 const std::string pair = VisitOperand(operation, 0, Type::Bool2); 1526 return {fmt::format("{}[{}]", VisitOperand(operation, 0).AsBool2(),
1425 return fmt::format("{}[{}]", pair, VisitOperand(operation, 1, Type::Uint)); 1527 VisitOperand(operation, 1).AsUint()),
1528 Type::Bool};
1426 } 1529 }
1427 1530
1428 std::string LogicalAnd2(Operation operation) { 1531 Expression LogicalAnd2(Operation operation) {
1429 return GenerateUnary(operation, "all", Type::Bool, Type::Bool2); 1532 return GenerateUnary(operation, "all", Type::Bool, Type::Bool2);
1430 } 1533 }
1431 1534
1432 template <bool with_nan> 1535 template <bool with_nan>
1433 std::string GenerateHalfComparison(Operation operation, const std::string& compare_op) { 1536 Expression GenerateHalfComparison(Operation operation, std::string_view compare_op) {
1434 const std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, 1537 Expression comparison = GenerateBinaryCall(operation, compare_op, Type::Bool2,
1435 Type::HalfFloat, Type::HalfFloat)}; 1538 Type::HalfFloat, Type::HalfFloat);
1436 if constexpr (!with_nan) { 1539 if constexpr (!with_nan) {
1437 return comparison; 1540 return comparison;
1438 } 1541 }
1439 return fmt::format("halfFloatNanComparison({}, {}, {})", comparison, 1542 return {fmt::format("HalfFloatNanComparison({}, {}, {})", comparison.AsBool2(),
1440 VisitOperand(operation, 0, Type::HalfFloat), 1543 VisitOperand(operation, 0).AsHalfFloat(),
1441 VisitOperand(operation, 1, Type::HalfFloat)); 1544 VisitOperand(operation, 1).AsHalfFloat()),
1545 Type::Bool2};
1442 } 1546 }
1443 1547
1444 template <bool with_nan> 1548 template <bool with_nan>
1445 std::string Logical2HLessThan(Operation operation) { 1549 Expression Logical2HLessThan(Operation operation) {
1446 return GenerateHalfComparison<with_nan>(operation, "lessThan"); 1550 return GenerateHalfComparison<with_nan>(operation, "lessThan");
1447 } 1551 }
1448 1552
1449 template <bool with_nan> 1553 template <bool with_nan>
1450 std::string Logical2HEqual(Operation operation) { 1554 Expression Logical2HEqual(Operation operation) {
1451 return GenerateHalfComparison<with_nan>(operation, "equal"); 1555 return GenerateHalfComparison<with_nan>(operation, "equal");
1452 } 1556 }
1453 1557
1454 template <bool with_nan> 1558 template <bool with_nan>
1455 std::string Logical2HLessEqual(Operation operation) { 1559 Expression Logical2HLessEqual(Operation operation) {
1456 return GenerateHalfComparison<with_nan>(operation, "lessThanEqual"); 1560 return GenerateHalfComparison<with_nan>(operation, "lessThanEqual");
1457 } 1561 }
1458 1562
1459 template <bool with_nan> 1563 template <bool with_nan>
1460 std::string Logical2HGreaterThan(Operation operation) { 1564 Expression Logical2HGreaterThan(Operation operation) {
1461 return GenerateHalfComparison<with_nan>(operation, "greaterThan"); 1565 return GenerateHalfComparison<with_nan>(operation, "greaterThan");
1462 } 1566 }
1463 1567
1464 template <bool with_nan> 1568 template <bool with_nan>
1465 std::string Logical2HNotEqual(Operation operation) { 1569 Expression Logical2HNotEqual(Operation operation) {
1466 return GenerateHalfComparison<with_nan>(operation, "notEqual"); 1570 return GenerateHalfComparison<with_nan>(operation, "notEqual");
1467 } 1571 }
1468 1572
1469 template <bool with_nan> 1573 template <bool with_nan>
1470 std::string Logical2HGreaterEqual(Operation operation) { 1574 Expression Logical2HGreaterEqual(Operation operation) {
1471 return GenerateHalfComparison<with_nan>(operation, "greaterThanEqual"); 1575 return GenerateHalfComparison<with_nan>(operation, "greaterThanEqual");
1472 } 1576 }
1473 1577
1474 std::string Texture(Operation operation) { 1578 Expression Texture(Operation operation) {
1475 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1579 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1476 ASSERT(meta); 1580 ASSERT(meta);
1477 1581
@@ -1480,10 +1584,10 @@ private:
1480 if (meta->sampler.IsShadow()) { 1584 if (meta->sampler.IsShadow()) {
1481 expr = "vec4(" + expr + ')'; 1585 expr = "vec4(" + expr + ')';
1482 } 1586 }
1483 return expr + GetSwizzle(meta->element); 1587 return {expr + GetSwizzle(meta->element), Type::Float};
1484 } 1588 }
1485 1589
1486 std::string TextureLod(Operation operation) { 1590 Expression TextureLod(Operation operation) {
1487 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1591 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1488 ASSERT(meta); 1592 ASSERT(meta);
1489 1593
@@ -1492,54 +1596,54 @@ private:
1492 if (meta->sampler.IsShadow()) { 1596 if (meta->sampler.IsShadow()) {
1493 expr = "vec4(" + expr + ')'; 1597 expr = "vec4(" + expr + ')';
1494 } 1598 }
1495 return expr + GetSwizzle(meta->element); 1599 return {expr + GetSwizzle(meta->element), Type::Float};
1496 } 1600 }
1497 1601
1498 std::string TextureGather(Operation operation) { 1602 Expression TextureGather(Operation operation) {
1499 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1603 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1500 ASSERT(meta); 1604 ASSERT(meta);
1501 1605
1502 const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int; 1606 const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int;
1503 return GenerateTexture(operation, "Gather", 1607 return {GenerateTexture(operation, "Gather",
1504 {TextureArgument{type, meta->component}, TextureAoffi{}}) + 1608 {TextureArgument{type, meta->component}, TextureAoffi{}}) +
1505 GetSwizzle(meta->element); 1609 GetSwizzle(meta->element),
1610 Type::Float};
1506 } 1611 }
1507 1612
1508 std::string TextureQueryDimensions(Operation operation) { 1613 Expression TextureQueryDimensions(Operation operation) {
1509 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1614 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1510 ASSERT(meta); 1615 ASSERT(meta);
1511 1616
1512 const std::string sampler = GetSampler(meta->sampler); 1617 const std::string sampler = GetSampler(meta->sampler);
1513 const std::string lod = VisitOperand(operation, 0, Type::Int); 1618 const std::string lod = VisitOperand(operation, 0).AsInt();
1514 1619
1515 switch (meta->element) { 1620 switch (meta->element) {
1516 case 0: 1621 case 0:
1517 case 1: 1622 case 1:
1518 return fmt::format("itof(int(textureSize({}, {}){}))", sampler, lod, 1623 return {fmt::format("textureSize({}, {}){}", sampler, lod, GetSwizzle(meta->element)),
1519 GetSwizzle(meta->element)); 1624 Type::Int};
1520 case 2:
1521 return "0";
1522 case 3: 1625 case 3:
1523 return fmt::format("itof(textureQueryLevels({}))", sampler); 1626 return {fmt::format("textureQueryLevels({})", sampler), Type::Int};
1524 } 1627 }
1525 UNREACHABLE(); 1628 UNREACHABLE();
1526 return "0"; 1629 return {"0", Type::Int};
1527 } 1630 }
1528 1631
1529 std::string TextureQueryLod(Operation operation) { 1632 Expression TextureQueryLod(Operation operation) {
1530 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1633 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1531 ASSERT(meta); 1634 ASSERT(meta);
1532 1635
1533 if (meta->element < 2) { 1636 if (meta->element < 2) {
1534 return fmt::format("itof(int(({} * vec2(256)){}))", 1637 return {fmt::format("int(({} * vec2(256)){})",
1535 GenerateTexture(operation, "QueryLod", {}), 1638 GenerateTexture(operation, "QueryLod", {}),
1536 GetSwizzle(meta->element)); 1639 GetSwizzle(meta->element)),
1640 Type::Int};
1537 } 1641 }
1538 return "0"; 1642 return {"0", Type::Int};
1539 } 1643 }
1540 1644
1541 std::string TexelFetch(Operation operation) { 1645 Expression TexelFetch(Operation operation) {
1542 constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; 1646 constexpr std::array constructors = {"int", "ivec2", "ivec3", "ivec4"};
1543 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1647 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1544 ASSERT(meta); 1648 ASSERT(meta);
1545 UNIMPLEMENTED_IF(meta->sampler.IsArray()); 1649 UNIMPLEMENTED_IF(meta->sampler.IsArray());
@@ -1552,7 +1656,7 @@ private:
1552 expr += constructors.at(operation.GetOperandsCount() - 1); 1656 expr += constructors.at(operation.GetOperandsCount() - 1);
1553 expr += '('; 1657 expr += '(';
1554 for (std::size_t i = 0; i < count; ++i) { 1658 for (std::size_t i = 0; i < count; ++i) {
1555 expr += VisitOperand(operation, i, Type::Int); 1659 expr += VisitOperand(operation, i).AsInt();
1556 const std::size_t next = i + 1; 1660 const std::size_t next = i + 1;
1557 if (next == count) 1661 if (next == count)
1558 expr += ')'; 1662 expr += ')';
@@ -1565,7 +1669,7 @@ private:
1565 1669
1566 if (meta->lod) { 1670 if (meta->lod) {
1567 expr += ", "; 1671 expr += ", ";
1568 expr += CastOperand(Visit(meta->lod), Type::Int); 1672 expr += Visit(meta->lod).AsInt();
1569 } 1673 }
1570 expr += ')'; 1674 expr += ')';
1571 expr += GetSwizzle(meta->element); 1675 expr += GetSwizzle(meta->element);
@@ -1580,11 +1684,11 @@ private:
1580 code.AddLine("float {} = {};", tmp, expr); 1684 code.AddLine("float {} = {};", tmp, expr);
1581 code.AddLine("#endif"); 1685 code.AddLine("#endif");
1582 1686
1583 return tmp; 1687 return {tmp, Type::Float};
1584 } 1688 }
1585 1689
1586 std::string ImageStore(Operation operation) { 1690 Expression ImageStore(Operation operation) {
1587 constexpr std::array<const char*, 4> constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; 1691 constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
1588 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1692 const auto meta{std::get<MetaImage>(operation.GetMeta())};
1589 1693
1590 std::string expr = "imageStore("; 1694 std::string expr = "imageStore(";
@@ -1594,7 +1698,7 @@ private:
1594 const std::size_t coords_count{operation.GetOperandsCount()}; 1698 const std::size_t coords_count{operation.GetOperandsCount()};
1595 expr += constructors.at(coords_count - 1); 1699 expr += constructors.at(coords_count - 1);
1596 for (std::size_t i = 0; i < coords_count; ++i) { 1700 for (std::size_t i = 0; i < coords_count; ++i) {
1597 expr += VisitOperand(operation, i, Type::Int); 1701 expr += VisitOperand(operation, i).AsInt();
1598 if (i + 1 < coords_count) { 1702 if (i + 1 < coords_count) {
1599 expr += ", "; 1703 expr += ", ";
1600 } 1704 }
@@ -1605,7 +1709,7 @@ private:
1605 UNIMPLEMENTED_IF(values_count != 4); 1709 UNIMPLEMENTED_IF(values_count != 4);
1606 expr += "vec4("; 1710 expr += "vec4(";
1607 for (std::size_t i = 0; i < values_count; ++i) { 1711 for (std::size_t i = 0; i < values_count; ++i) {
1608 expr += Visit(meta.values.at(i)); 1712 expr += Visit(meta.values.at(i)).AsFloat();
1609 if (i + 1 < values_count) { 1713 if (i + 1 < values_count) {
1610 expr += ", "; 1714 expr += ", ";
1611 } 1715 }
@@ -1616,52 +1720,52 @@ private:
1616 return {}; 1720 return {};
1617 } 1721 }
1618 1722
1619 std::string Branch(Operation operation) { 1723 Expression Branch(Operation operation) {
1620 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 1724 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
1621 UNIMPLEMENTED_IF(!target); 1725 UNIMPLEMENTED_IF(!target);
1622 1726
1623 code.AddLine("jmp_to = 0x{:x}u;", target->GetValue()); 1727 code.AddLine("jmp_to = 0x{:X}U;", target->GetValue());
1624 code.AddLine("break;"); 1728 code.AddLine("break;");
1625 return {}; 1729 return {};
1626 } 1730 }
1627 1731
1628 std::string BranchIndirect(Operation operation) { 1732 Expression BranchIndirect(Operation operation) {
1629 const std::string op_a = VisitOperand(operation, 0, Type::Uint); 1733 const std::string op_a = VisitOperand(operation, 0).AsUint();
1630 1734
1631 code.AddLine("jmp_to = {};", op_a); 1735 code.AddLine("jmp_to = {};", op_a);
1632 code.AddLine("break;"); 1736 code.AddLine("break;");
1633 return {}; 1737 return {};
1634 } 1738 }
1635 1739
1636 std::string PushFlowStack(Operation operation) { 1740 Expression PushFlowStack(Operation operation) {
1637 const auto stack = std::get<MetaStackClass>(operation.GetMeta()); 1741 const auto stack = std::get<MetaStackClass>(operation.GetMeta());
1638 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 1742 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
1639 UNIMPLEMENTED_IF(!target); 1743 UNIMPLEMENTED_IF(!target);
1640 1744
1641 code.AddLine("{}[{}++] = 0x{:x}u;", FlowStackName(stack), FlowStackTopName(stack), 1745 code.AddLine("{}[{}++] = 0x{:X}U;", FlowStackName(stack), FlowStackTopName(stack),
1642 target->GetValue()); 1746 target->GetValue());
1643 return {}; 1747 return {};
1644 } 1748 }
1645 1749
1646 std::string PopFlowStack(Operation operation) { 1750 Expression PopFlowStack(Operation operation) {
1647 const auto stack = std::get<MetaStackClass>(operation.GetMeta()); 1751 const auto stack = std::get<MetaStackClass>(operation.GetMeta());
1648 code.AddLine("jmp_to = {}[--{}];", FlowStackName(stack), FlowStackTopName(stack)); 1752 code.AddLine("jmp_to = {}[--{}];", FlowStackName(stack), FlowStackTopName(stack));
1649 code.AddLine("break;"); 1753 code.AddLine("break;");
1650 return {}; 1754 return {};
1651 } 1755 }
1652 1756
1653 std::string Exit(Operation operation) { 1757 Expression Exit(Operation operation) {
1654 if (stage != ProgramType::Fragment) { 1758 if (stage != ProgramType::Fragment) {
1655 code.AddLine("return;"); 1759 code.AddLine("return;");
1656 return {}; 1760 return {};
1657 } 1761 }
1658 const auto& used_registers = ir.GetRegisters(); 1762 const auto& used_registers = ir.GetRegisters();
1659 const auto SafeGetRegister = [&](u32 reg) -> std::string { 1763 const auto SafeGetRegister = [&](u32 reg) -> Expression {
1660 // TODO(Rodrigo): Replace with contains once C++20 releases 1764 // TODO(Rodrigo): Replace with contains once C++20 releases
1661 if (used_registers.find(reg) != used_registers.end()) { 1765 if (used_registers.find(reg) != used_registers.end()) {
1662 return GetRegister(reg); 1766 return {GetRegister(reg), Type::Float};
1663 } 1767 }
1664 return "0.0f"; 1768 return {"0.0f", Type::Float};
1665 }; 1769 };
1666 1770
1667 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); 1771 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented");
@@ -1674,7 +1778,7 @@ private:
1674 for (u32 component = 0; component < 4; ++component) { 1778 for (u32 component = 0; component < 4; ++component) {
1675 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { 1779 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) {
1676 code.AddLine("FragColor{}[{}] = {};", render_target, component, 1780 code.AddLine("FragColor{}[{}] = {};", render_target, component,
1677 SafeGetRegister(current_reg)); 1781 SafeGetRegister(current_reg).AsFloat());
1678 ++current_reg; 1782 ++current_reg;
1679 } 1783 }
1680 } 1784 }
@@ -1683,14 +1787,14 @@ private:
1683 if (header.ps.omap.depth) { 1787 if (header.ps.omap.depth) {
1684 // The depth output is always 2 registers after the last color output, and current_reg 1788 // The depth output is always 2 registers after the last color output, and current_reg
1685 // already contains one past the last color register. 1789 // already contains one past the last color register.
1686 code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1)); 1790 code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1).AsFloat());
1687 } 1791 }
1688 1792
1689 code.AddLine("return;"); 1793 code.AddLine("return;");
1690 return {}; 1794 return {};
1691 } 1795 }
1692 1796
1693 std::string Discard(Operation operation) { 1797 Expression Discard(Operation operation) {
1694 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 1798 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
1695 // about unexecuted instructions that may follow this. 1799 // about unexecuted instructions that may follow this.
1696 code.AddLine("if (true) {{"); 1800 code.AddLine("if (true) {{");
@@ -1701,7 +1805,7 @@ private:
1701 return {}; 1805 return {};
1702 } 1806 }
1703 1807
1704 std::string EmitVertex(Operation operation) { 1808 Expression EmitVertex(Operation operation) {
1705 ASSERT_MSG(stage == ProgramType::Geometry, 1809 ASSERT_MSG(stage == ProgramType::Geometry,
1706 "EmitVertex is expected to be used in a geometry shader."); 1810 "EmitVertex is expected to be used in a geometry shader.");
1707 1811
@@ -1712,7 +1816,7 @@ private:
1712 return {}; 1816 return {};
1713 } 1817 }
1714 1818
1715 std::string EndPrimitive(Operation operation) { 1819 Expression EndPrimitive(Operation operation) {
1716 ASSERT_MSG(stage == ProgramType::Geometry, 1820 ASSERT_MSG(stage == ProgramType::Geometry,
1717 "EndPrimitive is expected to be used in a geometry shader."); 1821 "EndPrimitive is expected to be used in a geometry shader.");
1718 1822
@@ -1720,59 +1824,59 @@ private:
1720 return {}; 1824 return {};
1721 } 1825 }
1722 1826
1723 std::string YNegate(Operation operation) { 1827 Expression YNegate(Operation operation) {
1724 // Config pack's third value is Y_NEGATE's state. 1828 // Config pack's third value is Y_NEGATE's state.
1725 return "uintBitsToFloat(config_pack[2])"; 1829 return {"config_pack[2]", Type::Uint};
1726 } 1830 }
1727 1831
1728 template <u32 element> 1832 template <u32 element>
1729 std::string LocalInvocationId(Operation) { 1833 Expression LocalInvocationId(Operation) {
1730 return "utof(gl_LocalInvocationID"s + GetSwizzle(element) + ')'; 1834 return {"gl_LocalInvocationID"s + GetSwizzle(element), Type::Uint};
1731 } 1835 }
1732 1836
1733 template <u32 element> 1837 template <u32 element>
1734 std::string WorkGroupId(Operation) { 1838 Expression WorkGroupId(Operation) {
1735 return "utof(gl_WorkGroupID"s + GetSwizzle(element) + ')'; 1839 return {"gl_WorkGroupID"s + GetSwizzle(element), Type::Uint};
1736 } 1840 }
1737 1841
1738 std::string BallotThread(Operation operation) { 1842 Expression BallotThread(Operation operation) {
1739 const std::string value = VisitOperand(operation, 0, Type::Bool); 1843 const std::string value = VisitOperand(operation, 0).AsBool();
1740 if (!device.HasWarpIntrinsics()) { 1844 if (!device.HasWarpIntrinsics()) {
1741 LOG_ERROR(Render_OpenGL, 1845 LOG_ERROR(Render_OpenGL,
1742 "Nvidia warp intrinsics are not available and its required by a shader"); 1846 "Nvidia warp intrinsics are not available and its required by a shader");
1743 // Stub on non-Nvidia devices by simulating all threads voting the same as the active 1847 // Stub on non-Nvidia devices by simulating all threads voting the same as the active
1744 // one. 1848 // one.
1745 return fmt::format("utof({} ? 0xFFFFFFFFU : 0U)", value); 1849 return {fmt::format("({} ? 0xFFFFFFFFU : 0U)", value), Type::Uint};
1746 } 1850 }
1747 return fmt::format("utof(ballotThreadNV({}))", value); 1851 return {fmt::format("ballotThreadNV({})", value), Type::Uint};
1748 } 1852 }
1749 1853
1750 std::string Vote(Operation operation, const char* func) { 1854 Expression Vote(Operation operation, const char* func) {
1751 const std::string value = VisitOperand(operation, 0, Type::Bool); 1855 const std::string value = VisitOperand(operation, 0).AsBool();
1752 if (!device.HasWarpIntrinsics()) { 1856 if (!device.HasWarpIntrinsics()) {
1753 LOG_ERROR(Render_OpenGL, 1857 LOG_ERROR(Render_OpenGL,
1754 "Nvidia vote intrinsics are not available and its required by a shader"); 1858 "Nvidia vote intrinsics are not available and its required by a shader");
1755 // Stub with a warp size of one. 1859 // Stub with a warp size of one.
1756 return value; 1860 return {value, Type::Bool};
1757 } 1861 }
1758 return fmt::format("{}({})", func, value); 1862 return {fmt::format("{}({})", func, value), Type::Bool};
1759 } 1863 }
1760 1864
1761 std::string VoteAll(Operation operation) { 1865 Expression VoteAll(Operation operation) {
1762 return Vote(operation, "allThreadsNV"); 1866 return Vote(operation, "allThreadsNV");
1763 } 1867 }
1764 1868
1765 std::string VoteAny(Operation operation) { 1869 Expression VoteAny(Operation operation) {
1766 return Vote(operation, "anyThreadNV"); 1870 return Vote(operation, "anyThreadNV");
1767 } 1871 }
1768 1872
1769 std::string VoteEqual(Operation operation) { 1873 Expression VoteEqual(Operation operation) {
1770 if (!device.HasWarpIntrinsics()) { 1874 if (!device.HasWarpIntrinsics()) {
1771 LOG_ERROR(Render_OpenGL, 1875 LOG_ERROR(Render_OpenGL,
1772 "Nvidia vote intrinsics are not available and its required by a shader"); 1876 "Nvidia vote intrinsics are not available and its required by a shader");
1773 // We must return true here since a stub for a theoretical warp size of 1 will always 1877 // We must return true here since a stub for a theoretical warp size of 1 will always
1774 // return an equal result for all its votes. 1878 // return an equal result for all its votes.
1775 return "true"; 1879 return {"true", Type::Bool};
1776 } 1880 }
1777 return Vote(operation, "allThreadsEqualNV"); 1881 return Vote(operation, "allThreadsEqualNV");
1778 } 1882 }
@@ -1973,8 +2077,8 @@ private:
1973 } 2077 }
1974 2078
1975 std::string GetInternalFlag(InternalFlag flag) const { 2079 std::string GetInternalFlag(InternalFlag flag) const {
1976 constexpr std::array<const char*, 4> InternalFlagNames = {"zero_flag", "sign_flag", 2080 constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
1977 "carry_flag", "overflow_flag"}; 2081 "overflow_flag"};
1978 const auto index = static_cast<u32>(flag); 2082 const auto index = static_cast<u32>(flag);
1979 ASSERT(index < static_cast<u32>(InternalFlag::Amount)); 2083 ASSERT(index < static_cast<u32>(InternalFlag::Amount));
1980 2084
@@ -2022,24 +2126,16 @@ private:
2022 2126
2023std::string GetCommonDeclarations() { 2127std::string GetCommonDeclarations() {
2024 return fmt::format( 2128 return fmt::format(
2025 "#define MAX_CONSTBUFFER_ELEMENTS {}\n"
2026 "#define ftoi floatBitsToInt\n" 2129 "#define ftoi floatBitsToInt\n"
2027 "#define ftou floatBitsToUint\n" 2130 "#define ftou floatBitsToUint\n"
2028 "#define itof intBitsToFloat\n" 2131 "#define itof intBitsToFloat\n"
2029 "#define utof uintBitsToFloat\n\n" 2132 "#define utof uintBitsToFloat\n\n"
2030 "float fromHalf2(vec2 pair) {{\n" 2133 "bvec2 HalfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {{\n"
2031 " return utof(packHalf2x16(pair));\n"
2032 "}}\n\n"
2033 "vec2 toHalf2(float value) {{\n"
2034 " return unpackHalf2x16(ftou(value));\n"
2035 "}}\n\n"
2036 "bvec2 halfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {{\n"
2037 " bvec2 is_nan1 = isnan(pair1);\n" 2134 " bvec2 is_nan1 = isnan(pair1);\n"
2038 " bvec2 is_nan2 = isnan(pair2);\n" 2135 " bvec2 is_nan2 = isnan(pair2);\n"
2039 " return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || " 2136 " return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || "
2040 "is_nan2.y);\n" 2137 "is_nan2.y);\n"
2041 "}}\n", 2138 "}}\n\n");
2042 MAX_CONSTBUFFER_ELEMENTS);
2043} 2139}
2044 2140
2045ProgramResult Decompile(const Device& device, const ShaderIR& ir, ProgramType stage, 2141ProgramResult Decompile(const Device& device, const ShaderIR& ir, ProgramType stage,