mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #2494 from lioncash/shader-text
gl_shader_decompiler: Add AddLine() overloads with single function that forwards to libfmt
This commit is contained in:
		
						commit
						9a17b20896
					
				| @ -57,15 +57,14 @@ public: | |||||||
|         shader_source += text; |         shader_source += text; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void AddLine(std::string_view text) { |     // Forwards all arguments directly to libfmt.
 | ||||||
|         AddExpression(text); |     // Note that all formatting requirements for fmt must be
 | ||||||
|         AddNewLine(); |     // obeyed when using this function. (e.g. {{ must be used
 | ||||||
|     } |     // printing the character '{' is desirable. Ditto for }} and '}',
 | ||||||
| 
 |     // etc).
 | ||||||
|     void AddLine(char character) { |     template <typename... Args> | ||||||
|         DEBUG_ASSERT(scope >= 0); |     void AddLine(std::string_view text, Args&&... args) { | ||||||
|         AppendIndentation(); |         AddExpression(fmt::format(text, std::forward<Args>(args)...)); | ||||||
|         shader_source += character; |  | ||||||
|         AddNewLine(); |         AddNewLine(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -75,9 +74,7 @@ public: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateTemporary() { |     std::string GenerateTemporary() { | ||||||
|         std::string temporary = "tmp"; |         return fmt::format("tmp{}", temporary_index++); | ||||||
|         temporary += std::to_string(temporary_index++); |  | ||||||
|         return temporary; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GetResult() { |     std::string GetResult() { | ||||||
| @ -167,41 +164,41 @@ public: | |||||||
|         DeclareSamplers(); |         DeclareSamplers(); | ||||||
|         DeclarePhysicalAttributeReader(); |         DeclarePhysicalAttributeReader(); | ||||||
| 
 | 
 | ||||||
|         code.AddLine("void execute_" + suffix + "() {"); |         code.AddLine("void execute_{}() {{", suffix); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
| 
 | 
 | ||||||
|         // VM's program counter
 |         // VM's program counter
 | ||||||
|         const auto first_address = ir.GetBasicBlocks().begin()->first; |         const auto first_address = ir.GetBasicBlocks().begin()->first; | ||||||
|         code.AddLine("uint jmp_to = " + std::to_string(first_address) + "u;"); |         code.AddLine("uint jmp_to = {}u;", first_address); | ||||||
| 
 | 
 | ||||||
|         // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
 |         // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
 | ||||||
|         // unlikely that shaders will use 20 nested SSYs and PBKs.
 |         // unlikely that shaders will use 20 nested SSYs and PBKs.
 | ||||||
|         constexpr u32 FLOW_STACK_SIZE = 20; |         constexpr u32 FLOW_STACK_SIZE = 20; | ||||||
|         code.AddLine(fmt::format("uint flow_stack[{}];", FLOW_STACK_SIZE)); |         code.AddLine("uint flow_stack[{}];", FLOW_STACK_SIZE); | ||||||
|         code.AddLine("uint flow_stack_top = 0u;"); |         code.AddLine("uint flow_stack_top = 0u;"); | ||||||
| 
 | 
 | ||||||
|         code.AddLine("while (true) {"); |         code.AddLine("while (true) {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
| 
 | 
 | ||||||
|         code.AddLine("switch (jmp_to) {"); |         code.AddLine("switch (jmp_to) {{"); | ||||||
| 
 | 
 | ||||||
|         for (const auto& pair : ir.GetBasicBlocks()) { |         for (const auto& pair : ir.GetBasicBlocks()) { | ||||||
|             const auto [address, bb] = pair; |             const auto [address, bb] = pair; | ||||||
|             code.AddLine(fmt::format("case 0x{:x}u: {{", address)); |             code.AddLine("case 0x{:x}u: {{", address); | ||||||
|             ++code.scope; |             ++code.scope; | ||||||
| 
 | 
 | ||||||
|             VisitBlock(bb); |             VisitBlock(bb); | ||||||
| 
 | 
 | ||||||
|             --code.scope; |             --code.scope; | ||||||
|             code.AddLine('}'); |             code.AddLine("}}"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine("default: return;"); |         code.AddLine("default: return;"); | ||||||
|         code.AddLine('}'); |         code.AddLine("}}"); | ||||||
| 
 | 
 | ||||||
|         for (std::size_t i = 0; i < 2; ++i) { |         for (std::size_t i = 0; i < 2; ++i) { | ||||||
|             --code.scope; |             --code.scope; | ||||||
|             code.AddLine('}'); |             code.AddLine("}}"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -241,12 +238,13 @@ private: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareGeometry() { |     void DeclareGeometry() { | ||||||
|         if (stage != ShaderStage::Geometry) |         if (stage != ShaderStage::Geometry) { | ||||||
|             return; |             return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         const auto topology = GetTopologyName(header.common3.output_topology); |         const auto topology = GetTopologyName(header.common3.output_topology); | ||||||
|         const auto max_vertices = std::to_string(header.common4.max_output_vertices); |         const auto max_vertices = header.common4.max_output_vertices.Value(); | ||||||
|         code.AddLine("layout (" + topology + ", max_vertices = " + max_vertices + ") out;"); |         code.AddLine("layout ({}, max_vertices = {}) out;", topology, max_vertices); | ||||||
|         code.AddNewLine(); |         code.AddNewLine(); | ||||||
| 
 | 
 | ||||||
|         DeclareVertexRedeclarations(); |         DeclareVertexRedeclarations(); | ||||||
| @ -255,7 +253,7 @@ private: | |||||||
|     void DeclareVertexRedeclarations() { |     void DeclareVertexRedeclarations() { | ||||||
|         bool clip_distances_declared = false; |         bool clip_distances_declared = false; | ||||||
| 
 | 
 | ||||||
|         code.AddLine("out gl_PerVertex {"); |         code.AddLine("out gl_PerVertex {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
| 
 | 
 | ||||||
|         code.AddLine("vec4 gl_Position;"); |         code.AddLine("vec4 gl_Position;"); | ||||||
| @ -271,40 +269,42 @@ private: | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         --code.scope; |         --code.scope; | ||||||
|         code.AddLine("};"); |         code.AddLine("}};"); | ||||||
|         code.AddNewLine(); |         code.AddNewLine(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareRegisters() { |     void DeclareRegisters() { | ||||||
|         const auto& registers = ir.GetRegisters(); |         const auto& registers = ir.GetRegisters(); | ||||||
|         for (const u32 gpr : registers) { |         for (const u32 gpr : registers) { | ||||||
|             code.AddLine("float " + GetRegister(gpr) + " = 0;"); |             code.AddLine("float {} = 0;", GetRegister(gpr)); | ||||||
|         } |         } | ||||||
|         if (!registers.empty()) |         if (!registers.empty()) { | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclarePredicates() { |     void DeclarePredicates() { | ||||||
|         const auto& predicates = ir.GetPredicates(); |         const auto& predicates = ir.GetPredicates(); | ||||||
|         for (const auto pred : predicates) { |         for (const auto pred : predicates) { | ||||||
|             code.AddLine("bool " + GetPredicate(pred) + " = false;"); |             code.AddLine("bool {} = false;", GetPredicate(pred)); | ||||||
|         } |         } | ||||||
|         if (!predicates.empty()) |         if (!predicates.empty()) { | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareLocalMemory() { |     void DeclareLocalMemory() { | ||||||
|         if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { |         if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { | ||||||
|             const auto element_count = Common::AlignUp(local_memory_size, 4) / 4; |             const auto element_count = Common::AlignUp(local_memory_size, 4) / 4; | ||||||
|             code.AddLine("float " + GetLocalMemory() + '[' + std::to_string(element_count) + "];"); |             code.AddLine("float {}[{}];", GetLocalMemory(), element_count); | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareInternalFlags() { |     void DeclareInternalFlags() { | ||||||
|         for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { |         for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { | ||||||
|             const InternalFlag flag_code = static_cast<InternalFlag>(flag); |             const auto flag_code = static_cast<InternalFlag>(flag); | ||||||
|             code.AddLine("bool " + GetInternalFlag(flag_code) + " = false;"); |             code.AddLine("bool {} = false;", GetInternalFlag(flag_code)); | ||||||
|         } |         } | ||||||
|         code.AddNewLine(); |         code.AddNewLine(); | ||||||
|     } |     } | ||||||
| @ -343,8 +343,9 @@ private: | |||||||
|                 DeclareInputAttribute(index, false); |                 DeclareInputAttribute(index, false); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (!attributes.empty()) |         if (!attributes.empty()) { | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { |     void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { | ||||||
| @ -370,8 +371,7 @@ private: | |||||||
|             location += GENERIC_VARYING_START_LOCATION; |             location += GENERIC_VARYING_START_LOCATION; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine("layout (location = " + std::to_string(location) + ") " + suffix + "in vec4 " + |         code.AddLine("layout (location = {}) {} in vec4 {};", name, location, suffix, name); | ||||||
|                      name + ';'); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareOutputAttributes() { |     void DeclareOutputAttributes() { | ||||||
| @ -389,23 +389,23 @@ private: | |||||||
|                 DeclareOutputAttribute(index); |                 DeclareOutputAttribute(index); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (!attributes.empty()) |         if (!attributes.empty()) { | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareOutputAttribute(Attribute::Index index) { |     void DeclareOutputAttribute(Attribute::Index index) { | ||||||
|         const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION}; |         const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION}; | ||||||
|         code.AddLine("layout (location = " + std::to_string(location) + ") out vec4 " + |         code.AddLine("layout (location = {}) out vec4 {};", location, GetOutputAttribute(index)); | ||||||
|                      GetOutputAttribute(index) + ';'); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareConstantBuffers() { |     void DeclareConstantBuffers() { | ||||||
|         for (const auto& entry : ir.GetConstantBuffers()) { |         for (const auto& entry : ir.GetConstantBuffers()) { | ||||||
|             const auto [index, size] = entry; |             const auto [index, size] = entry; | ||||||
|             code.AddLine("layout (std140, binding = CBUF_BINDING_" + std::to_string(index) + |             code.AddLine("layout (std140, binding = CBUF_BINDING_{}) uniform {} {{", index, | ||||||
|                          ") uniform " + GetConstBufferBlock(index) + " {"); |                          GetConstBufferBlock(index)); | ||||||
|             code.AddLine("    vec4 " + GetConstBuffer(index) + "[MAX_CONSTBUFFER_ELEMENTS];"); |             code.AddLine("    vec4 {}[MAX_CONSTBUFFER_ELEMENTS];", GetConstBuffer(index)); | ||||||
|             code.AddLine("};"); |             code.AddLine("}};"); | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -417,17 +417,16 @@ private: | |||||||
|             // Since we don't know how the shader will use the shader, hint the driver to disable as
 |             // Since we don't know how the shader will use the shader, hint the driver to disable as
 | ||||||
|             // much optimizations as possible
 |             // much optimizations as possible
 | ||||||
|             std::string qualifier = "coherent volatile"; |             std::string qualifier = "coherent volatile"; | ||||||
|             if (usage.is_read && !usage.is_written) |             if (usage.is_read && !usage.is_written) { | ||||||
|                 qualifier += " readonly"; |                 qualifier += " readonly"; | ||||||
|             else if (usage.is_written && !usage.is_read) |             } else if (usage.is_written && !usage.is_read) { | ||||||
|                 qualifier += " writeonly"; |                 qualifier += " writeonly"; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             const std::string binding = |             code.AddLine("layout (std430, binding = GMEM_BINDING_{}_{}) {} buffer {} {{", | ||||||
|                 fmt::format("GMEM_BINDING_{}_{}", base.cbuf_index, base.cbuf_offset); |                          base.cbuf_index, base.cbuf_offset, qualifier, GetGlobalMemoryBlock(base)); | ||||||
|             code.AddLine("layout (std430, binding = " + binding + ") " + qualifier + " buffer " + |             code.AddLine("    float {}[];", GetGlobalMemory(base)); | ||||||
|                          GetGlobalMemoryBlock(base) + " {"); |             code.AddLine("}};"); | ||||||
|             code.AddLine("    float " + GetGlobalMemory(base) + "[];"); |  | ||||||
|             code.AddLine("};"); |  | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -435,7 +434,7 @@ private: | |||||||
|     void DeclareSamplers() { |     void DeclareSamplers() { | ||||||
|         const auto& samplers = ir.GetSamplers(); |         const auto& samplers = ir.GetSamplers(); | ||||||
|         for (const auto& sampler : samplers) { |         for (const auto& sampler : samplers) { | ||||||
|             std::string sampler_type = [&]() { |             std::string sampler_type = [&sampler] { | ||||||
|                 switch (sampler.GetType()) { |                 switch (sampler.GetType()) { | ||||||
|                 case Tegra::Shader::TextureType::Texture1D: |                 case Tegra::Shader::TextureType::Texture1D: | ||||||
|                     return "sampler1D"; |                     return "sampler1D"; | ||||||
| @ -450,25 +449,28 @@ private: | |||||||
|                     return "sampler2D"; |                     return "sampler2D"; | ||||||
|                 } |                 } | ||||||
|             }(); |             }(); | ||||||
|             if (sampler.IsArray()) |             if (sampler.IsArray()) { | ||||||
|                 sampler_type += "Array"; |                 sampler_type += "Array"; | ||||||
|             if (sampler.IsShadow()) |             } | ||||||
|  |             if (sampler.IsShadow()) { | ||||||
|                 sampler_type += "Shadow"; |                 sampler_type += "Shadow"; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             code.AddLine("layout (binding = SAMPLER_BINDING_" + std::to_string(sampler.GetIndex()) + |             code.AddLine("layout (binding = SAMPLER_BINDING_{}) uniform {} {};", sampler.GetIndex(), | ||||||
|                          ") uniform " + sampler_type + ' ' + GetSampler(sampler) + ';'); |                          sampler_type, GetSampler(sampler)); | ||||||
|         } |         } | ||||||
|         if (!samplers.empty()) |         if (!samplers.empty()) { | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclarePhysicalAttributeReader() { |     void DeclarePhysicalAttributeReader() { | ||||||
|         if (!ir.HasPhysicalAttributes()) { |         if (!ir.HasPhysicalAttributes()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         code.AddLine("float readPhysicalAttribute(uint physical_address) {"); |         code.AddLine("float readPhysicalAttribute(uint physical_address) {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
|         code.AddLine("switch (physical_address) {"); |         code.AddLine("switch (physical_address) {{"); | ||||||
| 
 | 
 | ||||||
|         // Just declare generic attributes for now.
 |         // Just declare generic attributes for now.
 | ||||||
|         const auto num_attributes{static_cast<u32>(GetNumPhysicalInputAttributes())}; |         const auto num_attributes{static_cast<u32>(GetNumPhysicalInputAttributes())}; | ||||||
| @ -483,15 +485,15 @@ private: | |||||||
|                 const bool declared{stage != ShaderStage::Fragment || |                 const bool declared{stage != ShaderStage::Fragment || | ||||||
|                                     header.ps.GetAttributeUse(index) != AttributeUse::Unused}; |                                     header.ps.GetAttributeUse(index) != AttributeUse::Unused}; | ||||||
|                 const std::string value{declared ? ReadAttribute(attribute, element) : "0"}; |                 const std::string value{declared ? ReadAttribute(attribute, element) : "0"}; | ||||||
|                 code.AddLine(fmt::format("case 0x{:x}: return {};", address, value)); |                 code.AddLine("case 0x{:x}: return {};", address, value); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine("default: return 0;"); |         code.AddLine("default: return 0;"); | ||||||
| 
 | 
 | ||||||
|         code.AddLine('}'); |         code.AddLine("}}"); | ||||||
|         --code.scope; |         --code.scope; | ||||||
|         code.AddLine('}'); |         code.AddLine("}}"); | ||||||
|         code.AddNewLine(); |         code.AddNewLine(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -516,23 +518,26 @@ private: | |||||||
|                 return {}; |                 return {}; | ||||||
|             } |             } | ||||||
|             return (this->*decompiler)(*operation); |             return (this->*decompiler)(*operation); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto gpr = std::get_if<GprNode>(node)) { |         if (const auto gpr = std::get_if<GprNode>(node)) { | ||||||
|             const u32 index = gpr->GetIndex(); |             const u32 index = gpr->GetIndex(); | ||||||
|             if (index == Register::ZeroIndex) { |             if (index == Register::ZeroIndex) { | ||||||
|                 return "0"; |                 return "0"; | ||||||
|             } |             } | ||||||
|             return GetRegister(index); |             return GetRegister(index); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto immediate = std::get_if<ImmediateNode>(node)) { |         if (const auto immediate = std::get_if<ImmediateNode>(node)) { | ||||||
|             const u32 value = immediate->GetValue(); |             const u32 value = immediate->GetValue(); | ||||||
|             if (value < 10) { |             if (value < 10) { | ||||||
|                 // For eyecandy avoid using hex numbers on single digits
 |                 // For eyecandy avoid using hex numbers on single digits
 | ||||||
|                 return fmt::format("utof({}u)", immediate->GetValue()); |                 return fmt::format("utof({}u)", immediate->GetValue()); | ||||||
|             } |             } | ||||||
|             return fmt::format("utof(0x{:x}u)", immediate->GetValue()); |             return fmt::format("utof(0x{:x}u)", immediate->GetValue()); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto predicate = std::get_if<PredicateNode>(node)) { |         if (const auto predicate = std::get_if<PredicateNode>(node)) { | ||||||
|             const auto value = [&]() -> std::string { |             const auto value = [&]() -> std::string { | ||||||
|                 switch (const auto index = predicate->GetIndex(); index) { |                 switch (const auto index = predicate->GetIndex(); index) { | ||||||
|                 case Tegra::Shader::Pred::UnusedIndex: |                 case Tegra::Shader::Pred::UnusedIndex: | ||||||
| @ -544,19 +549,22 @@ private: | |||||||
|                 } |                 } | ||||||
|             }(); |             }(); | ||||||
|             if (predicate->IsNegated()) { |             if (predicate->IsNegated()) { | ||||||
|                 return "!(" + value + ')'; |                 return fmt::format("!({})", value); | ||||||
|             } |             } | ||||||
|             return value; |             return value; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto abuf = std::get_if<AbufNode>(node)) { |         if (const auto abuf = std::get_if<AbufNode>(node)) { | ||||||
|             UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, |             UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, | ||||||
|                                  "Physical attributes in geometry shaders are not implemented"); |                                  "Physical attributes in geometry shaders are not implemented"); | ||||||
|             if (abuf->IsPhysicalBuffer()) { |             if (abuf->IsPhysicalBuffer()) { | ||||||
|                 return "readPhysicalAttribute(ftou(" + Visit(abuf->GetPhysicalAddress()) + "))"; |                 return fmt::format("readPhysicalAttribute(ftou({}))", | ||||||
|  |                                    Visit(abuf->GetPhysicalAddress())); | ||||||
|             } |             } | ||||||
|             return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); |             return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto cbuf = std::get_if<CbufNode>(node)) { |         if (const auto cbuf = std::get_if<CbufNode>(node)) { | ||||||
|             const Node offset = cbuf->GetOffset(); |             const Node offset = cbuf->GetOffset(); | ||||||
|             if (const auto immediate = std::get_if<ImmediateNode>(offset)) { |             if (const auto immediate = std::get_if<ImmediateNode>(offset)) { | ||||||
|                 // Direct access
 |                 // Direct access
 | ||||||
| @ -564,57 +572,63 @@ private: | |||||||
|                 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); |                 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); | ||||||
|                 return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), |                 return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), | ||||||
|                                    offset_imm / (4 * 4), (offset_imm / 4) % 4); |                                    offset_imm / (4 * 4), (offset_imm / 4) % 4); | ||||||
| 
 |  | ||||||
|             } else if (std::holds_alternative<OperationNode>(*offset)) { |  | ||||||
|                 // Indirect access
 |  | ||||||
|                 const std::string final_offset = code.GenerateTemporary(); |  | ||||||
|                 code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4);"); |  | ||||||
|                 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), |  | ||||||
|                                    final_offset, final_offset); |  | ||||||
| 
 |  | ||||||
|             } else { |  | ||||||
|                 UNREACHABLE_MSG("Unmanaged offset node type"); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto gmem = std::get_if<GmemNode>(node)) { |             if (std::holds_alternative<OperationNode>(*offset)) { | ||||||
|  |                 // Indirect access
 | ||||||
|  |                 const std::string final_offset = code.GenerateTemporary(); | ||||||
|  |                 code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset)); | ||||||
|  |                 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), | ||||||
|  |                                    final_offset, final_offset); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             UNREACHABLE_MSG("Unmanaged offset node type"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (const auto gmem = std::get_if<GmemNode>(node)) { | ||||||
|             const std::string real = Visit(gmem->GetRealAddress()); |             const std::string real = Visit(gmem->GetRealAddress()); | ||||||
|             const std::string base = Visit(gmem->GetBaseAddress()); |             const std::string base = Visit(gmem->GetBaseAddress()); | ||||||
|             const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; |             const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); | ||||||
|             return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); |             return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto lmem = std::get_if<LmemNode>(node)) { |         if (const auto lmem = std::get_if<LmemNode>(node)) { | ||||||
|             return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); |             return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { |         if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { | ||||||
|             return GetInternalFlag(internal_flag->GetFlag()); |             return GetInternalFlag(internal_flag->GetFlag()); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto conditional = std::get_if<ConditionalNode>(node)) { |         if (const auto conditional = std::get_if<ConditionalNode>(node)) { | ||||||
|             // It's invalid to call conditional on nested nodes, use an operation instead
 |             // It's invalid to call conditional on nested nodes, use an operation instead
 | ||||||
|             code.AddLine("if (" + Visit(conditional->GetCondition()) + ") {"); |             code.AddLine("if ({}) {{", Visit(conditional->GetCondition())); | ||||||
|             ++code.scope; |             ++code.scope; | ||||||
| 
 | 
 | ||||||
|             VisitBlock(conditional->GetCode()); |             VisitBlock(conditional->GetCode()); | ||||||
| 
 | 
 | ||||||
|             --code.scope; |             --code.scope; | ||||||
|             code.AddLine('}'); |             code.AddLine("}}"); | ||||||
|             return {}; |             return {}; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         } else if (const auto comment = std::get_if<CommentNode>(node)) { |         if (const auto comment = std::get_if<CommentNode>(node)) { | ||||||
|             return "// " + comment->GetText(); |             return "// " + comment->GetText(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { |     std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { | ||||||
|         const auto GeometryPass = [&](std::string name) { |         const auto GeometryPass = [&](std::string_view name) { | ||||||
|             if (stage == ShaderStage::Geometry && buffer) { |             if (stage == ShaderStage::Geometry && buffer) { | ||||||
|                 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
 |                 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
 | ||||||
|                 // set an 0x80000000 index for those and the shader fails to build. Find out why
 |                 // set an 0x80000000 index for those and the shader fails to build. Find out why
 | ||||||
|                 // this happens and what's its intent.
 |                 // this happens and what's its intent.
 | ||||||
|                 return "gs_" + std::move(name) + "[ftou(" + Visit(buffer) + ") % MAX_VERTEX_INPUT]"; |                 return fmt::format("gs_{}[ftou({}) % MAX_VERTEX_INPUT]", name, Visit(buffer)); | ||||||
|             } |             } | ||||||
|             return name; |             return std::string(name); | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         switch (attribute) { |         switch (attribute) { | ||||||
| @ -677,7 +691,7 @@ private: | |||||||
|         const std::string precise = stage != ShaderStage::Fragment ? "precise " : ""; |         const std::string precise = stage != ShaderStage::Fragment ? "precise " : ""; | ||||||
| 
 | 
 | ||||||
|         const std::string temporary = code.GenerateTemporary(); |         const std::string temporary = code.GenerateTemporary(); | ||||||
|         code.AddLine(precise + "float " + temporary + " = " + value + ';'); |         code.AddLine("{}float {} = {};", precise, temporary, value); | ||||||
|         return temporary; |         return temporary; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -691,7 +705,7 @@ private: | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const std::string temporary = code.GenerateTemporary(); |         const std::string temporary = code.GenerateTemporary(); | ||||||
|         code.AddLine("float " + temporary + " = " + Visit(operand) + ';'); |         code.AddLine("float {} = {};", temporary, Visit(operand)); | ||||||
|         return temporary; |         return temporary; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -706,31 +720,32 @@ private: | |||||||
|         case Type::Float: |         case Type::Float: | ||||||
|             return value; |             return value; | ||||||
|         case Type::Int: |         case Type::Int: | ||||||
|             return "ftoi(" + value + ')'; |             return fmt::format("ftoi({})", value); | ||||||
|         case Type::Uint: |         case Type::Uint: | ||||||
|             return "ftou(" + value + ')'; |             return fmt::format("ftou({})", value); | ||||||
|         case Type::HalfFloat: |         case Type::HalfFloat: | ||||||
|             return "toHalf2(" + value + ')'; |             return fmt::format("toHalf2({})", value); | ||||||
|         } |         } | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|         return value; |         return value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string BitwiseCastResult(std::string value, Type type, bool needs_parenthesis = false) { |     std::string BitwiseCastResult(const std::string& value, Type type, | ||||||
|  |                                   bool needs_parenthesis = false) { | ||||||
|         switch (type) { |         switch (type) { | ||||||
|         case Type::Bool: |         case Type::Bool: | ||||||
|         case Type::Bool2: |         case Type::Bool2: | ||||||
|         case Type::Float: |         case Type::Float: | ||||||
|             if (needs_parenthesis) { |             if (needs_parenthesis) { | ||||||
|                 return '(' + value + ')'; |                 return fmt::format("({})", value); | ||||||
|             } |             } | ||||||
|             return value; |             return value; | ||||||
|         case Type::Int: |         case Type::Int: | ||||||
|             return "itof(" + value + ')'; |             return fmt::format("itof({})", value); | ||||||
|         case Type::Uint: |         case Type::Uint: | ||||||
|             return "utof(" + value + ')'; |             return fmt::format("utof({})", value); | ||||||
|         case Type::HalfFloat: |         case Type::HalfFloat: | ||||||
|             return "fromHalf2(" + value + ')'; |             return fmt::format("fromHalf2({})", value); | ||||||
|         } |         } | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|         return value; |         return value; | ||||||
| @ -738,27 +753,27 @@ private: | |||||||
| 
 | 
 | ||||||
|     std::string GenerateUnary(Operation operation, const std::string& func, Type result_type, |     std::string GenerateUnary(Operation operation, const std::string& func, Type result_type, | ||||||
|                               Type type_a, bool needs_parenthesis = true) { |                               Type type_a, bool needs_parenthesis = true) { | ||||||
|         return ApplyPrecise(operation, |         const std::string op_str = fmt::format("{}({})", func, VisitOperand(operation, 0, type_a)); | ||||||
|                             BitwiseCastResult(func + '(' + VisitOperand(operation, 0, type_a) + ')', | 
 | ||||||
|                                               result_type, needs_parenthesis)); |         return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type, needs_parenthesis)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type, |     std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type, | ||||||
|                                     Type type_a, Type type_b) { |                                     Type type_a, Type type_b) { | ||||||
|         const std::string op_a = VisitOperand(operation, 0, type_a); |         const std::string op_a = VisitOperand(operation, 0, type_a); | ||||||
|         const std::string op_b = VisitOperand(operation, 1, type_b); |         const std::string op_b = VisitOperand(operation, 1, type_b); | ||||||
|  |         const std::string op_str = fmt::format("({} {} {})", op_a, func, op_b); | ||||||
| 
 | 
 | ||||||
|         return ApplyPrecise( |         return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); | ||||||
|             operation, BitwiseCastResult('(' + op_a + ' ' + func + ' ' + op_b + ')', result_type)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, |     std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, | ||||||
|                                    Type type_a, Type type_b) { |                                    Type type_a, Type type_b) { | ||||||
|         const std::string op_a = VisitOperand(operation, 0, type_a); |         const std::string op_a = VisitOperand(operation, 0, type_a); | ||||||
|         const std::string op_b = VisitOperand(operation, 1, type_b); |         const std::string op_b = VisitOperand(operation, 1, type_b); | ||||||
|  |         const std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b); | ||||||
| 
 | 
 | ||||||
|         return ApplyPrecise(operation, |         return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); | ||||||
|                             BitwiseCastResult(func + '(' + op_a + ", " + op_b + ')', result_type)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, |     std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, | ||||||
| @ -766,10 +781,9 @@ private: | |||||||
|         const std::string op_a = VisitOperand(operation, 0, type_a); |         const std::string op_a = VisitOperand(operation, 0, type_a); | ||||||
|         const std::string op_b = VisitOperand(operation, 1, type_b); |         const std::string op_b = VisitOperand(operation, 1, type_b); | ||||||
|         const std::string op_c = VisitOperand(operation, 2, type_c); |         const std::string op_c = VisitOperand(operation, 2, type_c); | ||||||
|  |         const std::string op_str = fmt::format("{}({}, {}, {})", func, op_a, op_b, op_c); | ||||||
| 
 | 
 | ||||||
|         return ApplyPrecise( |         return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); | ||||||
|             operation, |  | ||||||
|             BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + op_c + ')', result_type)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, |     std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, | ||||||
| @ -778,10 +792,9 @@ private: | |||||||
|         const std::string op_b = VisitOperand(operation, 1, type_b); |         const std::string op_b = VisitOperand(operation, 1, type_b); | ||||||
|         const std::string op_c = VisitOperand(operation, 2, type_c); |         const std::string op_c = VisitOperand(operation, 2, type_c); | ||||||
|         const std::string op_d = VisitOperand(operation, 3, type_d); |         const std::string op_d = VisitOperand(operation, 3, type_d); | ||||||
|  |         const std::string op_str = fmt::format("{}({}, {}, {}, {})", func, op_a, op_b, op_c, op_d); | ||||||
| 
 | 
 | ||||||
|         return ApplyPrecise(operation, BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + |         return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type)); | ||||||
|                                                              op_c + ", " + op_d + ')', |  | ||||||
|                                                          result_type)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GenerateTexture(Operation operation, const std::string& function_suffix, |     std::string GenerateTexture(Operation operation, const std::string& function_suffix, | ||||||
| @ -844,7 +857,7 @@ private: | |||||||
|                 // required to be constant)
 |                 // required to be constant)
 | ||||||
|                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); |                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||||||
|             } else { |             } else { | ||||||
|                 expr += "ftoi(" + Visit(operand) + ')'; |                 expr += fmt::format("ftoi({})", Visit(operand)); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         case Type::Float: |         case Type::Float: | ||||||
| @ -877,7 +890,7 @@ private: | |||||||
|                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); |                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||||||
|             } else if (device.HasVariableAoffi()) { |             } else if (device.HasVariableAoffi()) { | ||||||
|                 // Avoid using variable AOFFI on unsupported devices.
 |                 // Avoid using variable AOFFI on unsupported devices.
 | ||||||
|                 expr += "ftoi(" + Visit(operand) + ')'; |                 expr += fmt::format("ftoi({})", Visit(operand)); | ||||||
|             } else { |             } else { | ||||||
|                 // Insert 0 on devices not supporting variable AOFFI.
 |                 // Insert 0 on devices not supporting variable AOFFI.
 | ||||||
|                 expr += '0'; |                 expr += '0'; | ||||||
| @ -902,7 +915,6 @@ private: | |||||||
|                 return {}; |                 return {}; | ||||||
|             } |             } | ||||||
|             target = GetRegister(gpr->GetIndex()); |             target = GetRegister(gpr->GetIndex()); | ||||||
| 
 |  | ||||||
|         } else if (const auto abuf = std::get_if<AbufNode>(dest)) { |         } else if (const auto abuf = std::get_if<AbufNode>(dest)) { | ||||||
|             UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); |             UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); | ||||||
| 
 | 
 | ||||||
| @ -913,9 +925,9 @@ private: | |||||||
|                 case Attribute::Index::PointSize: |                 case Attribute::Index::PointSize: | ||||||
|                     return "gl_PointSize"; |                     return "gl_PointSize"; | ||||||
|                 case Attribute::Index::ClipDistances0123: |                 case Attribute::Index::ClipDistances0123: | ||||||
|                     return "gl_ClipDistance[" + std::to_string(abuf->GetElement()) + ']'; |                     return fmt::format("gl_ClipDistance[{}]", abuf->GetElement()); | ||||||
|                 case Attribute::Index::ClipDistances4567: |                 case Attribute::Index::ClipDistances4567: | ||||||
|                     return "gl_ClipDistance[" + std::to_string(abuf->GetElement() + 4) + ']'; |                     return fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4); | ||||||
|                 default: |                 default: | ||||||
|                     if (IsGenericAttribute(attribute)) { |                     if (IsGenericAttribute(attribute)) { | ||||||
|                         return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); |                         return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); | ||||||
| @ -925,21 +937,18 @@ private: | |||||||
|                     return "0"; |                     return "0"; | ||||||
|                 } |                 } | ||||||
|             }(); |             }(); | ||||||
| 
 |  | ||||||
|         } else if (const auto lmem = std::get_if<LmemNode>(dest)) { |         } else if (const auto lmem = std::get_if<LmemNode>(dest)) { | ||||||
|             target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; |             target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); | ||||||
| 
 |  | ||||||
|         } else if (const auto gmem = std::get_if<GmemNode>(dest)) { |         } else if (const auto gmem = std::get_if<GmemNode>(dest)) { | ||||||
|             const std::string real = Visit(gmem->GetRealAddress()); |             const std::string real = Visit(gmem->GetRealAddress()); | ||||||
|             const std::string base = Visit(gmem->GetBaseAddress()); |             const std::string base = Visit(gmem->GetBaseAddress()); | ||||||
|             const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; |             const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); | ||||||
|             target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); |             target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); | ||||||
| 
 |  | ||||||
|         } else { |         } else { | ||||||
|             UNREACHABLE_MSG("Assign called without a proper target"); |             UNREACHABLE_MSG("Assign called without a proper target"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine(target + " = " + Visit(src) + ';'); |         code.AddLine("{} = {};", target, Visit(src)); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -992,8 +1001,9 @@ private: | |||||||
|         const std::string condition = Visit(operation[0]); |         const std::string condition = Visit(operation[0]); | ||||||
|         const std::string true_case = Visit(operation[1]); |         const std::string true_case = Visit(operation[1]); | ||||||
|         const std::string false_case = Visit(operation[2]); |         const std::string false_case = Visit(operation[2]); | ||||||
|         return ApplyPrecise(operation, |         const std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case); | ||||||
|                             '(' + condition + " ? " + true_case + " : " + false_case + ')'); | 
 | ||||||
|  |         return ApplyPrecise(operation, op_str); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string FCos(Operation operation) { |     std::string FCos(Operation operation) { | ||||||
| @ -1057,9 +1067,9 @@ private: | |||||||
|     std::string ILogicalShiftRight(Operation operation) { |     std::string ILogicalShiftRight(Operation operation) { | ||||||
|         const std::string op_a = VisitOperand(operation, 0, Type::Uint); |         const std::string op_a = VisitOperand(operation, 0, Type::Uint); | ||||||
|         const std::string op_b = VisitOperand(operation, 1, Type::Uint); |         const std::string op_b = VisitOperand(operation, 1, Type::Uint); | ||||||
|  |         const std::string op_str = fmt::format("int({} >> {})", op_a, op_b); | ||||||
| 
 | 
 | ||||||
|         return ApplyPrecise(operation, |         return ApplyPrecise(operation, BitwiseCastResult(op_str, Type::Int)); | ||||||
|                             BitwiseCastResult("int(" + op_a + " >> " + op_b + ')', Type::Int)); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string IArithmeticShiftRight(Operation operation) { |     std::string IArithmeticShiftRight(Operation operation) { | ||||||
| @ -1115,11 +1125,12 @@ private: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string HNegate(Operation operation) { |     std::string HNegate(Operation operation) { | ||||||
|         const auto GetNegate = [&](std::size_t index) -> std::string { |         const auto GetNegate = [&](std::size_t index) { | ||||||
|             return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; |             return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; | ||||||
|         }; |         }; | ||||||
|         const std::string value = '(' + VisitOperand(operation, 0, Type::HalfFloat) + " * vec2(" + |         const std::string value = | ||||||
|                                   GetNegate(1) + ", " + GetNegate(2) + "))"; |             fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0, Type::HalfFloat), | ||||||
|  |                         GetNegate(1), GetNegate(2)); | ||||||
|         return BitwiseCastResult(value, Type::HalfFloat); |         return BitwiseCastResult(value, Type::HalfFloat); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1127,7 +1138,8 @@ private: | |||||||
|         const std::string value = VisitOperand(operation, 0, Type::HalfFloat); |         const std::string value = VisitOperand(operation, 0, Type::HalfFloat); | ||||||
|         const std::string min = VisitOperand(operation, 1, Type::Float); |         const std::string min = VisitOperand(operation, 1, Type::Float); | ||||||
|         const std::string max = VisitOperand(operation, 2, Type::Float); |         const std::string max = VisitOperand(operation, 2, Type::Float); | ||||||
|         const std::string clamped = "clamp(" + value + ", vec2(" + min + "), vec2(" + max + "))"; |         const std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max); | ||||||
|  | 
 | ||||||
|         return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); |         return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1138,34 +1150,35 @@ private: | |||||||
|             case Tegra::Shader::HalfType::H0_H1: |             case Tegra::Shader::HalfType::H0_H1: | ||||||
|                 return operand; |                 return operand; | ||||||
|             case Tegra::Shader::HalfType::F32: |             case Tegra::Shader::HalfType::F32: | ||||||
|                 return "vec2(fromHalf2(" + operand + "))"; |                 return fmt::format("vec2(fromHalf2({}))", operand); | ||||||
|             case Tegra::Shader::HalfType::H0_H0: |             case Tegra::Shader::HalfType::H0_H0: | ||||||
|                 return "vec2(" + operand + "[0])"; |                 return fmt::format("vec2({}[0])", operand); | ||||||
|             case Tegra::Shader::HalfType::H1_H1: |             case Tegra::Shader::HalfType::H1_H1: | ||||||
|                 return "vec2(" + operand + "[1])"; |                 return fmt::format("vec2({}[1])", operand); | ||||||
|             } |             } | ||||||
|             UNREACHABLE(); |             UNREACHABLE(); | ||||||
|             return "0"; |             return "0"; | ||||||
|         }(); |         }(); | ||||||
|         return "fromHalf2(" + value + ')'; |         return fmt::format("fromHalf2({})", value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string HMergeF32(Operation operation) { |     std::string HMergeF32(Operation operation) { | ||||||
|         return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; |         return fmt::format("float(toHalf2({})[0])", Visit(operation[0])); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string HMergeH0(Operation operation) { |     std::string HMergeH0(Operation operation) { | ||||||
|         return "fromHalf2(vec2(toHalf2(" + Visit(operation[1]) + ")[0], toHalf2(" + |         return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[1]), | ||||||
|                Visit(operation[0]) + ")[1]))"; |                            Visit(operation[0])); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string HMergeH1(Operation operation) { |     std::string HMergeH1(Operation operation) { | ||||||
|         return "fromHalf2(vec2(toHalf2(" + Visit(operation[0]) + ")[0], toHalf2(" + |         return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[0]), | ||||||
|                Visit(operation[1]) + ")[1]))"; |                            Visit(operation[1])); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string HPack2(Operation operation) { |     std::string HPack2(Operation operation) { | ||||||
|         return "utof(packHalf2x16(vec2(" + Visit(operation[0]) + ", " + Visit(operation[1]) + ")))"; |         return fmt::format("utof(packHalf2x16(vec2({}, {})))", Visit(operation[0]), | ||||||
|  |                            Visit(operation[1])); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template <Type type> |     template <Type type> | ||||||
| @ -1223,7 +1236,7 @@ private: | |||||||
|             target = GetInternalFlag(flag->GetFlag()); |             target = GetInternalFlag(flag->GetFlag()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine(target + " = " + Visit(src) + ';'); |         code.AddLine("{} = {};", target, Visit(src)); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1245,7 +1258,7 @@ private: | |||||||
| 
 | 
 | ||||||
|     std::string LogicalPick2(Operation operation) { |     std::string LogicalPick2(Operation operation) { | ||||||
|         const std::string pair = VisitOperand(operation, 0, Type::Bool2); |         const std::string pair = VisitOperand(operation, 0, Type::Bool2); | ||||||
|         return pair + '[' + VisitOperand(operation, 1, Type::Uint) + ']'; |         return fmt::format("{}[{}]", pair, VisitOperand(operation, 1, Type::Uint)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string LogicalAll2(Operation operation) { |     std::string LogicalAll2(Operation operation) { | ||||||
| @ -1257,15 +1270,15 @@ private: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template <bool with_nan> |     template <bool with_nan> | ||||||
|     std::string GenerateHalfComparison(Operation operation, std::string compare_op) { |     std::string GenerateHalfComparison(Operation operation, const std::string& compare_op) { | ||||||
|         std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, |         const std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, | ||||||
|                                                   Type::HalfFloat, Type::HalfFloat)}; |                                                         Type::HalfFloat, Type::HalfFloat)}; | ||||||
|         if constexpr (!with_nan) { |         if constexpr (!with_nan) { | ||||||
|             return comparison; |             return comparison; | ||||||
|         } |         } | ||||||
|         return "halfFloatNanComparison(" + comparison + ", " + |         return fmt::format("halfFloatNanComparison({}, {}, {})", comparison, | ||||||
|                VisitOperand(operation, 0, Type::HalfFloat) + ", " + |                            VisitOperand(operation, 0, Type::HalfFloat), | ||||||
|                VisitOperand(operation, 1, Type::HalfFloat) + ')'; |                            VisitOperand(operation, 1, Type::HalfFloat)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template <bool with_nan> |     template <bool with_nan> | ||||||
| @ -1342,12 +1355,12 @@ private: | |||||||
|         switch (meta->element) { |         switch (meta->element) { | ||||||
|         case 0: |         case 0: | ||||||
|         case 1: |         case 1: | ||||||
|             return "itof(int(textureSize(" + sampler + ", " + lod + ')' + |             return fmt::format("itof(int(textureSize({}, {}){}))", sampler, lod, | ||||||
|                    GetSwizzle(meta->element) + "))"; |                                GetSwizzle(meta->element)); | ||||||
|         case 2: |         case 2: | ||||||
|             return "0"; |             return "0"; | ||||||
|         case 3: |         case 3: | ||||||
|             return "itof(textureQueryLevels(" + sampler + "))"; |             return fmt::format("itof(textureQueryLevels({}))", sampler); | ||||||
|         } |         } | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|         return "0"; |         return "0"; | ||||||
| @ -1358,8 +1371,9 @@ private: | |||||||
|         ASSERT(meta); |         ASSERT(meta); | ||||||
| 
 | 
 | ||||||
|         if (meta->element < 2) { |         if (meta->element < 2) { | ||||||
|             return "itof(int((" + GenerateTexture(operation, "QueryLod", {}) + " * vec2(256))" + |             return fmt::format("itof(int(({} * vec2(256)){}))", | ||||||
|                    GetSwizzle(meta->element) + "))"; |                                GenerateTexture(operation, "QueryLod", {}), | ||||||
|  |                                GetSwizzle(meta->element)); | ||||||
|         } |         } | ||||||
|         return "0"; |         return "0"; | ||||||
|     } |     } | ||||||
| @ -1398,7 +1412,7 @@ private: | |||||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); |         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||||
|         UNIMPLEMENTED_IF(!target); |         UNIMPLEMENTED_IF(!target); | ||||||
| 
 | 
 | ||||||
|         code.AddLine(fmt::format("jmp_to = 0x{:x}u;", target->GetValue())); |         code.AddLine("jmp_to = 0x{:x}u;", target->GetValue()); | ||||||
|         code.AddLine("break;"); |         code.AddLine("break;"); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| @ -1407,7 +1421,7 @@ private: | |||||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); |         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||||
|         UNIMPLEMENTED_IF(!target); |         UNIMPLEMENTED_IF(!target); | ||||||
| 
 | 
 | ||||||
|         code.AddLine(fmt::format("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue())); |         code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue()); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1433,7 +1447,7 @@ private: | |||||||
| 
 | 
 | ||||||
|         UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); |         UNIMPLEMENTED_IF_MSG(header.ps.omap.sample_mask != 0, "Sample mask write is unimplemented"); | ||||||
| 
 | 
 | ||||||
|         code.AddLine("if (alpha_test[0] != 0) {"); |         code.AddLine("if (alpha_test[0] != 0) {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
|         // We start on the register containing the alpha value in the first RT.
 |         // We start on the register containing the alpha value in the first RT.
 | ||||||
|         u32 current_reg = 3; |         u32 current_reg = 3; | ||||||
| @ -1444,13 +1458,12 @@ private: | |||||||
|                 header.ps.IsColorComponentOutputEnabled(render_target, 1) || |                 header.ps.IsColorComponentOutputEnabled(render_target, 1) || | ||||||
|                 header.ps.IsColorComponentOutputEnabled(render_target, 2) || |                 header.ps.IsColorComponentOutputEnabled(render_target, 2) || | ||||||
|                 header.ps.IsColorComponentOutputEnabled(render_target, 3)) { |                 header.ps.IsColorComponentOutputEnabled(render_target, 3)) { | ||||||
|                 code.AddLine( |                 code.AddLine("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg)); | ||||||
|                     fmt::format("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg))); |  | ||||||
|                 current_reg += 4; |                 current_reg += 4; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         --code.scope; |         --code.scope; | ||||||
|         code.AddLine('}'); |         code.AddLine("}}"); | ||||||
| 
 | 
 | ||||||
|         // Write the color outputs using the data in the shader registers, disabled
 |         // Write the color outputs using the data in the shader registers, disabled
 | ||||||
|         // rendertargets/components are skipped in the register assignment.
 |         // rendertargets/components are skipped in the register assignment.
 | ||||||
| @ -1459,8 +1472,8 @@ private: | |||||||
|             // TODO(Subv): Figure out how dual-source blending is configured in the Switch.
 |             // TODO(Subv): Figure out how dual-source blending is configured in the Switch.
 | ||||||
|             for (u32 component = 0; component < 4; ++component) { |             for (u32 component = 0; component < 4; ++component) { | ||||||
|                 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { |                 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { | ||||||
|                     code.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, |                     code.AddLine("FragColor{}[{}] = {};", render_target, component, | ||||||
|                                              SafeGetRegister(current_reg))); |                                  SafeGetRegister(current_reg)); | ||||||
|                     ++current_reg; |                     ++current_reg; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -1469,7 +1482,7 @@ private: | |||||||
|         if (header.ps.omap.depth) { |         if (header.ps.omap.depth) { | ||||||
|             // The depth output is always 2 registers after the last color output, and current_reg
 |             // The depth output is always 2 registers after the last color output, and current_reg
 | ||||||
|             // already contains one past the last color register.
 |             // already contains one past the last color register.
 | ||||||
|             code.AddLine("gl_FragDepth = " + SafeGetRegister(current_reg + 1) + ';'); |             code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine("return;"); |         code.AddLine("return;"); | ||||||
| @ -1479,11 +1492,11 @@ private: | |||||||
|     std::string Discard(Operation operation) { |     std::string Discard(Operation operation) { | ||||||
|         // Enclose "discard" in a conditional, so that GLSL compilation does not complain
 |         // Enclose "discard" in a conditional, so that GLSL compilation does not complain
 | ||||||
|         // about unexecuted instructions that may follow this.
 |         // about unexecuted instructions that may follow this.
 | ||||||
|         code.AddLine("if (true) {"); |         code.AddLine("if (true) {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
|         code.AddLine("discard;"); |         code.AddLine("discard;"); | ||||||
|         --code.scope; |         --code.scope; | ||||||
|         code.AddLine("}"); |         code.AddLine("}}"); | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1697,7 +1710,7 @@ private: | |||||||
|         const auto index = static_cast<u32>(flag); |         const auto index = static_cast<u32>(flag); | ||||||
|         ASSERT(index < static_cast<u32>(InternalFlag::Amount)); |         ASSERT(index < static_cast<u32>(InternalFlag::Amount)); | ||||||
| 
 | 
 | ||||||
|         return std::string(InternalFlagNames[index]) + '_' + suffix; |         return fmt::format("{}_{}", InternalFlagNames[index], suffix); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GetSampler(const Sampler& sampler) const { |     std::string GetSampler(const Sampler& sampler) const { | ||||||
| @ -1705,7 +1718,7 @@ private: | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const { |     std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const { | ||||||
|         return name + '_' + std::to_string(index) + '_' + suffix; |         return fmt::format("{}_{}_{}", name, index, suffix); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u32 GetNumPhysicalInputAttributes() const { |     u32 GetNumPhysicalInputAttributes() const { | ||||||
| @ -1733,24 +1746,25 @@ private: | |||||||
| } // Anonymous namespace
 | } // Anonymous namespace
 | ||||||
| 
 | 
 | ||||||
| std::string GetCommonDeclarations() { | std::string GetCommonDeclarations() { | ||||||
|     const auto cbuf = std::to_string(MAX_CONSTBUFFER_ELEMENTS); |     return fmt::format( | ||||||
|     return "#define MAX_CONSTBUFFER_ELEMENTS " + cbuf + "\n" + |         "#define MAX_CONSTBUFFER_ELEMENTS {}\n" | ||||||
|            "#define ftoi floatBitsToInt\n" |         "#define ftoi floatBitsToInt\n" | ||||||
|            "#define ftou floatBitsToUint\n" |         "#define ftou floatBitsToUint\n" | ||||||
|            "#define itof intBitsToFloat\n" |         "#define itof intBitsToFloat\n" | ||||||
|            "#define utof uintBitsToFloat\n\n" |         "#define utof uintBitsToFloat\n\n" | ||||||
|            "float fromHalf2(vec2 pair) {\n" |         "float fromHalf2(vec2 pair) {{\n" | ||||||
|            "    return utof(packHalf2x16(pair));\n" |         "    return utof(packHalf2x16(pair));\n" | ||||||
|            "}\n\n" |         "}}\n\n" | ||||||
|            "vec2 toHalf2(float value) {\n" |         "vec2 toHalf2(float value) {{\n" | ||||||
|            "    return unpackHalf2x16(ftou(value));\n" |         "    return unpackHalf2x16(ftou(value));\n" | ||||||
|            "}\n\n" |         "}}\n\n" | ||||||
|            "bvec2 halfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {\n" |         "bvec2 halfFloatNanComparison(bvec2 comparison, vec2 pair1, vec2 pair2) {{\n" | ||||||
|            "    bvec2 is_nan1 = isnan(pair1);\n" |         "    bvec2 is_nan1 = isnan(pair1);\n" | ||||||
|            "    bvec2 is_nan2 = isnan(pair2);\n" |         "    bvec2 is_nan2 = isnan(pair2);\n" | ||||||
|            "    return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || " |         "    return bvec2(comparison.x || is_nan1.x || is_nan2.x, comparison.y || is_nan1.y || " | ||||||
|            "is_nan2.y);\n" |         "is_nan2.y);\n" | ||||||
|            "}\n"; |         "}}\n", | ||||||
|  |         MAX_CONSTBUFFER_ELEMENTS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ProgramResult Decompile(const Device& device, const ShaderIR& ir, Maxwell::ShaderStage stage, | ProgramResult Decompile(const Device& device, const ShaderIR& ir, Maxwell::ShaderStage stage, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei