#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SPIRVBUILDER_H_ #define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SPIRVBUILDER_H_ #include "common/common.h" #include #include #include #include #include #include #include #include #include #include namespace Libs::Graphics::ShaderRecompiler::Spirv { struct TypeAnnotation { spv::Op opcode = spv::OpNop; std::vector operands; // Already encoded operand words. }; struct DeferredPhi { size_t word_offset = 0; }; class Builder { public: explicit Builder(uint32_t version = 0x00010300u); ~Builder() = default; KYTY_CLASS_DEFAULT_COPY(Builder); uint32_t AllocateId(); void RequireVersion(uint32_t version); void RequireCapability(spv::Capability capability); void RequireExtension(const char* name); uint32_t Import(const char* name); template uint32_t Type(spv::Op opcode, const Args&... operands) { return DeclareType(opcode, MakeTypeKey(opcode, operands...)); } template uint32_t DecoratedType(spv::Op opcode, std::initializer_list annotations, const Args&... operands) { return DeclareDecoratedType(opcode, MakeTypeKey(opcode, operands...), annotations); } template uint32_t Constant(spv::Op opcode, uint32_t type, const Args&... operands) { std::vector key; key.reserve(2u + (0u + ... + OperandWordCount(operands))); AppendOperands(key, opcode, type, operands...); return DeclareConstant(opcode, std::move(key)); } uint32_t DefineGlobalVariable(uint32_t pointer_type, spv::StorageClass storage_class); void DefineGlobalVariable(uint32_t id, uint32_t pointer_type, spv::StorageClass storage_class); void AddMemoryModel(spv::AddressingModel addressing_model, spv::MemoryModel memory_model); void AddEntryPoint(spv::ExecutionModel execution_model, uint32_t entry_point, const char* name, const std::vector& interfaces); template void AddExecutionMode(uint32_t entry_point, spv::ExecutionMode mode, const Args&... operands) { AppendInstruction(m_execution_modes, spv::OpExecutionMode, entry_point, mode, operands...); } void AddName(uint32_t target, const char* name); template void AddAnnotation(spv::Op opcode, const Args&... operands) { AppendInstruction(m_annotations, opcode, operands...); } template void AddFunction(spv::Op opcode, const Args&... operands) { AppendInstruction(m_functions, opcode, operands...); } void AddFunction(std::span words); DeferredPhi AddDeferredPhi(uint32_t type, uint32_t result, size_t incoming_count); void PatchDeferredPhi(DeferredPhi phi, size_t incoming, uint32_t value, uint32_t parent); [[nodiscard]] std::vector Build() const; private: static void AppendOperand(std::vector& words, uint32_t value) { words.push_back(value); } static void AppendOperand(std::vector& words, int32_t value) { words.push_back(static_cast(value)); } template requires std::is_enum_v static void AppendOperand(std::vector& words, T value) { static_assert(sizeof(T) == sizeof(uint32_t)); words.push_back(static_cast(value)); } static void AppendOperand(std::vector& words, std::span values) { words.insert(words.end(), values.begin(), values.end()); } template static void AppendOperands(std::vector& words, const Args&... operands) { (AppendOperand(words, operands), ...); } template static size_t OperandWordCount(const T& operand) { if constexpr (std::is_integral_v || std::is_enum_v) { return 1; } else { return std::size(operand); } } template static std::vector MakeTypeKey(spv::Op opcode, const Args&... operands) { const auto operand_count = static_cast((0u + ... + OperandWordCount(operands))); std::vector key; key.reserve(2u + operand_count); AppendOperands(key, opcode, operand_count, operands...); return key; } template static void AppendInstruction(std::vector& section, spv::Op opcode, const Args&... operands) { const auto offset = section.size(); AppendOperands(section, opcode, operands...); const auto word_count = static_cast(section.size() - offset); section[offset] |= word_count << spv::WordCountShift; } uint32_t DeclareType(spv::Op opcode, std::vector key); uint32_t DeclareDecoratedType(spv::Op opcode, std::vector key, std::initializer_list annotations); uint32_t DeclareConstant(spv::Op opcode, std::vector key); static void AppendString(std::vector& words, const char* text); uint32_t m_next_id = 1; uint32_t m_version = 0; std::vector m_capabilities; std::vector m_extensions; std::vector m_ext_inst_imports; std::vector m_memory_model; std::vector m_entry_points; std::vector m_execution_modes; std::vector m_debug; std::vector m_annotations; std::vector m_declarations; std::vector m_functions; std::set m_required_capabilities; std::set m_required_extensions; std::map m_import_ids; std::map, uint32_t> m_declaration_ids; size_t m_unpatched_phi_incomings = 0; }; } // namespace Libs::Graphics::ShaderRecompiler::Spirv #endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_SHADER_RECOMPILER_SPIRVBUILDER_H_ */