diff options
Diffstat (limited to 'thirdparty/glslang/SPIRV/disassemble.cpp')
-rw-r--r-- | thirdparty/glslang/SPIRV/disassemble.cpp | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/thirdparty/glslang/SPIRV/disassemble.cpp b/thirdparty/glslang/SPIRV/disassemble.cpp new file mode 100644 index 0000000000..631173c0ec --- /dev/null +++ b/thirdparty/glslang/SPIRV/disassemble.cpp @@ -0,0 +1,759 @@ +// +// Copyright (C) 2014-2015 LunarG, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +// +// Disassembler for SPIR-V. +// + +#include <cstdlib> +#include <cstring> +#include <cassert> +#include <iomanip> +#include <stack> +#include <sstream> +#include <cstring> + +#include "disassemble.h" +#include "doc.h" +#include "SpvTools.h" + +namespace spv { + extern "C" { + // Include C-based headers that don't have a namespace + #include "GLSL.std.450.h" +#ifdef AMD_EXTENSIONS + #include "GLSL.ext.AMD.h" +#endif + +#ifdef NV_EXTENSIONS + #include "GLSL.ext.NV.h" +#endif + } +} +const char* GlslStd450DebugNames[spv::GLSLstd450Count]; + +namespace spv { + +#ifdef AMD_EXTENSIONS +static const char* GLSLextAMDGetDebugNames(const char*, unsigned); +#endif + +#ifdef NV_EXTENSIONS +static const char* GLSLextNVGetDebugNames(const char*, unsigned); +#endif + +static void Kill(std::ostream& out, const char* message) +{ + out << std::endl << "Disassembly failed: " << message << std::endl; + exit(1); +} + +// used to identify the extended instruction library imported when printing +enum ExtInstSet { + GLSL450Inst, + +#ifdef AMD_EXTENSIONS + GLSLextAMDInst, +#endif + +#ifdef NV_EXTENSIONS + GLSLextNVInst, +#endif + + OpenCLExtInst, +}; + +// Container class for a single instance of a SPIR-V stream, with methods for disassembly. +class SpirvStream { +public: + SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { } + virtual ~SpirvStream() { } + + void validate(); + void processInstructions(); + +protected: + SpirvStream(const SpirvStream&); + SpirvStream& operator=(const SpirvStream&); + Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; } + + // Output methods + void outputIndent(); + void formatId(Id id, std::stringstream&); + void outputResultId(Id id); + void outputTypeId(Id id); + void outputId(Id id); + void outputMask(OperandClass operandClass, unsigned mask); + void disassembleImmediates(int numOperands); + void disassembleIds(int numOperands); + int disassembleString(); + void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands); + + // Data + std::ostream& out; // where to write the disassembly + const std::vector<unsigned int>& stream; // the actual word stream + int size; // the size of the word stream + int word; // the next word of the stream to read + + // map each <id> to the instruction that created it + Id bound; + std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter) + + std::vector<std::string> idDescriptor; // the best text string known for explaining the <id> + + // schema + unsigned int schema; + + // stack of structured-merge points + std::stack<Id> nestedControl; + Id nextNestedControl; // need a slight delay for when we are nested +}; + +void SpirvStream::validate() +{ + size = (int)stream.size(); + if (size < 4) + Kill(out, "stream is too short"); + + // Magic number + if (stream[word++] != MagicNumber) { + out << "Bad magic number"; + return; + } + + // Version + out << "// Module Version " << std::hex << stream[word++] << std::endl; + + // Generator's magic number + out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl; + + // Result <id> bound + bound = stream[word++]; + idInstruction.resize(bound); + idDescriptor.resize(bound); + out << "// Id's are bound by " << bound << std::endl; + out << std::endl; + + // Reserved schema, must be 0 for now + schema = stream[word++]; + if (schema != 0) + Kill(out, "bad schema, must be 0"); +} + +// Loop over all the instructions, in order, processing each. +// Boiler plate for each is handled here directly, the rest is dispatched. +void SpirvStream::processInstructions() +{ + // Instructions + while (word < size) { + int instructionStart = word; + + // Instruction wordCount and opcode + unsigned int firstWord = stream[word]; + unsigned wordCount = firstWord >> WordCountShift; + Op opCode = (Op)(firstWord & OpCodeMask); + int nextInst = word + wordCount; + ++word; + + // Presence of full instruction + if (nextInst > size) + Kill(out, "stream instruction terminated too early"); + + // Base for computing number of operands; will be updated as more is learned + unsigned numOperands = wordCount - 1; + + // Type <id> + Id typeId = 0; + if (InstructionDesc[opCode].hasType()) { + typeId = stream[word++]; + --numOperands; + } + + // Result <id> + Id resultId = 0; + if (InstructionDesc[opCode].hasResult()) { + resultId = stream[word++]; + --numOperands; + + // save instruction for future reference + idInstruction[resultId] = instructionStart; + } + + outputResultId(resultId); + outputTypeId(typeId); + outputIndent(); + + // Hand off the Op and all its operands + disassembleInstruction(resultId, typeId, opCode, numOperands); + if (word != nextInst) { + out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart; + word = nextInst; + } + out << std::endl; + } +} + +void SpirvStream::outputIndent() +{ + for (int i = 0; i < (int)nestedControl.size(); ++i) + out << " "; +} + +void SpirvStream::formatId(Id id, std::stringstream& idStream) +{ + if (id != 0) { + // On instructions with no IDs, this is called with "0", which does not + // have to be within ID bounds on null shaders. + if (id >= bound) + Kill(out, "Bad <id>"); + + idStream << id; + if (idDescriptor[id].size() > 0) + idStream << "(" << idDescriptor[id] << ")"; + } +} + +void SpirvStream::outputResultId(Id id) +{ + const int width = 16; + std::stringstream idStream; + formatId(id, idStream); + out << std::setw(width) << std::right << idStream.str(); + if (id != 0) + out << ":"; + else + out << " "; + + if (nestedControl.size() && id == nestedControl.top()) + nestedControl.pop(); +} + +void SpirvStream::outputTypeId(Id id) +{ + const int width = 12; + std::stringstream idStream; + formatId(id, idStream); + out << std::setw(width) << std::right << idStream.str() << " "; +} + +void SpirvStream::outputId(Id id) +{ + if (id >= bound) + Kill(out, "Bad <id>"); + + out << id; + if (idDescriptor[id].size() > 0) + out << "(" << idDescriptor[id] << ")"; +} + +void SpirvStream::outputMask(OperandClass operandClass, unsigned mask) +{ + if (mask == 0) + out << "None"; + else { + for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) { + if (mask & (1 << m)) + out << OperandClassParams[operandClass].getName(m) << " "; + } + } +} + +void SpirvStream::disassembleImmediates(int numOperands) +{ + for (int i = 0; i < numOperands; ++i) { + out << stream[word++]; + if (i < numOperands - 1) + out << " "; + } +} + +void SpirvStream::disassembleIds(int numOperands) +{ + for (int i = 0; i < numOperands; ++i) { + outputId(stream[word++]); + if (i < numOperands - 1) + out << " "; + } +} + +// return the number of operands consumed by the string +int SpirvStream::disassembleString() +{ + int startWord = word; + + out << " \""; + + const char* wordString; + bool done = false; + do { + unsigned int content = stream[word]; + wordString = (const char*)&content; + for (int charCount = 0; charCount < 4; ++charCount) { + if (*wordString == 0) { + done = true; + break; + } + out << *(wordString++); + } + ++word; + } while (! done); + + out << "\""; + + return word - startWord; +} + +void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands) +{ + // Process the opcode + + out << (OpcodeString(opCode) + 2); // leave out the "Op" + + if (opCode == OpLoopMerge || opCode == OpSelectionMerge) + nextNestedControl = stream[word]; + else if (opCode == OpBranchConditional || opCode == OpSwitch) { + if (nextNestedControl) { + nestedControl.push(nextNestedControl); + nextNestedControl = 0; + } + } else if (opCode == OpExtInstImport) { + idDescriptor[resultId] = (const char*)(&stream[word]); + } + else { + if (resultId != 0 && idDescriptor[resultId].size() == 0) { + switch (opCode) { + case OpTypeInt: + switch (stream[word]) { + case 8: idDescriptor[resultId] = "int8_t"; break; + case 16: idDescriptor[resultId] = "int16_t"; break; + default: assert(0); // fallthrough + case 32: idDescriptor[resultId] = "int"; break; + case 64: idDescriptor[resultId] = "int64_t"; break; + } + break; + case OpTypeFloat: + switch (stream[word]) { + case 16: idDescriptor[resultId] = "float16_t"; break; + default: assert(0); // fallthrough + case 32: idDescriptor[resultId] = "float"; break; + case 64: idDescriptor[resultId] = "float64_t"; break; + } + break; + case OpTypeBool: + idDescriptor[resultId] = "bool"; + break; + case OpTypeStruct: + idDescriptor[resultId] = "struct"; + break; + case OpTypePointer: + idDescriptor[resultId] = "ptr"; + break; + case OpTypeVector: + if (idDescriptor[stream[word]].size() > 0) { + idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1); + if (strstr(idDescriptor[stream[word]].c_str(), "8")) { + idDescriptor[resultId].append("8"); + } + if (strstr(idDescriptor[stream[word]].c_str(), "16")) { + idDescriptor[resultId].append("16"); + } + if (strstr(idDescriptor[stream[word]].c_str(), "64")) { + idDescriptor[resultId].append("64"); + } + } + idDescriptor[resultId].append("vec"); + switch (stream[word + 1]) { + case 2: idDescriptor[resultId].append("2"); break; + case 3: idDescriptor[resultId].append("3"); break; + case 4: idDescriptor[resultId].append("4"); break; + case 8: idDescriptor[resultId].append("8"); break; + case 16: idDescriptor[resultId].append("16"); break; + case 32: idDescriptor[resultId].append("32"); break; + default: break; + } + break; + default: + break; + } + } + } + + // Process the operands. Note, a new context-dependent set could be + // swapped in mid-traversal. + + // Handle images specially, so can put out helpful strings. + if (opCode == OpTypeImage) { + out << " "; + disassembleIds(1); + out << " " << DimensionString((Dim)stream[word++]); + out << (stream[word++] != 0 ? " depth" : ""); + out << (stream[word++] != 0 ? " array" : ""); + out << (stream[word++] != 0 ? " multi-sampled" : ""); + switch (stream[word++]) { + case 0: out << " runtime"; break; + case 1: out << " sampled"; break; + case 2: out << " nonsampled"; break; + } + out << " format:" << ImageFormatString((ImageFormat)stream[word++]); + + if (numOperands == 8) { + out << " " << AccessQualifierString(stream[word++]); + } + return; + } + + // Handle all the parameterized operands + for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) { + out << " "; + OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op); + switch (operandClass) { + case OperandId: + case OperandScope: + case OperandMemorySemantics: + disassembleIds(1); + --numOperands; + // Get names for printing "(XXX)" for readability, *after* this id + if (opCode == OpName) + idDescriptor[stream[word - 1]] = (const char*)(&stream[word]); + break; + case OperandVariableIds: + disassembleIds(numOperands); + return; + case OperandImageOperands: + outputMask(OperandImageOperands, stream[word++]); + --numOperands; + disassembleIds(numOperands); + return; + case OperandOptionalLiteral: + case OperandVariableLiterals: + if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) || + (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) { + out << BuiltInString(stream[word++]); + --numOperands; + ++op; + } + disassembleImmediates(numOperands); + return; + case OperandVariableIdLiteral: + while (numOperands > 0) { + out << std::endl; + outputResultId(0); + outputTypeId(0); + outputIndent(); + out << " Type "; + disassembleIds(1); + out << ", member "; + disassembleImmediates(1); + numOperands -= 2; + } + return; + case OperandVariableLiteralId: + while (numOperands > 0) { + out << std::endl; + outputResultId(0); + outputTypeId(0); + outputIndent(); + out << " case "; + disassembleImmediates(1); + out << ": "; + disassembleIds(1); + numOperands -= 2; + } + return; + case OperandLiteralNumber: + disassembleImmediates(1); + --numOperands; + if (opCode == OpExtInst) { + ExtInstSet extInstSet = GLSL450Inst; + const char* name = idDescriptor[stream[word - 2]].c_str(); + if (0 == memcmp("OpenCL", name, 6)) { + extInstSet = OpenCLExtInst; +#ifdef AMD_EXTENSIONS + } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 || + strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 || + strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 || + strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) { + extInstSet = GLSLextAMDInst; +#endif +#ifdef NV_EXTENSIONS + }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 || + strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 || + strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 || + strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 || + strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 || + strcmp(spv::E_SPV_NV_mesh_shader, name) == 0) { + extInstSet = GLSLextNVInst; +#endif + } + unsigned entrypoint = stream[word - 1]; + if (extInstSet == GLSL450Inst) { + if (entrypoint < GLSLstd450Count) { + out << "(" << GlslStd450DebugNames[entrypoint] << ")"; + } +#ifdef AMD_EXTENSIONS + } else if (extInstSet == GLSLextAMDInst) { + out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")"; +#endif +#ifdef NV_EXTENSIONS + } + else if (extInstSet == GLSLextNVInst) { + out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")"; +#endif + } + } + break; + case OperandOptionalLiteralString: + case OperandLiteralString: + numOperands -= disassembleString(); + break; + case OperandMemoryAccess: + outputMask(OperandMemoryAccess, stream[word++]); + --numOperands; + // Aligned is the only memory access operand that uses an immediate + // value, and it is also the first operand that uses a value at all. + if (stream[word-1] & MemoryAccessAlignedMask) { + disassembleImmediates(1); + numOperands--; + if (numOperands) + out << " "; + } + disassembleIds(numOperands); + return; + default: + assert(operandClass >= OperandSource && operandClass < OperandOpcode); + + if (OperandClassParams[operandClass].bitmask) + outputMask(operandClass, stream[word++]); + else + out << OperandClassParams[operandClass].getName(stream[word++]); + --numOperands; + + break; + } + } + + return; +} + +static void GLSLstd450GetDebugNames(const char** names) +{ + for (int i = 0; i < GLSLstd450Count; ++i) + names[i] = "Unknown"; + + names[GLSLstd450Round] = "Round"; + names[GLSLstd450RoundEven] = "RoundEven"; + names[GLSLstd450Trunc] = "Trunc"; + names[GLSLstd450FAbs] = "FAbs"; + names[GLSLstd450SAbs] = "SAbs"; + names[GLSLstd450FSign] = "FSign"; + names[GLSLstd450SSign] = "SSign"; + names[GLSLstd450Floor] = "Floor"; + names[GLSLstd450Ceil] = "Ceil"; + names[GLSLstd450Fract] = "Fract"; + names[GLSLstd450Radians] = "Radians"; + names[GLSLstd450Degrees] = "Degrees"; + names[GLSLstd450Sin] = "Sin"; + names[GLSLstd450Cos] = "Cos"; + names[GLSLstd450Tan] = "Tan"; + names[GLSLstd450Asin] = "Asin"; + names[GLSLstd450Acos] = "Acos"; + names[GLSLstd450Atan] = "Atan"; + names[GLSLstd450Sinh] = "Sinh"; + names[GLSLstd450Cosh] = "Cosh"; + names[GLSLstd450Tanh] = "Tanh"; + names[GLSLstd450Asinh] = "Asinh"; + names[GLSLstd450Acosh] = "Acosh"; + names[GLSLstd450Atanh] = "Atanh"; + names[GLSLstd450Atan2] = "Atan2"; + names[GLSLstd450Pow] = "Pow"; + names[GLSLstd450Exp] = "Exp"; + names[GLSLstd450Log] = "Log"; + names[GLSLstd450Exp2] = "Exp2"; + names[GLSLstd450Log2] = "Log2"; + names[GLSLstd450Sqrt] = "Sqrt"; + names[GLSLstd450InverseSqrt] = "InverseSqrt"; + names[GLSLstd450Determinant] = "Determinant"; + names[GLSLstd450MatrixInverse] = "MatrixInverse"; + names[GLSLstd450Modf] = "Modf"; + names[GLSLstd450ModfStruct] = "ModfStruct"; + names[GLSLstd450FMin] = "FMin"; + names[GLSLstd450SMin] = "SMin"; + names[GLSLstd450UMin] = "UMin"; + names[GLSLstd450FMax] = "FMax"; + names[GLSLstd450SMax] = "SMax"; + names[GLSLstd450UMax] = "UMax"; + names[GLSLstd450FClamp] = "FClamp"; + names[GLSLstd450SClamp] = "SClamp"; + names[GLSLstd450UClamp] = "UClamp"; + names[GLSLstd450FMix] = "FMix"; + names[GLSLstd450Step] = "Step"; + names[GLSLstd450SmoothStep] = "SmoothStep"; + names[GLSLstd450Fma] = "Fma"; + names[GLSLstd450Frexp] = "Frexp"; + names[GLSLstd450FrexpStruct] = "FrexpStruct"; + names[GLSLstd450Ldexp] = "Ldexp"; + names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8"; + names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8"; + names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16"; + names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16"; + names[GLSLstd450PackHalf2x16] = "PackHalf2x16"; + names[GLSLstd450PackDouble2x32] = "PackDouble2x32"; + names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16"; + names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16"; + names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16"; + names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8"; + names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8"; + names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32"; + names[GLSLstd450Length] = "Length"; + names[GLSLstd450Distance] = "Distance"; + names[GLSLstd450Cross] = "Cross"; + names[GLSLstd450Normalize] = "Normalize"; + names[GLSLstd450FaceForward] = "FaceForward"; + names[GLSLstd450Reflect] = "Reflect"; + names[GLSLstd450Refract] = "Refract"; + names[GLSLstd450FindILsb] = "FindILsb"; + names[GLSLstd450FindSMsb] = "FindSMsb"; + names[GLSLstd450FindUMsb] = "FindUMsb"; + names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid"; + names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample"; + names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset"; +} + +#ifdef AMD_EXTENSIONS +static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint) +{ + if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) { + switch (entrypoint) { + case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD"; + case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD"; + case WriteInvocationAMD: return "WriteInvocationAMD"; + case MbcntAMD: return "MbcntAMD"; + default: return "Bad"; + } + } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) { + switch (entrypoint) { + case FMin3AMD: return "FMin3AMD"; + case UMin3AMD: return "UMin3AMD"; + case SMin3AMD: return "SMin3AMD"; + case FMax3AMD: return "FMax3AMD"; + case UMax3AMD: return "UMax3AMD"; + case SMax3AMD: return "SMax3AMD"; + case FMid3AMD: return "FMid3AMD"; + case UMid3AMD: return "UMid3AMD"; + case SMid3AMD: return "SMid3AMD"; + default: return "Bad"; + } + } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) { + switch (entrypoint) { + case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD"; + default: return "Bad"; + } + } + else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) { + switch (entrypoint) { + case CubeFaceIndexAMD: return "CubeFaceIndexAMD"; + case CubeFaceCoordAMD: return "CubeFaceCoordAMD"; + case TimeAMD: return "TimeAMD"; + default: + break; + } + } + + return "Bad"; +} +#endif + +#ifdef NV_EXTENSIONS +static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint) +{ + if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 || + strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 || + strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 || + strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 || + strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 || + strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 || + strcmp(name, spv::E_SPV_NV_mesh_shader) == 0) { + switch (entrypoint) { + // NV builtins + case BuiltInViewportMaskNV: return "ViewportMaskNV"; + case BuiltInSecondaryPositionNV: return "SecondaryPositionNV"; + case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV"; + case BuiltInPositionPerViewNV: return "PositionPerViewNV"; + case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; + case BuiltInBaryCoordNV: return "BaryCoordNV"; + case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; + case BuiltInTaskCountNV: return "TaskCountNV"; + case BuiltInPrimitiveCountNV: return "PrimitiveCountNV"; + case BuiltInPrimitiveIndicesNV: return "PrimitiveIndicesNV"; + case BuiltInClipDistancePerViewNV: return "ClipDistancePerViewNV"; + case BuiltInCullDistancePerViewNV: return "CullDistancePerViewNV"; + case BuiltInLayerPerViewNV: return "LayerPerViewNV"; + case BuiltInMeshViewCountNV: return "MeshViewCountNV"; + case BuiltInMeshViewIndicesNV: return "MeshViewIndicesNV"; + + // NV Capabilities + case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV"; + case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV"; + case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV"; + case CapabilityPerViewAttributesNV: return "PerViewAttributesNV"; + case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV"; + case CapabilityMeshShadingNV: return "MeshShadingNV"; + + // NV Decorations + case DecorationOverrideCoverageNV: return "OverrideCoverageNV"; + case DecorationPassthroughNV: return "PassthroughNV"; + case DecorationViewportRelativeNV: return "ViewportRelativeNV"; + case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV"; + case DecorationPerVertexNV: return "PerVertexNV"; + case DecorationPerPrimitiveNV: return "PerPrimitiveNV"; + case DecorationPerViewNV: return "PerViewNV"; + case DecorationPerTaskNV: return "PerTaskNV"; + + default: return "Bad"; + } + } + return "Bad"; +} +#endif + +void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream) +{ + SpirvStream SpirvStream(out, stream); + spv::Parameterize(); + GLSLstd450GetDebugNames(GlslStd450DebugNames); + SpirvStream.validate(); + SpirvStream.processInstructions(); +} + +}; // end namespace spv |