// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #include #include namespace Nz { struct SpirvPrinter::State { State(const Settings& s) : settings(s) { } std::size_t resultOffset; std::ostringstream stream; const Settings& settings; }; std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count, const Settings& settings) { State state(settings); m_currentState = &state; CallOnExit resetOnExit([&] { m_currentState = nullptr; }); Decode(codepoints, count); return m_currentState->stream.str(); } bool SpirvPrinter::HandleHeader(const SpirvHeader& header) { UInt8 majorVersion = ((header.versionNumber) >> 16) & 0xFF; UInt8 minorVersion = ((header.versionNumber) >> 8) & 0xFF; m_currentState->resultOffset = std::snprintf(nullptr, 0, "%%%u = ", header.bound); if (m_currentState->settings.printHeader) { m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n"; m_currentState->stream << "Generator: " << std::to_string(header.generatorId) << "\n"; m_currentState->stream << "Bound: " << std::to_string(header.bound) << "\n"; m_currentState->stream << "Schema: " << std::to_string(header.schema) << "\n"; } return true; } bool SpirvPrinter::HandleOpcode(const SpirvInstruction& instruction, UInt32 wordCount) { const UInt32* startPtr = GetCurrentPtr(); if (m_currentState->settings.printParameters) { std::ostringstream instructionStream; instructionStream << instruction.name; UInt32 resultId = 0; std::size_t currentOperand = 0; const UInt32* endPtr = startPtr + wordCount - 1; while (GetCurrentPtr() < endPtr) { const SpirvInstruction::Operand* operand = &instruction.operands[currentOperand]; if (operand->kind != SpirvOperandKind::IdResult) { switch (operand->kind) { case SpirvOperandKind::IdRef: case SpirvOperandKind::IdResultType: case SpirvOperandKind::IdMemorySemantics: case SpirvOperandKind::IdScope: { UInt32 value = ReadWord(); instructionStream << " %" << value; break; } case SpirvOperandKind::ImageOperands: case SpirvOperandKind::FPFastMathMode: case SpirvOperandKind::SelectionControl: case SpirvOperandKind::LoopControl: case SpirvOperandKind::FunctionControl: case SpirvOperandKind::MemorySemantics: case SpirvOperandKind::MemoryAccess: case SpirvOperandKind::KernelProfilingInfo: case SpirvOperandKind::RayFlags: case SpirvOperandKind::SourceLanguage: case SpirvOperandKind::ExecutionModel: case SpirvOperandKind::AddressingModel: case SpirvOperandKind::MemoryModel: case SpirvOperandKind::ExecutionMode: case SpirvOperandKind::StorageClass: case SpirvOperandKind::Dim: case SpirvOperandKind::SamplerAddressingMode: case SpirvOperandKind::SamplerFilterMode: case SpirvOperandKind::ImageFormat: case SpirvOperandKind::ImageChannelOrder: case SpirvOperandKind::ImageChannelDataType: case SpirvOperandKind::FPRoundingMode: case SpirvOperandKind::LinkageType: case SpirvOperandKind::AccessQualifier: case SpirvOperandKind::FunctionParameterAttribute: case SpirvOperandKind::Decoration: case SpirvOperandKind::BuiltIn: case SpirvOperandKind::Scope: case SpirvOperandKind::GroupOperation: case SpirvOperandKind::KernelEnqueueFlags: case SpirvOperandKind::Capability: case SpirvOperandKind::RayQueryIntersection: case SpirvOperandKind::RayQueryCommittedIntersectionType: case SpirvOperandKind::RayQueryCandidateIntersectionType: case SpirvOperandKind::LiteralInteger: case SpirvOperandKind::LiteralExtInstInteger: case SpirvOperandKind::LiteralSpecConstantOpInteger: case SpirvOperandKind::LiteralContextDependentNumber: //< FIXME { UInt32 value = ReadWord(); instructionStream << " " << operand->name << "(" << value << ")"; break; } case SpirvOperandKind::LiteralString: { std::string str = ReadString(); instructionStream << " \"" << str << "\""; /* std::size_t offset = GetOutputOffset(); std::size_t size4 = CountWord(str); for (std::size_t i = 0; i < size4; ++i) { UInt32 codepoint = 0; for (std::size_t j = 0; j < 4; ++j) { std::size_t pos = i * 4 + j; if (pos < str.size()) codepoint |= UInt32(str[pos]) << (j * 8); } Append(codepoint); } */ break; } case SpirvOperandKind::PairLiteralIntegerIdRef: { ReadWord(); ReadWord(); break; } case SpirvOperandKind::PairIdRefLiteralInteger: { ReadWord(); ReadWord(); break; } case SpirvOperandKind::PairIdRefIdRef: { ReadWord(); ReadWord(); break; } /*case SpirvOperandKind::LiteralContextDependentNumber: { throw std::runtime_error("not yet implemented"); }*/ default: break; } } else resultId = ReadWord(); if (currentOperand < instruction.minOperandCount - 1) currentOperand++; } if (resultId != 0) { std::string resultInfo = "%" + std::to_string(resultId) + " = "; m_currentState->stream << std::setw(m_currentState->resultOffset) << resultInfo; } else m_currentState->stream << std::string(m_currentState->resultOffset, ' '); m_currentState->stream << instructionStream.str(); assert(GetCurrentPtr() == startPtr + wordCount - 1); } else m_currentState->stream << instruction.name; m_currentState->stream << "\n"; return true; } }