summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-08-24 17:29:19 -0300
committerGravatar ReinUsesLisp2019-09-04 01:54:00 -0300
commit6c449793b8a12cb4460d8c16d6a5a5d4d8595edf (patch)
tree593cc7c3cfcd719216630b19af71ebea6d6d74b6 /src
parentMerge pull request #2835 from chris062689/master (diff)
downloadyuzu-6c449793b8a12cb4460d8c16d6a5a5d4d8595edf.tar.gz
yuzu-6c449793b8a12cb4460d8c16d6a5a5d4d8595edf.tar.xz
yuzu-6c449793b8a12cb4460d8c16d6a5a5d4d8595edf.zip
gl_shader_decompiler: Rework GLSL decompiler type system
GLSL decompiler type system was broken. We converted all return values to float except for some cases where returning we couldn't and implicitly broke the rule of returning floats (e.g. for bools or bool pairs). Instead of doing this introduce class Expression that knows what type a return value has and when a consumer wants to use the string it asks for it with a required type, emitting a runtime error if types are incompatible. This has the disadvantage that there's more C++ code, but we can emit better GLSL code that's easier to read.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp921
1 files changed, 505 insertions, 416 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 359d58cbe..f73bf6392 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,18 +807,20 @@ 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.
@@ -687,33 +835,36 @@ private:
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,42 @@ 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 std::string temporary = code.GenerateTemporary();
806 const std::string precise = stage != ProgramType::Fragment ? "precise " : ""; 961 code.AddLine("precise {} {} = {};", GetTypeString(type), temporary, value);
807 962 return {std::move(temporary), type};
808 const std::string temporary = code.GenerateTemporary();
809 code.AddLine("{}float {} = {};", precise, temporary, value);
810 return temporary;
811 } 963 }
812 964
813 std::string VisitOperand(Operation operation, std::size_t operand_index) { 965 Expression VisitOperand(Operation operation, std::size_t operand_index) {
814 const auto& operand = operation[operand_index]; 966 const auto& operand = operation[operand_index];
815 const bool parent_precise = IsPrecise(operation); 967 const bool parent_precise = IsPrecise(operation);
816 const bool child_precise = IsPrecise(operand); 968 const bool child_precise = IsPrecise(operand);
@@ -819,19 +971,16 @@ private:
819 return Visit(operand); 971 return Visit(operand);
820 } 972 }
821 973
822 const std::string temporary = code.GenerateTemporary(); 974 Expression value = Visit(operand);
823 code.AddLine("float {} = {};", temporary, Visit(operand)); 975 std::string temporary = code.GenerateTemporary();
824 return temporary; 976 code.AddLine("{} {} = {};", GetTypeString(value.GetType()), temporary, value.GetCode());
825 } 977 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 } 978 }
830 979
831 std::optional<std::pair<std::string, bool>> GetOutputAttribute(const AbufNode* abuf) { 980 Expression GetOutputAttribute(const AbufNode* abuf) {
832 switch (const auto attribute = abuf->GetIndex()) { 981 switch (const auto attribute = abuf->GetIndex()) {
833 case Attribute::Index::Position: 982 case Attribute::Index::Position:
834 return std::make_pair("gl_Position"s + GetSwizzle(abuf->GetElement()), false); 983 return {"gl_Position"s + GetSwizzle(abuf->GetElement()), Type::Float};
835 case Attribute::Index::LayerViewportPointSize: 984 case Attribute::Index::LayerViewportPointSize:
836 switch (abuf->GetElement()) { 985 switch (abuf->GetElement()) {
837 case 0: 986 case 0:
@@ -841,119 +990,79 @@ private:
841 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) { 990 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
842 return {}; 991 return {};
843 } 992 }
844 return std::make_pair("gl_Layer", true); 993 return {"gl_Layer", Type::Int};
845 case 2: 994 case 2:
846 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) { 995 if (IsVertexShader(stage) && !device.HasVertexViewportLayer()) {
847 return {}; 996 return {};
848 } 997 }
849 return std::make_pair("gl_ViewportIndex", true); 998 return {"gl_ViewportIndex", Type::Int};
850 case 3: 999 case 3:
851 UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader"); 1000 UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader");
852 return std::make_pair("gl_PointSize", false); 1001 return {"gl_PointSize", Type::Float};
853 } 1002 }
854 return {}; 1003 return {};
855 case Attribute::Index::ClipDistances0123: 1004 case Attribute::Index::ClipDistances0123:
856 return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), false); 1005 return {fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), Type::Float};
857 case Attribute::Index::ClipDistances4567: 1006 case Attribute::Index::ClipDistances4567:
858 return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), 1007 return {fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float};
859 false);
860 default: 1008 default:
861 if (IsGenericAttribute(attribute)) { 1009 if (IsGenericAttribute(attribute)) {
862 return std::make_pair( 1010 return {GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()),
863 GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), false); 1011 Type::Float};
864 } 1012 }
865 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); 1013 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
866 return {}; 1014 return {};
867 } 1015 }
868 } 1016 }
869 1017
870 std::string CastOperand(const std::string& value, Type type) const { 1018 Expression GenerateUnary(Operation operation, std::string_view func, Type result_type,
871 switch (type) { 1019 Type type_a) {
872 case Type::Bool: 1020 std::string op_str = fmt::format("{}({})", func, VisitOperand(operation, 0).As(type_a));
873 case Type::Bool2: 1021 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 } 1022 }
886 1023
887 std::string BitwiseCastResult(const std::string& value, Type type, 1024 Expression GenerateBinaryInfix(Operation operation, std::string_view func, Type result_type,
888 bool needs_parenthesis = false) { 1025 Type type_a, Type type_b) {
889 switch (type) { 1026 const std::string op_a = VisitOperand(operation, 0).As(type_a);
890 case Type::Bool: 1027 const std::string op_b = VisitOperand(operation, 1).As(type_b);
891 case Type::Bool2: 1028 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 1029
921 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1030 return ApplyPrecise(operation, std::move(op_str), result_type);
922 } 1031 }
923 1032
924 std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, 1033 Expression GenerateBinaryCall(Operation operation, std::string_view func, Type result_type,
925 Type type_a, Type type_b) { 1034 Type type_a, Type type_b) {
926 const std::string op_a = VisitOperand(operation, 0, type_a); 1035 const std::string op_a = VisitOperand(operation, 0).As(type_a);
927 const std::string op_b = VisitOperand(operation, 1, type_b); 1036 const std::string op_b = VisitOperand(operation, 1).As(type_b);
928 const std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b); 1037 std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b);
929 1038
930 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1039 return ApplyPrecise(operation, std::move(op_str), result_type);
931 } 1040 }
932 1041
933 std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, 1042 Expression GenerateTernary(Operation operation, std::string_view func, Type result_type,
934 Type type_a, Type type_b, Type type_c) { 1043 Type type_a, Type type_b, Type type_c) {
935 const std::string op_a = VisitOperand(operation, 0, type_a); 1044 const std::string op_a = VisitOperand(operation, 0).As(type_a);
936 const std::string op_b = VisitOperand(operation, 1, type_b); 1045 const std::string op_b = VisitOperand(operation, 1).As(type_b);
937 const std::string op_c = VisitOperand(operation, 2, type_c); 1046 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); 1047 std::string op_str = fmt::format("{}({}, {}, {})", func, op_a, op_b, op_c);
939 1048
940 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1049 return ApplyPrecise(operation, std::move(op_str), result_type);
941 } 1050 }
942 1051
943 std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, 1052 Expression GenerateQuaternary(Operation operation, const std::string& func, Type result_type,
944 Type type_a, Type type_b, Type type_c, Type type_d) { 1053 Type type_a, Type type_b, Type type_c, Type type_d) {
945 const std::string op_a = VisitOperand(operation, 0, type_a); 1054 const std::string op_a = VisitOperand(operation, 0).As(type_a);
946 const std::string op_b = VisitOperand(operation, 1, type_b); 1055 const std::string op_b = VisitOperand(operation, 1).As(type_b);
947 const std::string op_c = VisitOperand(operation, 2, type_c); 1056 const std::string op_c = VisitOperand(operation, 2).As(type_c);
948 const std::string op_d = VisitOperand(operation, 3, type_d); 1057 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); 1058 std::string op_str = fmt::format("{}({}, {}, {}, {})", func, op_a, op_b, op_c, op_d);
950 1059
951 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); 1060 return ApplyPrecise(operation, std::move(op_str), result_type);
952 } 1061 }
953 1062
954 std::string GenerateTexture(Operation operation, const std::string& function_suffix, 1063 std::string GenerateTexture(Operation operation, const std::string& function_suffix,
955 const std::vector<TextureIR>& extras) { 1064 const std::vector<TextureIR>& extras) {
956 constexpr std::array<const char*, 4> coord_constructors = {"float", "vec2", "vec3", "vec4"}; 1065 constexpr std::array coord_constructors = {"float", "vec2", "vec3", "vec4"};
957 1066
958 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1067 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
959 ASSERT(meta); 1068 ASSERT(meta);
@@ -970,17 +1079,17 @@ private:
970 expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1); 1079 expr += coord_constructors.at(count + (has_array ? 1 : 0) + (has_shadow ? 1 : 0) - 1);
971 expr += '('; 1080 expr += '(';
972 for (std::size_t i = 0; i < count; ++i) { 1081 for (std::size_t i = 0; i < count; ++i) {
973 expr += Visit(operation[i]); 1082 expr += Visit(operation[i]).AsFloat();
974 1083
975 const std::size_t next = i + 1; 1084 const std::size_t next = i + 1;
976 if (next < count) 1085 if (next < count)
977 expr += ", "; 1086 expr += ", ";
978 } 1087 }
979 if (has_array) { 1088 if (has_array) {
980 expr += ", float(ftoi(" + Visit(meta->array) + "))"; 1089 expr += ", float(" + Visit(meta->array).AsInt() + ')';
981 } 1090 }
982 if (has_shadow) { 1091 if (has_shadow) {
983 expr += ", " + Visit(meta->depth_compare); 1092 expr += ", " + Visit(meta->depth_compare).AsFloat();
984 } 1093 }
985 expr += ')'; 1094 expr += ')';
986 1095
@@ -1011,11 +1120,11 @@ private:
1011 // required to be constant) 1120 // required to be constant)
1012 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 1121 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
1013 } else { 1122 } else {
1014 expr += fmt::format("ftoi({})", Visit(operand)); 1123 expr += Visit(operand).AsInt();
1015 } 1124 }
1016 break; 1125 break;
1017 case Type::Float: 1126 case Type::Float:
1018 expr += Visit(operand); 1127 expr += Visit(operand).AsFloat();
1019 break; 1128 break;
1020 default: { 1129 default: {
1021 const auto type_int = static_cast<u32>(type); 1130 const auto type_int = static_cast<u32>(type);
@@ -1031,7 +1140,7 @@ private:
1031 if (aoffi.empty()) { 1140 if (aoffi.empty()) {
1032 return {}; 1141 return {};
1033 } 1142 }
1034 constexpr std::array<const char*, 3> coord_constructors = {"int", "ivec2", "ivec3"}; 1143 constexpr std::array coord_constructors = {"int", "ivec2", "ivec3"};
1035 std::string expr = ", "; 1144 std::string expr = ", ";
1036 expr += coord_constructors.at(aoffi.size() - 1); 1145 expr += coord_constructors.at(aoffi.size() - 1);
1037 expr += '('; 1146 expr += '(';
@@ -1044,7 +1153,7 @@ private:
1044 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 1153 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
1045 } else if (device.HasVariableAoffi()) { 1154 } else if (device.HasVariableAoffi()) {
1046 // Avoid using variable AOFFI on unsupported devices. 1155 // Avoid using variable AOFFI on unsupported devices.
1047 expr += fmt::format("ftoi({})", Visit(operand)); 1156 expr += Visit(operand).AsInt();
1048 } else { 1157 } else {
1049 // Insert 0 on devices not supporting variable AOFFI. 1158 // Insert 0 on devices not supporting variable AOFFI.
1050 expr += '0'; 1159 expr += '0';
@@ -1058,328 +1167,314 @@ private:
1058 return expr; 1167 return expr;
1059 } 1168 }
1060 1169
1061 std::string Assign(Operation operation) { 1170 Expression Assign(Operation operation) {
1062 const Node& dest = operation[0]; 1171 const Node& dest = operation[0];
1063 const Node& src = operation[1]; 1172 const Node& src = operation[1];
1064 1173
1065 std::string target; 1174 Expression target;
1066 bool is_integer = false;
1067
1068 if (const auto gpr = std::get_if<GprNode>(&*dest)) { 1175 if (const auto gpr = std::get_if<GprNode>(&*dest)) {
1069 if (gpr->GetIndex() == Register::ZeroIndex) { 1176 if (gpr->GetIndex() == Register::ZeroIndex) {
1070 // Writing to Register::ZeroIndex is a no op 1177 // Writing to Register::ZeroIndex is a no op
1071 return {}; 1178 return {};
1072 } 1179 }
1073 target = GetRegister(gpr->GetIndex()); 1180 target = {GetRegister(gpr->GetIndex()), Type::Float};
1074 } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { 1181 } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
1075 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); 1182 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
1076 const auto result = GetOutputAttribute(abuf); 1183 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)) { 1184 } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
1083 if (stage == ProgramType::Compute) { 1185 if (stage == ProgramType::Compute) {
1084 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders"); 1186 LOG_WARNING(Render_OpenGL, "Local memory is stubbed on compute shaders");
1085 } 1187 }
1086 target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); 1188 target = {
1189 fmt::format("{}[{} >> 2]", GetLocalMemory(), Visit(lmem->GetAddress()).AsUint()),
1190 Type::Uint};
1087 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { 1191 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
1088 const std::string real = Visit(gmem->GetRealAddress()); 1192 const std::string real = Visit(gmem->GetRealAddress()).AsUint();
1089 const std::string base = Visit(gmem->GetBaseAddress()); 1193 const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
1090 const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); 1194 const std::string final_offset = fmt::format("({} - {}) >> 2", real, base);
1091 target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); 1195 target = {fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset),
1196 Type::Uint};
1092 } else { 1197 } else {
1093 UNREACHABLE_MSG("Assign called without a proper target"); 1198 UNREACHABLE_MSG("Assign called without a proper target");
1094 } 1199 }
1095 1200
1096 if (is_integer) { 1201 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 {}; 1202 return {};
1102 } 1203 }
1103 1204
1104 template <Type type> 1205 template <Type type>
1105 std::string Add(Operation operation) { 1206 Expression Add(Operation operation) {
1106 return GenerateBinaryInfix(operation, "+", type, type, type); 1207 return GenerateBinaryInfix(operation, "+", type, type, type);
1107 } 1208 }
1108 1209
1109 template <Type type> 1210 template <Type type>
1110 std::string Mul(Operation operation) { 1211 Expression Mul(Operation operation) {
1111 return GenerateBinaryInfix(operation, "*", type, type, type); 1212 return GenerateBinaryInfix(operation, "*", type, type, type);
1112 } 1213 }
1113 1214
1114 template <Type type> 1215 template <Type type>
1115 std::string Div(Operation operation) { 1216 Expression Div(Operation operation) {
1116 return GenerateBinaryInfix(operation, "/", type, type, type); 1217 return GenerateBinaryInfix(operation, "/", type, type, type);
1117 } 1218 }
1118 1219
1119 template <Type type> 1220 template <Type type>
1120 std::string Fma(Operation operation) { 1221 Expression Fma(Operation operation) {
1121 return GenerateTernary(operation, "fma", type, type, type, type); 1222 return GenerateTernary(operation, "fma", type, type, type, type);
1122 } 1223 }
1123 1224
1124 template <Type type> 1225 template <Type type>
1125 std::string Negate(Operation operation) { 1226 Expression Negate(Operation operation) {
1126 return GenerateUnary(operation, "-", type, type, true); 1227 return GenerateUnary(operation, "-", type, type);
1127 } 1228 }
1128 1229
1129 template <Type type> 1230 template <Type type>
1130 std::string Absolute(Operation operation) { 1231 Expression Absolute(Operation operation) {
1131 return GenerateUnary(operation, "abs", type, type, false); 1232 return GenerateUnary(operation, "abs", type, type);
1132 } 1233 }
1133 1234
1134 std::string FClamp(Operation operation) { 1235 Expression FClamp(Operation operation) {
1135 return GenerateTernary(operation, "clamp", Type::Float, Type::Float, Type::Float, 1236 return GenerateTernary(operation, "clamp", Type::Float, Type::Float, Type::Float,
1136 Type::Float); 1237 Type::Float);
1137 } 1238 }
1138 1239
1139 std::string FCastHalf0(Operation operation) { 1240 Expression FCastHalf0(Operation operation) {
1140 const std::string op_a = VisitOperand(operation, 0, Type::HalfFloat); 1241 return {fmt::format("({})[0]", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1141 return fmt::format("({})[0]", op_a);
1142 } 1242 }
1143 1243
1144 std::string FCastHalf1(Operation operation) { 1244 Expression FCastHalf1(Operation operation) {
1145 const std::string op_a = VisitOperand(operation, 0, Type::HalfFloat); 1245 return {fmt::format("({})[1]", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1146 return fmt::format("({})[1]", op_a);
1147 } 1246 }
1148 1247
1149 template <Type type> 1248 template <Type type>
1150 std::string Min(Operation operation) { 1249 Expression Min(Operation operation) {
1151 return GenerateBinaryCall(operation, "min", type, type, type); 1250 return GenerateBinaryCall(operation, "min", type, type, type);
1152 } 1251 }
1153 1252
1154 template <Type type> 1253 template <Type type>
1155 std::string Max(Operation operation) { 1254 Expression Max(Operation operation) {
1156 return GenerateBinaryCall(operation, "max", type, type, type); 1255 return GenerateBinaryCall(operation, "max", type, type, type);
1157 } 1256 }
1158 1257
1159 std::string Select(Operation operation) { 1258 Expression Select(Operation operation) {
1160 const std::string condition = Visit(operation[0]); 1259 const std::string condition = Visit(operation[0]).AsBool();
1161 const std::string true_case = Visit(operation[1]); 1260 const std::string true_case = Visit(operation[1]).AsUint();
1162 const std::string false_case = Visit(operation[2]); 1261 const std::string false_case = Visit(operation[2]).AsUint();
1163 const std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case); 1262 std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case);
1164 1263
1165 return ApplyPrecise(operation, op_str); 1264 return ApplyPrecise(operation, std::move(op_str), Type::Uint);
1166 } 1265 }
1167 1266
1168 std::string FCos(Operation operation) { 1267 Expression FCos(Operation operation) {
1169 return GenerateUnary(operation, "cos", Type::Float, Type::Float, false); 1268 return GenerateUnary(operation, "cos", Type::Float, Type::Float);
1170 } 1269 }
1171 1270
1172 std::string FSin(Operation operation) { 1271 Expression FSin(Operation operation) {
1173 return GenerateUnary(operation, "sin", Type::Float, Type::Float, false); 1272 return GenerateUnary(operation, "sin", Type::Float, Type::Float);
1174 } 1273 }
1175 1274
1176 std::string FExp2(Operation operation) { 1275 Expression FExp2(Operation operation) {
1177 return GenerateUnary(operation, "exp2", Type::Float, Type::Float, false); 1276 return GenerateUnary(operation, "exp2", Type::Float, Type::Float);
1178 } 1277 }
1179 1278
1180 std::string FLog2(Operation operation) { 1279 Expression FLog2(Operation operation) {
1181 return GenerateUnary(operation, "log2", Type::Float, Type::Float, false); 1280 return GenerateUnary(operation, "log2", Type::Float, Type::Float);
1182 } 1281 }
1183 1282
1184 std::string FInverseSqrt(Operation operation) { 1283 Expression FInverseSqrt(Operation operation) {
1185 return GenerateUnary(operation, "inversesqrt", Type::Float, Type::Float, false); 1284 return GenerateUnary(operation, "inversesqrt", Type::Float, Type::Float);
1186 } 1285 }
1187 1286
1188 std::string FSqrt(Operation operation) { 1287 Expression FSqrt(Operation operation) {
1189 return GenerateUnary(operation, "sqrt", Type::Float, Type::Float, false); 1288 return GenerateUnary(operation, "sqrt", Type::Float, Type::Float);
1190 } 1289 }
1191 1290
1192 std::string FRoundEven(Operation operation) { 1291 Expression FRoundEven(Operation operation) {
1193 return GenerateUnary(operation, "roundEven", Type::Float, Type::Float, false); 1292 return GenerateUnary(operation, "roundEven", Type::Float, Type::Float);
1194 } 1293 }
1195 1294
1196 std::string FFloor(Operation operation) { 1295 Expression FFloor(Operation operation) {
1197 return GenerateUnary(operation, "floor", Type::Float, Type::Float, false); 1296 return GenerateUnary(operation, "floor", Type::Float, Type::Float);
1198 } 1297 }
1199 1298
1200 std::string FCeil(Operation operation) { 1299 Expression FCeil(Operation operation) {
1201 return GenerateUnary(operation, "ceil", Type::Float, Type::Float, false); 1300 return GenerateUnary(operation, "ceil", Type::Float, Type::Float);
1202 } 1301 }
1203 1302
1204 std::string FTrunc(Operation operation) { 1303 Expression FTrunc(Operation operation) {
1205 return GenerateUnary(operation, "trunc", Type::Float, Type::Float, false); 1304 return GenerateUnary(operation, "trunc", Type::Float, Type::Float);
1206 } 1305 }
1207 1306
1208 template <Type type> 1307 template <Type type>
1209 std::string FCastInteger(Operation operation) { 1308 Expression FCastInteger(Operation operation) {
1210 return GenerateUnary(operation, "float", Type::Float, type, false); 1309 return GenerateUnary(operation, "float", Type::Float, type);
1211 } 1310 }
1212 1311
1213 std::string ICastFloat(Operation operation) { 1312 Expression ICastFloat(Operation operation) {
1214 return GenerateUnary(operation, "int", Type::Int, Type::Float, false); 1313 return GenerateUnary(operation, "int", Type::Int, Type::Float);
1215 } 1314 }
1216 1315
1217 std::string ICastUnsigned(Operation operation) { 1316 Expression ICastUnsigned(Operation operation) {
1218 return GenerateUnary(operation, "int", Type::Int, Type::Uint, false); 1317 return GenerateUnary(operation, "int", Type::Int, Type::Uint);
1219 } 1318 }
1220 1319
1221 template <Type type> 1320 template <Type type>
1222 std::string LogicalShiftLeft(Operation operation) { 1321 Expression LogicalShiftLeft(Operation operation) {
1223 return GenerateBinaryInfix(operation, "<<", type, type, Type::Uint); 1322 return GenerateBinaryInfix(operation, "<<", type, type, Type::Uint);
1224 } 1323 }
1225 1324
1226 std::string ILogicalShiftRight(Operation operation) { 1325 Expression ILogicalShiftRight(Operation operation) {
1227 const std::string op_a = VisitOperand(operation, 0, Type::Uint); 1326 const std::string op_a = VisitOperand(operation, 0).AsUint();
1228 const std::string op_b = VisitOperand(operation, 1, Type::Uint); 1327 const std::string op_b = VisitOperand(operation, 1).AsUint();
1229 const std::string op_str = fmt::format("int({} >> {})", op_a, op_b); 1328 std::string op_str = fmt::format("int({} >> {})", op_a, op_b);
1230 1329
1231 return ApplyPrecise(operation, BitwiseCastResult(op_str, Type::Int)); 1330 return ApplyPrecise(operation, std::move(op_str), Type::Int);
1232 } 1331 }
1233 1332
1234 std::string IArithmeticShiftRight(Operation operation) { 1333 Expression IArithmeticShiftRight(Operation operation) {
1235 return GenerateBinaryInfix(operation, ">>", Type::Int, Type::Int, Type::Uint); 1334 return GenerateBinaryInfix(operation, ">>", Type::Int, Type::Int, Type::Uint);
1236 } 1335 }
1237 1336
1238 template <Type type> 1337 template <Type type>
1239 std::string BitwiseAnd(Operation operation) { 1338 Expression BitwiseAnd(Operation operation) {
1240 return GenerateBinaryInfix(operation, "&", type, type, type); 1339 return GenerateBinaryInfix(operation, "&", type, type, type);
1241 } 1340 }
1242 1341
1243 template <Type type> 1342 template <Type type>
1244 std::string BitwiseOr(Operation operation) { 1343 Expression BitwiseOr(Operation operation) {
1245 return GenerateBinaryInfix(operation, "|", type, type, type); 1344 return GenerateBinaryInfix(operation, "|", type, type, type);
1246 } 1345 }
1247 1346
1248 template <Type type> 1347 template <Type type>
1249 std::string BitwiseXor(Operation operation) { 1348 Expression BitwiseXor(Operation operation) {
1250 return GenerateBinaryInfix(operation, "^", type, type, type); 1349 return GenerateBinaryInfix(operation, "^", type, type, type);
1251 } 1350 }
1252 1351
1253 template <Type type> 1352 template <Type type>
1254 std::string BitwiseNot(Operation operation) { 1353 Expression BitwiseNot(Operation operation) {
1255 return GenerateUnary(operation, "~", type, type, false); 1354 return GenerateUnary(operation, "~", type, type);
1256 } 1355 }
1257 1356
1258 std::string UCastFloat(Operation operation) { 1357 Expression UCastFloat(Operation operation) {
1259 return GenerateUnary(operation, "uint", Type::Uint, Type::Float, false); 1358 return GenerateUnary(operation, "uint", Type::Uint, Type::Float);
1260 } 1359 }
1261 1360
1262 std::string UCastSigned(Operation operation) { 1361 Expression UCastSigned(Operation operation) {
1263 return GenerateUnary(operation, "uint", Type::Uint, Type::Int, false); 1362 return GenerateUnary(operation, "uint", Type::Uint, Type::Int);
1264 } 1363 }
1265 1364
1266 std::string UShiftRight(Operation operation) { 1365 Expression UShiftRight(Operation operation) {
1267 return GenerateBinaryInfix(operation, ">>", Type::Uint, Type::Uint, Type::Uint); 1366 return GenerateBinaryInfix(operation, ">>", Type::Uint, Type::Uint, Type::Uint);
1268 } 1367 }
1269 1368
1270 template <Type type> 1369 template <Type type>
1271 std::string BitfieldInsert(Operation operation) { 1370 Expression BitfieldInsert(Operation operation) {
1272 return GenerateQuaternary(operation, "bitfieldInsert", type, type, type, Type::Int, 1371 return GenerateQuaternary(operation, "bitfieldInsert", type, type, type, Type::Int,
1273 Type::Int); 1372 Type::Int);
1274 } 1373 }
1275 1374
1276 template <Type type> 1375 template <Type type>
1277 std::string BitfieldExtract(Operation operation) { 1376 Expression BitfieldExtract(Operation operation) {
1278 return GenerateTernary(operation, "bitfieldExtract", type, type, Type::Int, Type::Int); 1377 return GenerateTernary(operation, "bitfieldExtract", type, type, Type::Int, Type::Int);
1279 } 1378 }
1280 1379
1281 template <Type type> 1380 template <Type type>
1282 std::string BitCount(Operation operation) { 1381 Expression BitCount(Operation operation) {
1283 return GenerateUnary(operation, "bitCount", type, type, false); 1382 return GenerateUnary(operation, "bitCount", type, type);
1284 } 1383 }
1285 1384
1286 std::string HNegate(Operation operation) { 1385 Expression HNegate(Operation operation) {
1287 const auto GetNegate = [&](std::size_t index) { 1386 const auto GetNegate = [&](std::size_t index) {
1288 return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; 1387 return VisitOperand(operation, index).AsBool() + " ? -1 : 1";
1289 }; 1388 };
1290 const std::string value = 1389 return {fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0).AsHalfFloat(),
1291 fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0, Type::HalfFloat), 1390 GetNegate(1), GetNegate(2)),
1292 GetNegate(1), GetNegate(2)); 1391 Type::HalfFloat};
1293 return BitwiseCastResult(value, Type::HalfFloat); 1392 }
1294 } 1393
1295 1394 Expression HClamp(Operation operation) {
1296 std::string HClamp(Operation operation) { 1395 const std::string value = VisitOperand(operation, 0).AsHalfFloat();
1297 const std::string value = VisitOperand(operation, 0, Type::HalfFloat); 1396 const std::string min = VisitOperand(operation, 1).AsFloat();
1298 const std::string min = VisitOperand(operation, 1, Type::Float); 1397 const std::string max = VisitOperand(operation, 2).AsFloat();
1299 const std::string max = VisitOperand(operation, 2, Type::Float); 1398 std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max);
1300 const std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max); 1399
1301 1400 return ApplyPrecise(operation, std::move(clamped), Type::HalfFloat);
1302 return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); 1401 }
1303 } 1402
1304 1403 Expression HCastFloat(Operation operation) {
1305 std::string HCastFloat(Operation operation) { 1404 return {fmt::format("vec2({})", VisitOperand(operation, 0).AsFloat()), Type::HalfFloat};
1306 const std::string op_a = VisitOperand(operation, 0, Type::Float); 1405 }
1307 return fmt::format("fromHalf2(vec2({}, 0.0f))", op_a); 1406
1308 } 1407 Expression HUnpack(Operation operation) {
1309 1408 Expression operand = VisitOperand(operation, 0);
1310 std::string HUnpack(Operation operation) { 1409 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) {
1311 const std::string operand{VisitOperand(operation, 0, Type::HalfFloat)}; 1410 case Tegra::Shader::HalfType::H0_H1:
1312 const auto value = [&]() -> std::string { 1411 return operand;
1313 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { 1412 case Tegra::Shader::HalfType::F32:
1314 case Tegra::Shader::HalfType::H0_H1: 1413 return {fmt::format("vec2({})", operand.AsFloat()), Type::HalfFloat};
1315 return operand; 1414 case Tegra::Shader::HalfType::H0_H0:
1316 case Tegra::Shader::HalfType::F32: 1415 return {fmt::format("vec2({}[0])", operand.AsHalfFloat()), Type::HalfFloat};
1317 return fmt::format("vec2(fromHalf2({}))", operand); 1416 case Tegra::Shader::HalfType::H1_H1:
1318 case Tegra::Shader::HalfType::H0_H0: 1417 return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat};
1319 return fmt::format("vec2({}[0])", operand); 1418 }
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 } 1419 }
1328 1420
1329 std::string HMergeF32(Operation operation) { 1421 Expression HMergeF32(Operation operation) {
1330 return fmt::format("float(toHalf2({})[0])", Visit(operation[0])); 1422 return {fmt::format("float({}[0])", VisitOperand(operation, 0).AsHalfFloat()), Type::Float};
1331 } 1423 }
1332 1424
1333 std::string HMergeH0(Operation operation) { 1425 Expression HMergeH0(Operation operation) {
1334 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[1]), 1426 std::string dest = VisitOperand(operation, 0).AsUint();
1335 Visit(operation[0])); 1427 std::string src = VisitOperand(operation, 1).AsUint();
1428 return {fmt::format("(({} & 0x0000FFFFU) | ({} & 0xFFFF0000U))", src, dest), Type::Uint};
1336 } 1429 }
1337 1430
1338 std::string HMergeH1(Operation operation) { 1431 Expression HMergeH1(Operation operation) {
1339 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[0]), 1432 std::string dest = VisitOperand(operation, 0).AsUint();
1340 Visit(operation[1])); 1433 std::string src = VisitOperand(operation, 1).AsUint();
1434 return {fmt::format("(({} & 0x0000FFFFU) | ({} & 0xFFFF0000U))", dest, src), Type::Uint};
1341 } 1435 }
1342 1436
1343 std::string HPack2(Operation operation) { 1437 Expression HPack2(Operation operation) {
1344 return fmt::format("utof(packHalf2x16(vec2({}, {})))", Visit(operation[0]), 1438 return {fmt::format("vec2({}, {})", VisitOperand(operation, 0).AsFloat(),
1345 Visit(operation[1])); 1439 VisitOperand(operation, 1).AsFloat()),
1440 Type::HalfFloat};
1346 } 1441 }
1347 1442
1348 template <Type type> 1443 template <Type type>
1349 std::string LogicalLessThan(Operation operation) { 1444 Expression LogicalLessThan(Operation operation) {
1350 return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); 1445 return GenerateBinaryInfix(operation, "<", Type::Bool, type, type);
1351 } 1446 }
1352 1447
1353 template <Type type> 1448 template <Type type>
1354 std::string LogicalEqual(Operation operation) { 1449 Expression LogicalEqual(Operation operation) {
1355 return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); 1450 return GenerateBinaryInfix(operation, "==", Type::Bool, type, type);
1356 } 1451 }
1357 1452
1358 template <Type type> 1453 template <Type type>
1359 std::string LogicalLessEqual(Operation operation) { 1454 Expression LogicalLessEqual(Operation operation) {
1360 return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); 1455 return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type);
1361 } 1456 }
1362 1457
1363 template <Type type> 1458 template <Type type>
1364 std::string LogicalGreaterThan(Operation operation) { 1459 Expression LogicalGreaterThan(Operation operation) {
1365 return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); 1460 return GenerateBinaryInfix(operation, ">", Type::Bool, type, type);
1366 } 1461 }
1367 1462
1368 template <Type type> 1463 template <Type type>
1369 std::string LogicalNotEqual(Operation operation) { 1464 Expression LogicalNotEqual(Operation operation) {
1370 return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); 1465 return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type);
1371 } 1466 }
1372 1467
1373 template <Type type> 1468 template <Type type>
1374 std::string LogicalGreaterEqual(Operation operation) { 1469 Expression LogicalGreaterEqual(Operation operation) {
1375 return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); 1470 return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type);
1376 } 1471 }
1377 1472
1378 std::string LogicalFIsNan(Operation operation) { 1473 Expression LogicalFIsNan(Operation operation) {
1379 return GenerateUnary(operation, "isnan", Type::Bool, Type::Float, false); 1474 return GenerateUnary(operation, "isnan", Type::Bool, Type::Float);
1380 } 1475 }
1381 1476
1382 std::string LogicalAssign(Operation operation) { 1477 Expression LogicalAssign(Operation operation) {
1383 const Node& dest = operation[0]; 1478 const Node& dest = operation[0];
1384 const Node& src = operation[1]; 1479 const Node& src = operation[1];
1385 1480
@@ -1400,78 +1495,80 @@ private:
1400 target = GetInternalFlag(flag->GetFlag()); 1495 target = GetInternalFlag(flag->GetFlag());
1401 } 1496 }
1402 1497
1403 code.AddLine("{} = {};", target, Visit(src)); 1498 code.AddLine("{} = {};", target, Visit(src).AsBool());
1404 return {}; 1499 return {};
1405 } 1500 }
1406 1501
1407 std::string LogicalAnd(Operation operation) { 1502 Expression LogicalAnd(Operation operation) {
1408 return GenerateBinaryInfix(operation, "&&", Type::Bool, Type::Bool, Type::Bool); 1503 return GenerateBinaryInfix(operation, "&&", Type::Bool, Type::Bool, Type::Bool);
1409 } 1504 }
1410 1505
1411 std::string LogicalOr(Operation operation) { 1506 Expression LogicalOr(Operation operation) {
1412 return GenerateBinaryInfix(operation, "||", Type::Bool, Type::Bool, Type::Bool); 1507 return GenerateBinaryInfix(operation, "||", Type::Bool, Type::Bool, Type::Bool);
1413 } 1508 }
1414 1509
1415 std::string LogicalXor(Operation operation) { 1510 Expression LogicalXor(Operation operation) {
1416 return GenerateBinaryInfix(operation, "^^", Type::Bool, Type::Bool, Type::Bool); 1511 return GenerateBinaryInfix(operation, "^^", Type::Bool, Type::Bool, Type::Bool);
1417 } 1512 }
1418 1513
1419 std::string LogicalNegate(Operation operation) { 1514 Expression LogicalNegate(Operation operation) {
1420 return GenerateUnary(operation, "!", Type::Bool, Type::Bool, false); 1515 return GenerateUnary(operation, "!", Type::Bool, Type::Bool);
1421 } 1516 }
1422 1517
1423 std::string LogicalPick2(Operation operation) { 1518 Expression LogicalPick2(Operation operation) {
1424 const std::string pair = VisitOperand(operation, 0, Type::Bool2); 1519 return {fmt::format("{}[{}]", VisitOperand(operation, 0).AsBool2(),
1425 return fmt::format("{}[{}]", pair, VisitOperand(operation, 1, Type::Uint)); 1520 VisitOperand(operation, 1).AsUint()),
1521 Type::Bool};
1426 } 1522 }
1427 1523
1428 std::string LogicalAnd2(Operation operation) { 1524 Expression LogicalAnd2(Operation operation) {
1429 return GenerateUnary(operation, "all", Type::Bool, Type::Bool2); 1525 return GenerateUnary(operation, "all", Type::Bool, Type::Bool2);
1430 } 1526 }
1431 1527
1432 template <bool with_nan> 1528 template <bool with_nan>
1433 std::string GenerateHalfComparison(Operation operation, const std::string& compare_op) { 1529 Expression GenerateHalfComparison(Operation operation, std::string_view compare_op) {
1434 const std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, 1530 Expression comparison = GenerateBinaryCall(operation, compare_op, Type::Bool2,
1435 Type::HalfFloat, Type::HalfFloat)}; 1531 Type::HalfFloat, Type::HalfFloat);
1436 if constexpr (!with_nan) { 1532 if constexpr (!with_nan) {
1437 return comparison; 1533 return comparison;
1438 } 1534 }
1439 return fmt::format("halfFloatNanComparison({}, {}, {})", comparison, 1535 return {fmt::format("HalfFloatNanComparison({}, {}, {})", comparison.AsBool2(),
1440 VisitOperand(operation, 0, Type::HalfFloat), 1536 VisitOperand(operation, 0).AsHalfFloat(),
1441 VisitOperand(operation, 1, Type::HalfFloat)); 1537 VisitOperand(operation, 1).AsHalfFloat()),
1538 Type::Bool2};
1442 } 1539 }
1443 1540
1444 template <bool with_nan> 1541 template <bool with_nan>
1445 std::string Logical2HLessThan(Operation operation) { 1542 Expression Logical2HLessThan(Operation operation) {
1446 return GenerateHalfComparison<with_nan>(operation, "lessThan"); 1543 return GenerateHalfComparison<with_nan>(operation, "lessThan");
1447 } 1544 }
1448 1545
1449 template <bool with_nan> 1546 template <bool with_nan>
1450 std::string Logical2HEqual(Operation operation) { 1547 Expression Logical2HEqual(Operation operation) {
1451 return GenerateHalfComparison<with_nan>(operation, "equal"); 1548 return GenerateHalfComparison<with_nan>(operation, "equal");
1452 } 1549 }
1453 1550
1454 template <bool with_nan> 1551 template <bool with_nan>
1455 std::string Logical2HLessEqual(Operation operation) { 1552 Expression Logical2HLessEqual(Operation operation) {
1456 return GenerateHalfComparison<with_nan>(operation, "lessThanEqual"); 1553 return GenerateHalfComparison<with_nan>(operation, "lessThanEqual");
1457 } 1554 }
1458 1555
1459 template <bool with_nan> 1556 template <bool with_nan>
1460 std::string Logical2HGreaterThan(Operation operation) { 1557 Expression Logical2HGreaterThan(Operation operation) {
1461 return GenerateHalfComparison<with_nan>(operation, "greaterThan"); 1558 return GenerateHalfComparison<with_nan>(operation, "greaterThan");
1462 } 1559 }
1463 1560
1464 template <bool with_nan> 1561 template <bool with_nan>
1465 std::string Logical2HNotEqual(Operation operation) { 1562 Expression Logical2HNotEqual(Operation operation) {
1466 return GenerateHalfComparison<with_nan>(operation, "notEqual"); 1563 return GenerateHalfComparison<with_nan>(operation, "notEqual");
1467 } 1564 }
1468 1565
1469 template <bool with_nan> 1566 template <bool with_nan>
1470 std::string Logical2HGreaterEqual(Operation operation) { 1567 Expression Logical2HGreaterEqual(Operation operation) {
1471 return GenerateHalfComparison<with_nan>(operation, "greaterThanEqual"); 1568 return GenerateHalfComparison<with_nan>(operation, "greaterThanEqual");
1472 } 1569 }
1473 1570
1474 std::string Texture(Operation operation) { 1571 Expression Texture(Operation operation) {
1475 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1572 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1476 ASSERT(meta); 1573 ASSERT(meta);
1477 1574
@@ -1480,10 +1577,10 @@ private:
1480 if (meta->sampler.IsShadow()) { 1577 if (meta->sampler.IsShadow()) {
1481 expr = "vec4(" + expr + ')'; 1578 expr = "vec4(" + expr + ')';
1482 } 1579 }
1483 return expr + GetSwizzle(meta->element); 1580 return {expr + GetSwizzle(meta->element), Type::Float};
1484 } 1581 }
1485 1582
1486 std::string TextureLod(Operation operation) { 1583 Expression TextureLod(Operation operation) {
1487 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1584 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1488 ASSERT(meta); 1585 ASSERT(meta);
1489 1586
@@ -1492,54 +1589,54 @@ private:
1492 if (meta->sampler.IsShadow()) { 1589 if (meta->sampler.IsShadow()) {
1493 expr = "vec4(" + expr + ')'; 1590 expr = "vec4(" + expr + ')';
1494 } 1591 }
1495 return expr + GetSwizzle(meta->element); 1592 return {expr + GetSwizzle(meta->element), Type::Float};
1496 } 1593 }
1497 1594
1498 std::string TextureGather(Operation operation) { 1595 Expression TextureGather(Operation operation) {
1499 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1596 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1500 ASSERT(meta); 1597 ASSERT(meta);
1501 1598
1502 const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int; 1599 const auto type = meta->sampler.IsShadow() ? Type::Float : Type::Int;
1503 return GenerateTexture(operation, "Gather", 1600 return {GenerateTexture(operation, "Gather",
1504 {TextureArgument{type, meta->component}, TextureAoffi{}}) + 1601 {TextureArgument{type, meta->component}, TextureAoffi{}}) +
1505 GetSwizzle(meta->element); 1602 GetSwizzle(meta->element),
1603 Type::Float};
1506 } 1604 }
1507 1605
1508 std::string TextureQueryDimensions(Operation operation) { 1606 Expression TextureQueryDimensions(Operation operation) {
1509 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1607 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1510 ASSERT(meta); 1608 ASSERT(meta);
1511 1609
1512 const std::string sampler = GetSampler(meta->sampler); 1610 const std::string sampler = GetSampler(meta->sampler);
1513 const std::string lod = VisitOperand(operation, 0, Type::Int); 1611 const std::string lod = VisitOperand(operation, 0).AsInt();
1514 1612
1515 switch (meta->element) { 1613 switch (meta->element) {
1516 case 0: 1614 case 0:
1517 case 1: 1615 case 1:
1518 return fmt::format("itof(int(textureSize({}, {}){}))", sampler, lod, 1616 return {fmt::format("textureSize({}, {}){}", sampler, lod, GetSwizzle(meta->element)),
1519 GetSwizzle(meta->element)); 1617 Type::Int};
1520 case 2:
1521 return "0";
1522 case 3: 1618 case 3:
1523 return fmt::format("itof(textureQueryLevels({}))", sampler); 1619 return {fmt::format("textureQueryLevels({})", sampler), Type::Int};
1524 } 1620 }
1525 UNREACHABLE(); 1621 UNREACHABLE();
1526 return "0"; 1622 return {"0", Type::Int};
1527 } 1623 }
1528 1624
1529 std::string TextureQueryLod(Operation operation) { 1625 Expression TextureQueryLod(Operation operation) {
1530 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1626 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1531 ASSERT(meta); 1627 ASSERT(meta);
1532 1628
1533 if (meta->element < 2) { 1629 if (meta->element < 2) {
1534 return fmt::format("itof(int(({} * vec2(256)){}))", 1630 return {fmt::format("int(({} * vec2(256)){})",
1535 GenerateTexture(operation, "QueryLod", {}), 1631 GenerateTexture(operation, "QueryLod", {}),
1536 GetSwizzle(meta->element)); 1632 GetSwizzle(meta->element)),
1633 Type::Int};
1537 } 1634 }
1538 return "0"; 1635 return {"0", Type::Int};
1539 } 1636 }
1540 1637
1541 std::string TexelFetch(Operation operation) { 1638 Expression TexelFetch(Operation operation) {
1542 constexpr std::array<const char*, 4> constructors = {"int", "ivec2", "ivec3", "ivec4"}; 1639 constexpr std::array constructors = {"int", "ivec2", "ivec3", "ivec4"};
1543 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta()); 1640 const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
1544 ASSERT(meta); 1641 ASSERT(meta);
1545 UNIMPLEMENTED_IF(meta->sampler.IsArray()); 1642 UNIMPLEMENTED_IF(meta->sampler.IsArray());
@@ -1552,7 +1649,7 @@ private:
1552 expr += constructors.at(operation.GetOperandsCount() - 1); 1649 expr += constructors.at(operation.GetOperandsCount() - 1);
1553 expr += '('; 1650 expr += '(';
1554 for (std::size_t i = 0; i < count; ++i) { 1651 for (std::size_t i = 0; i < count; ++i) {
1555 expr += VisitOperand(operation, i, Type::Int); 1652 expr += VisitOperand(operation, i).AsInt();
1556 const std::size_t next = i + 1; 1653 const std::size_t next = i + 1;
1557 if (next == count) 1654 if (next == count)
1558 expr += ')'; 1655 expr += ')';
@@ -1565,7 +1662,7 @@ private:
1565 1662
1566 if (meta->lod) { 1663 if (meta->lod) {
1567 expr += ", "; 1664 expr += ", ";
1568 expr += CastOperand(Visit(meta->lod), Type::Int); 1665 expr += Visit(meta->lod).AsInt();
1569 } 1666 }
1570 expr += ')'; 1667 expr += ')';
1571 expr += GetSwizzle(meta->element); 1668 expr += GetSwizzle(meta->element);
@@ -1580,11 +1677,11 @@ private:
1580 code.AddLine("float {} = {};", tmp, expr); 1677 code.AddLine("float {} = {};", tmp, expr);
1581 code.AddLine("#endif"); 1678 code.AddLine("#endif");
1582 1679
1583 return tmp; 1680 return {tmp, Type::Float};
1584 } 1681 }
1585 1682
1586 std::string ImageStore(Operation operation) { 1683 Expression ImageStore(Operation operation) {
1587 constexpr std::array<const char*, 4> constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; 1684 constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
1588 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1685 const auto meta{std::get<MetaImage>(operation.GetMeta())};
1589 1686
1590 std::string expr = "imageStore("; 1687 std::string expr = "imageStore(";
@@ -1594,7 +1691,7 @@ private:
1594 const std::size_t coords_count{operation.GetOperandsCount()}; 1691 const std::size_t coords_count{operation.GetOperandsCount()};
1595 expr += constructors.at(coords_count - 1); 1692 expr += constructors.at(coords_count - 1);
1596 for (std::size_t i = 0; i < coords_count; ++i) { 1693 for (std::size_t i = 0; i < coords_count; ++i) {
1597 expr += VisitOperand(operation, i, Type::Int); 1694 expr += VisitOperand(operation, i).AsInt();
1598 if (i + 1 < coords_count) { 1695 if (i + 1 < coords_count) {
1599 expr += ", "; 1696 expr += ", ";
1600 } 1697 }
@@ -1605,7 +1702,7 @@ private:
1605 UNIMPLEMENTED_IF(values_count != 4); 1702 UNIMPLEMENTED_IF(values_count != 4);
1606 expr += "vec4("; 1703 expr += "vec4(";
1607 for (std::size_t i = 0; i < values_count; ++i) { 1704 for (std::size_t i = 0; i < values_count; ++i) {
1608 expr += Visit(meta.values.at(i)); 1705 expr += Visit(meta.values.at(i)).AsFloat();
1609 if (i + 1 < values_count) { 1706 if (i + 1 < values_count) {
1610 expr += ", "; 1707 expr += ", ";
1611 } 1708 }
@@ -1616,52 +1713,52 @@ private:
1616 return {}; 1713 return {};
1617 } 1714 }
1618 1715
1619 std::string Branch(Operation operation) { 1716 Expression Branch(Operation operation) {
1620 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 1717 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
1621 UNIMPLEMENTED_IF(!target); 1718 UNIMPLEMENTED_IF(!target);
1622 1719
1623 code.AddLine("jmp_to = 0x{:x}u;", target->GetValue()); 1720 code.AddLine("jmp_to = 0x{:X}U;", target->GetValue());
1624 code.AddLine("break;"); 1721 code.AddLine("break;");
1625 return {}; 1722 return {};
1626 } 1723 }
1627 1724
1628 std::string BranchIndirect(Operation operation) { 1725 Expression BranchIndirect(Operation operation) {
1629 const std::string op_a = VisitOperand(operation, 0, Type::Uint); 1726 const std::string op_a = VisitOperand(operation, 0).AsUint();
1630 1727
1631 code.AddLine("jmp_to = {};", op_a); 1728 code.AddLine("jmp_to = {};", op_a);
1632 code.AddLine("break;"); 1729 code.AddLine("break;");
1633 return {}; 1730 return {};
1634 } 1731 }
1635 1732
1636 std::string PushFlowStack(Operation operation) { 1733 Expression PushFlowStack(Operation operation) {
1637 const auto stack = std::get<MetaStackClass>(operation.GetMeta()); 1734 const auto stack = std::get<MetaStackClass>(operation.GetMeta());
1638 const auto target = std::get_if<ImmediateNode>(&*operation[0]); 1735 const auto target = std::get_if<ImmediateNode>(&*operation[0]);
1639 UNIMPLEMENTED_IF(!target); 1736 UNIMPLEMENTED_IF(!target);
1640 1737
1641 code.AddLine("{}[{}++] = 0x{:x}u;", FlowStackName(stack), FlowStackTopName(stack), 1738 code.AddLine("{}[{}++] = 0x{:X}U;", FlowStackName(stack), FlowStackTopName(stack),
1642 target->GetValue()); 1739 target->GetValue());
1643 return {}; 1740 return {};
1644 } 1741 }
1645 1742
1646 std::string PopFlowStack(Operation operation) { 1743 Expression PopFlowStack(Operation operation) {
1647 const auto stack = std::get<MetaStackClass>(operation.GetMeta()); 1744 const auto stack = std::get<MetaStackClass>(operation.GetMeta());
1648 code.AddLine("jmp_to = {}[--{}];", FlowStackName(stack), FlowStackTopName(stack)); 1745 code.AddLine("jmp_to = {}[--{}];", FlowStackName(stack), FlowStackTopName(stack));
1649 code.AddLine("break;"); 1746 code.AddLine("break;");
1650 return {}; 1747 return {};
1651 } 1748 }
1652 1749
1653 std::string Exit(Operation operation) { 1750 Expression Exit(Operation operation) {
1654 if (stage != ProgramType::Fragment) { 1751 if (stage != ProgramType::Fragment) {
1655 code.AddLine("return;"); 1752 code.AddLine("return;");
1656 return {}; 1753 return {};
1657 } 1754 }
1658 const auto& used_registers = ir.GetRegisters(); 1755 const auto& used_registers = ir.GetRegisters();
1659 const auto SafeGetRegister = [&](u32 reg) -> std::string { 1756 const auto SafeGetRegister = [&](u32 reg) -> Expression {
1660 // TODO(Rodrigo): Replace with contains once C++20 releases 1757 // TODO(Rodrigo): Replace with contains once C++20 releases
1661 if (used_registers.find(reg) != used_registers.end()) { 1758 if (used_registers.find(reg) != used_registers.end()) {
1662 return GetRegister(reg); 1759 return {GetRegister(reg), Type::Float};
1663 } 1760 }
1664 return "0.0f"; 1761 return {"0.0f", Type::Float};
1665 }; 1762 };
1666 1763
1667 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); 1764 UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented");
@@ -1674,7 +1771,7 @@ private:
1674 for (u32 component = 0; component < 4; ++component) { 1771 for (u32 component = 0; component < 4; ++component) {
1675 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { 1772 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) {
1676 code.AddLine("FragColor{}[{}] = {};", render_target, component, 1773 code.AddLine("FragColor{}[{}] = {};", render_target, component,
1677 SafeGetRegister(current_reg)); 1774 SafeGetRegister(current_reg).AsFloat());
1678 ++current_reg; 1775 ++current_reg;
1679 } 1776 }
1680 } 1777 }
@@ -1683,14 +1780,14 @@ private:
1683 if (header.ps.omap.depth) { 1780 if (header.ps.omap.depth) {
1684 // The depth output is always 2 registers after the last color output, and current_reg 1781 // The depth output is always 2 registers after the last color output, and current_reg
1685 // already contains one past the last color register. 1782 // already contains one past the last color register.
1686 code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1)); 1783 code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1).AsFloat());
1687 } 1784 }
1688 1785
1689 code.AddLine("return;"); 1786 code.AddLine("return;");
1690 return {}; 1787 return {};
1691 } 1788 }
1692 1789
1693 std::string Discard(Operation operation) { 1790 Expression Discard(Operation operation) {
1694 // Enclose "discard" in a conditional, so that GLSL compilation does not complain 1791 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
1695 // about unexecuted instructions that may follow this. 1792 // about unexecuted instructions that may follow this.
1696 code.AddLine("if (true) {{"); 1793 code.AddLine("if (true) {{");
@@ -1701,7 +1798,7 @@ private:
1701 return {}; 1798 return {};
1702 } 1799 }
1703 1800
1704 std::string EmitVertex(Operation operation) { 1801 Expression EmitVertex(Operation operation) {
1705 ASSERT_MSG(stage == ProgramType::Geometry, 1802 ASSERT_MSG(stage == ProgramType::Geometry,
1706 "EmitVertex is expected to be used in a geometry shader."); 1803 "EmitVertex is expected to be used in a geometry shader.");
1707 1804
@@ -1712,7 +1809,7 @@ private:
1712 return {}; 1809 return {};
1713 } 1810 }
1714 1811
1715 std::string EndPrimitive(Operation operation) { 1812 Expression EndPrimitive(Operation operation) {
1716 ASSERT_MSG(stage == ProgramType::Geometry, 1813 ASSERT_MSG(stage == ProgramType::Geometry,
1717 "EndPrimitive is expected to be used in a geometry shader."); 1814 "EndPrimitive is expected to be used in a geometry shader.");
1718 1815
@@ -1720,59 +1817,59 @@ private:
1720 return {}; 1817 return {};
1721 } 1818 }
1722 1819
1723 std::string YNegate(Operation operation) { 1820 Expression YNegate(Operation operation) {
1724 // Config pack's third value is Y_NEGATE's state. 1821 // Config pack's third value is Y_NEGATE's state.
1725 return "uintBitsToFloat(config_pack[2])"; 1822 return {"config_pack[2]", Type::Uint};
1726 } 1823 }
1727 1824
1728 template <u32 element> 1825 template <u32 element>
1729 std::string LocalInvocationId(Operation) { 1826 Expression LocalInvocationId(Operation) {
1730 return "utof(gl_LocalInvocationID"s + GetSwizzle(element) + ')'; 1827 return {"gl_LocalInvocationID"s + GetSwizzle(element), Type::Uint};
1731 } 1828 }
1732 1829
1733 template <u32 element> 1830 template <u32 element>
1734 std::string WorkGroupId(Operation) { 1831 Expression WorkGroupId(Operation) {
1735 return "utof(gl_WorkGroupID"s + GetSwizzle(element) + ')'; 1832 return {"gl_WorkGroupID"s + GetSwizzle(element), Type::Uint};
1736 } 1833 }
1737 1834
1738 std::string BallotThread(Operation operation) { 1835 Expression BallotThread(Operation operation) {
1739 const std::string value = VisitOperand(operation, 0, Type::Bool); 1836 const std::string value = VisitOperand(operation, 0).AsBool();
1740 if (!device.HasWarpIntrinsics()) { 1837 if (!device.HasWarpIntrinsics()) {
1741 LOG_ERROR(Render_OpenGL, 1838 LOG_ERROR(Render_OpenGL,
1742 "Nvidia warp intrinsics are not available and its required by a shader"); 1839 "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 1840 // Stub on non-Nvidia devices by simulating all threads voting the same as the active
1744 // one. 1841 // one.
1745 return fmt::format("utof({} ? 0xFFFFFFFFU : 0U)", value); 1842 return {fmt::format("({} ? 0xFFFFFFFFU : 0U)", value), Type::Uint};
1746 } 1843 }
1747 return fmt::format("utof(ballotThreadNV({}))", value); 1844 return {fmt::format("ballotThreadNV({})", value), Type::Uint};
1748 } 1845 }
1749 1846
1750 std::string Vote(Operation operation, const char* func) { 1847 Expression Vote(Operation operation, const char* func) {
1751 const std::string value = VisitOperand(operation, 0, Type::Bool); 1848 const std::string value = VisitOperand(operation, 0).AsBool();
1752 if (!device.HasWarpIntrinsics()) { 1849 if (!device.HasWarpIntrinsics()) {
1753 LOG_ERROR(Render_OpenGL, 1850 LOG_ERROR(Render_OpenGL,
1754 "Nvidia vote intrinsics are not available and its required by a shader"); 1851 "Nvidia vote intrinsics are not available and its required by a shader");
1755 // Stub with a warp size of one. 1852 // Stub with a warp size of one.
1756 return value; 1853 return {value, Type::Bool};
1757 } 1854 }
1758 return fmt::format("{}({})", func, value); 1855 return {fmt::format("{}({})", func, value), Type::Bool};
1759 } 1856 }
1760 1857
1761 std::string VoteAll(Operation operation) { 1858 Expression VoteAll(Operation operation) {
1762 return Vote(operation, "allThreadsNV"); 1859 return Vote(operation, "allThreadsNV");
1763 } 1860 }
1764 1861
1765 std::string VoteAny(Operation operation) { 1862 Expression VoteAny(Operation operation) {
1766 return Vote(operation, "anyThreadNV"); 1863 return Vote(operation, "anyThreadNV");
1767 } 1864 }
1768 1865
1769 std::string VoteEqual(Operation operation) { 1866 Expression VoteEqual(Operation operation) {
1770 if (!device.HasWarpIntrinsics()) { 1867 if (!device.HasWarpIntrinsics()) {
1771 LOG_ERROR(Render_OpenGL, 1868 LOG_ERROR(Render_OpenGL,
1772 "Nvidia vote intrinsics are not available and its required by a shader"); 1869 "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 1870 // 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. 1871 // return an equal result for all its votes.
1775 return "true"; 1872 return {"true", Type::Bool};
1776 } 1873 }
1777 return Vote(operation, "allThreadsEqualNV"); 1874 return Vote(operation, "allThreadsEqualNV");
1778 } 1875 }
@@ -1973,8 +2070,8 @@ private:
1973 } 2070 }
1974 2071
1975 std::string GetInternalFlag(InternalFlag flag) const { 2072 std::string GetInternalFlag(InternalFlag flag) const {
1976 constexpr std::array<const char*, 4> InternalFlagNames = {"zero_flag", "sign_flag", 2073 constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
1977 "carry_flag", "overflow_flag"}; 2074 "overflow_flag"};
1978 const auto index = static_cast<u32>(flag); 2075 const auto index = static_cast<u32>(flag);
1979 ASSERT(index < static_cast<u32>(InternalFlag::Amount)); 2076 ASSERT(index < static_cast<u32>(InternalFlag::Amount));
1980 2077
@@ -2022,24 +2119,16 @@ private:
2022 2119
2023std::string GetCommonDeclarations() { 2120std::string GetCommonDeclarations() {
2024 return fmt::format( 2121 return fmt::format(
2025 "#define MAX_CONSTBUFFER_ELEMENTS {}\n"
2026 "#define ftoi floatBitsToInt\n" 2122 "#define ftoi floatBitsToInt\n"
2027 "#define ftou floatBitsToUint\n" 2123 "#define ftou floatBitsToUint\n"
2028 "#define itof intBitsToFloat\n" 2124 "#define itof intBitsToFloat\n"
2029 "#define utof uintBitsToFloat\n\n" 2125 "#define utof uintBitsToFloat\n\n"
2030 "float fromHalf2(vec2 pair) {{\n" 2126 "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" 2127 " bvec2 is_nan1 = isnan(pair1);\n"
2038 " bvec2 is_nan2 = isnan(pair2);\n" 2128 " bvec2 is_nan2 = isnan(pair2);\n"
2039 " return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || " 2129 " return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || "
2040 "is_nan2.y);\n" 2130 "is_nan2.y);\n"
2041 "}}\n", 2131 "}}\n\n");
2042 MAX_CONSTBUFFER_ELEMENTS);
2043} 2132}
2044 2133
2045ProgramResult Decompile(const Device& device, const ShaderIR& ir, ProgramType stage, 2134ProgramResult Decompile(const Device& device, const ShaderIR& ir, ProgramType stage,