// 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 { void SpirvDecoder::Decode(const UInt32* codepoints, std::size_t count) { m_currentCodepoint = codepoints; m_codepointEnd = codepoints + count; UInt32 magicNumber = ReadWord(); if (magicNumber != SpirvMagicNumber) throw std::runtime_error("invalid Spir-V: magic number didn't match"); UInt32 versionNumber = ReadWord(); if (versionNumber > SpirvVersion) throw std::runtime_error("Spir-V is more recent than decoder, dismissing"); SpirvHeader header; header.generatorId = ReadWord(); header.bound = ReadWord(); header.schema = ReadWord(); header.versionNumber = versionNumber; if (!HandleHeader(header)) return; while (m_currentCodepoint < m_codepointEnd) { const UInt32* instructionBegin = m_currentCodepoint; UInt32 firstWord = ReadWord(); UInt16 wordCount = static_cast((firstWord >> 16) & 0xFFFF); UInt16 opcode = static_cast(firstWord & 0xFFFF); const SpirvInstruction* inst = GetInstructionData(opcode); if (!inst) throw std::runtime_error("invalid instruction"); if (!HandleOpcode(*inst, wordCount)) break; m_currentCodepoint = instructionBegin + wordCount; } } bool SpirvDecoder::HandleHeader(const SpirvHeader& /*header*/) { return true; } std::string SpirvDecoder::ReadString() { std::string str; for (;;) { UInt32 value = ReadWord(); for (std::size_t j = 0; j < 4; ++j) { char c = static_cast((value >> (j * 8)) & 0xFF); if (c == '\0') return str; str.push_back(c); } } } UInt32 SpirvDecoder::ReadWord() { if (m_currentCodepoint >= m_codepointEnd) throw std::runtime_error("unexpected end of stream"); return *m_currentCodepoint++; } }