2 // Copyright (C) 2014-2015 LunarG, Inc.
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
10 // Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
13 // Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following
15 // disclaimer in the documentation and/or other materials provided
16 // with the distribution.
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19 // contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
36 // Disassembler for SPIR-V.
48 #include "disassemble.h"
53 // Include C-based headers that don't have a namespace
54 #include "GLSL.std.450.h"
55 #include "GLSL.ext.AMD.h"
56 #include "GLSL.ext.NV.h"
59 const char* GlslStd450DebugNames[spv::GLSLstd450Count];
63 static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
64 static const char* GLSLextNVGetDebugNames(const char*, unsigned);
66 static void Kill(std::ostream& out, const char* message)
68 out << std::endl << "Disassembly failed: " << message << std::endl;
72 // used to identify the extended instruction library imported when printing
78 NonSemanticDebugPrintfExtInst,
81 // Container class for a single instance of a SPIR-V stream, with methods for disassembly.
84 SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
85 virtual ~SpirvStream() { }
88 void processInstructions();
91 SpirvStream(const SpirvStream&);
92 SpirvStream& operator=(const SpirvStream&);
93 Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
97 void formatId(Id id, std::stringstream&);
98 void outputResultId(Id id);
99 void outputTypeId(Id id);
100 void outputId(Id id);
101 void outputMask(OperandClass operandClass, unsigned mask);
102 void disassembleImmediates(int numOperands);
103 void disassembleIds(int numOperands);
104 std::pair<int, std::string> decodeString();
105 int disassembleString();
106 void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
109 std::ostream& out; // where to write the disassembly
110 const std::vector<unsigned int>& stream; // the actual word stream
111 int size; // the size of the word stream
112 int word; // the next word of the stream to read
114 // map each <id> to the instruction that created it
116 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)
118 std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
123 // stack of structured-merge points
124 std::stack<Id> nestedControl;
125 Id nextNestedControl; // need a slight delay for when we are nested
128 void SpirvStream::validate()
130 size = (int)stream.size();
132 Kill(out, "stream is too short");
135 if (stream[word++] != MagicNumber) {
136 out << "Bad magic number";
141 out << "// Module Version " << std::hex << stream[word++] << std::endl;
143 // Generator's magic number
144 out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
147 bound = stream[word++];
148 idInstruction.resize(bound);
149 idDescriptor.resize(bound);
150 out << "// Id's are bound by " << bound << std::endl;
153 // Reserved schema, must be 0 for now
154 schema = stream[word++];
156 Kill(out, "bad schema, must be 0");
159 // Loop over all the instructions, in order, processing each.
160 // Boiler plate for each is handled here directly, the rest is dispatched.
161 void SpirvStream::processInstructions()
164 while (word < size) {
165 int instructionStart = word;
167 // Instruction wordCount and opcode
168 unsigned int firstWord = stream[word];
169 unsigned wordCount = firstWord >> WordCountShift;
170 Op opCode = (Op)(firstWord & OpCodeMask);
171 int nextInst = word + wordCount;
174 // Presence of full instruction
176 Kill(out, "stream instruction terminated too early");
178 // Base for computing number of operands; will be updated as more is learned
179 unsigned numOperands = wordCount - 1;
183 if (InstructionDesc[opCode].hasType()) {
184 typeId = stream[word++];
190 if (InstructionDesc[opCode].hasResult()) {
191 resultId = stream[word++];
194 // save instruction for future reference
195 idInstruction[resultId] = instructionStart;
198 outputResultId(resultId);
199 outputTypeId(typeId);
202 // Hand off the Op and all its operands
203 disassembleInstruction(resultId, typeId, opCode, numOperands);
204 if (word != nextInst) {
205 out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
212 void SpirvStream::outputIndent()
214 for (int i = 0; i < (int)nestedControl.size(); ++i)
218 void SpirvStream::formatId(Id id, std::stringstream& idStream)
221 // On instructions with no IDs, this is called with "0", which does not
222 // have to be within ID bounds on null shaders.
224 Kill(out, "Bad <id>");
227 if (idDescriptor[id].size() > 0)
228 idStream << "(" << idDescriptor[id] << ")";
232 void SpirvStream::outputResultId(Id id)
234 const int width = 16;
235 std::stringstream idStream;
236 formatId(id, idStream);
237 out << std::setw(width) << std::right << idStream.str();
243 if (nestedControl.size() && id == nestedControl.top())
247 void SpirvStream::outputTypeId(Id id)
249 const int width = 12;
250 std::stringstream idStream;
251 formatId(id, idStream);
252 out << std::setw(width) << std::right << idStream.str() << " ";
255 void SpirvStream::outputId(Id id)
258 Kill(out, "Bad <id>");
261 if (idDescriptor[id].size() > 0)
262 out << "(" << idDescriptor[id] << ")";
265 void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
270 for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
272 out << OperandClassParams[operandClass].getName(m) << " ";
277 void SpirvStream::disassembleImmediates(int numOperands)
279 for (int i = 0; i < numOperands; ++i) {
280 out << stream[word++];
281 if (i < numOperands - 1)
286 void SpirvStream::disassembleIds(int numOperands)
288 for (int i = 0; i < numOperands; ++i) {
289 outputId(stream[word++]);
290 if (i < numOperands - 1)
295 // decode string from words at current position (non-consuming)
296 std::pair<int, std::string> SpirvStream::decodeString()
304 unsigned int content = stream[wordPos];
305 for (int charCount = 0; charCount < 4; ++charCount) {
317 return std::make_pair(wordPos - word, res);
320 // return the number of operands consumed by the string
321 int SpirvStream::disassembleString()
325 std::pair<int, std::string> decoderes = decodeString();
327 out << decoderes.second;
330 word += decoderes.first;
332 return decoderes.first;
335 void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
337 // Process the opcode
339 out << (OpcodeString(opCode) + 2); // leave out the "Op"
341 if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
342 nextNestedControl = stream[word];
343 else if (opCode == OpBranchConditional || opCode == OpSwitch) {
344 if (nextNestedControl) {
345 nestedControl.push(nextNestedControl);
346 nextNestedControl = 0;
348 } else if (opCode == OpExtInstImport) {
349 idDescriptor[resultId] = decodeString().second;
352 if (resultId != 0 && idDescriptor[resultId].size() == 0) {
355 switch (stream[word]) {
356 case 8: idDescriptor[resultId] = "int8_t"; break;
357 case 16: idDescriptor[resultId] = "int16_t"; break;
358 default: assert(0); // fallthrough
359 case 32: idDescriptor[resultId] = "int"; break;
360 case 64: idDescriptor[resultId] = "int64_t"; break;
364 switch (stream[word]) {
365 case 16: idDescriptor[resultId] = "float16_t"; break;
366 default: assert(0); // fallthrough
367 case 32: idDescriptor[resultId] = "float"; break;
368 case 64: idDescriptor[resultId] = "float64_t"; break;
372 idDescriptor[resultId] = "bool";
375 idDescriptor[resultId] = "struct";
378 idDescriptor[resultId] = "ptr";
381 if (idDescriptor[stream[word]].size() > 0) {
382 idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
383 if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
384 idDescriptor[resultId].append("8");
386 if (strstr(idDescriptor[stream[word]].c_str(), "16")) {
387 idDescriptor[resultId].append("16");
389 if (strstr(idDescriptor[stream[word]].c_str(), "64")) {
390 idDescriptor[resultId].append("64");
393 idDescriptor[resultId].append("vec");
394 switch (stream[word + 1]) {
395 case 2: idDescriptor[resultId].append("2"); break;
396 case 3: idDescriptor[resultId].append("3"); break;
397 case 4: idDescriptor[resultId].append("4"); break;
398 case 8: idDescriptor[resultId].append("8"); break;
399 case 16: idDescriptor[resultId].append("16"); break;
400 case 32: idDescriptor[resultId].append("32"); break;
410 // Process the operands. Note, a new context-dependent set could be
411 // swapped in mid-traversal.
413 // Handle images specially, so can put out helpful strings.
414 if (opCode == OpTypeImage) {
417 out << " " << DimensionString((Dim)stream[word++]);
418 out << (stream[word++] != 0 ? " depth" : "");
419 out << (stream[word++] != 0 ? " array" : "");
420 out << (stream[word++] != 0 ? " multi-sampled" : "");
421 switch (stream[word++]) {
422 case 0: out << " runtime"; break;
423 case 1: out << " sampled"; break;
424 case 2: out << " nonsampled"; break;
426 out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
428 if (numOperands == 8) {
429 out << " " << AccessQualifierString(stream[word++]);
434 // Handle all the parameterized operands
435 for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
437 OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
438 switch (operandClass) {
441 case OperandMemorySemantics:
444 // Get names for printing "(XXX)" for readability, *after* this id
445 if (opCode == OpName)
446 idDescriptor[stream[word - 1]] = decodeString().second;
448 case OperandVariableIds:
449 disassembleIds(numOperands);
451 case OperandImageOperands:
452 outputMask(OperandImageOperands, stream[word++]);
454 disassembleIds(numOperands);
456 case OperandOptionalLiteral:
457 case OperandVariableLiterals:
458 if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
459 (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
460 out << BuiltInString(stream[word++]);
464 disassembleImmediates(numOperands);
466 case OperandVariableIdLiteral:
467 while (numOperands > 0) {
475 disassembleImmediates(1);
479 case OperandVariableLiteralId:
480 while (numOperands > 0) {
486 disassembleImmediates(1);
492 case OperandLiteralNumber:
493 disassembleImmediates(1);
495 if (opCode == OpExtInst) {
496 ExtInstSet extInstSet = GLSL450Inst;
497 const char* name = idDescriptor[stream[word - 2]].c_str();
498 if (strcmp("OpenCL.std", name) == 0) {
499 extInstSet = OpenCLExtInst;
500 } else if (strcmp("OpenCL.DebugInfo.100", name) == 0) {
501 extInstSet = OpenCLExtInst;
502 } else if (strcmp("NonSemantic.DebugPrintf", name) == 0) {
503 extInstSet = NonSemanticDebugPrintfExtInst;
504 } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
505 strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
506 strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
507 strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
508 extInstSet = GLSLextAMDInst;
509 } else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
510 strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
511 strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
512 strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 ||
513 strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 ||
514 strcmp(spv::E_SPV_NV_mesh_shader, name) == 0) {
515 extInstSet = GLSLextNVInst;
517 unsigned entrypoint = stream[word - 1];
518 if (extInstSet == GLSL450Inst) {
519 if (entrypoint < GLSLstd450Count) {
520 out << "(" << GlslStd450DebugNames[entrypoint] << ")";
522 } else if (extInstSet == GLSLextAMDInst) {
523 out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
525 else if (extInstSet == GLSLextNVInst) {
526 out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
527 } else if (extInstSet == NonSemanticDebugPrintfExtInst) {
528 out << "(DebugPrintf)";
532 case OperandOptionalLiteralString:
533 case OperandLiteralString:
534 numOperands -= disassembleString();
536 case OperandVariableLiteralStrings:
537 while (numOperands > 0)
538 numOperands -= disassembleString();
540 case OperandMemoryAccess:
541 outputMask(OperandMemoryAccess, stream[word++]);
543 // Aligned is the only memory access operand that uses an immediate
544 // value, and it is also the first operand that uses a value at all.
545 if (stream[word-1] & MemoryAccessAlignedMask) {
546 disassembleImmediates(1);
551 disassembleIds(numOperands);
554 assert(operandClass >= OperandSource && operandClass < OperandOpcode);
556 if (OperandClassParams[operandClass].bitmask)
557 outputMask(operandClass, stream[word++]);
559 out << OperandClassParams[operandClass].getName(stream[word++]);
569 static void GLSLstd450GetDebugNames(const char** names)
571 for (int i = 0; i < GLSLstd450Count; ++i)
572 names[i] = "Unknown";
574 names[GLSLstd450Round] = "Round";
575 names[GLSLstd450RoundEven] = "RoundEven";
576 names[GLSLstd450Trunc] = "Trunc";
577 names[GLSLstd450FAbs] = "FAbs";
578 names[GLSLstd450SAbs] = "SAbs";
579 names[GLSLstd450FSign] = "FSign";
580 names[GLSLstd450SSign] = "SSign";
581 names[GLSLstd450Floor] = "Floor";
582 names[GLSLstd450Ceil] = "Ceil";
583 names[GLSLstd450Fract] = "Fract";
584 names[GLSLstd450Radians] = "Radians";
585 names[GLSLstd450Degrees] = "Degrees";
586 names[GLSLstd450Sin] = "Sin";
587 names[GLSLstd450Cos] = "Cos";
588 names[GLSLstd450Tan] = "Tan";
589 names[GLSLstd450Asin] = "Asin";
590 names[GLSLstd450Acos] = "Acos";
591 names[GLSLstd450Atan] = "Atan";
592 names[GLSLstd450Sinh] = "Sinh";
593 names[GLSLstd450Cosh] = "Cosh";
594 names[GLSLstd450Tanh] = "Tanh";
595 names[GLSLstd450Asinh] = "Asinh";
596 names[GLSLstd450Acosh] = "Acosh";
597 names[GLSLstd450Atanh] = "Atanh";
598 names[GLSLstd450Atan2] = "Atan2";
599 names[GLSLstd450Pow] = "Pow";
600 names[GLSLstd450Exp] = "Exp";
601 names[GLSLstd450Log] = "Log";
602 names[GLSLstd450Exp2] = "Exp2";
603 names[GLSLstd450Log2] = "Log2";
604 names[GLSLstd450Sqrt] = "Sqrt";
605 names[GLSLstd450InverseSqrt] = "InverseSqrt";
606 names[GLSLstd450Determinant] = "Determinant";
607 names[GLSLstd450MatrixInverse] = "MatrixInverse";
608 names[GLSLstd450Modf] = "Modf";
609 names[GLSLstd450ModfStruct] = "ModfStruct";
610 names[GLSLstd450FMin] = "FMin";
611 names[GLSLstd450SMin] = "SMin";
612 names[GLSLstd450UMin] = "UMin";
613 names[GLSLstd450FMax] = "FMax";
614 names[GLSLstd450SMax] = "SMax";
615 names[GLSLstd450UMax] = "UMax";
616 names[GLSLstd450FClamp] = "FClamp";
617 names[GLSLstd450SClamp] = "SClamp";
618 names[GLSLstd450UClamp] = "UClamp";
619 names[GLSLstd450FMix] = "FMix";
620 names[GLSLstd450Step] = "Step";
621 names[GLSLstd450SmoothStep] = "SmoothStep";
622 names[GLSLstd450Fma] = "Fma";
623 names[GLSLstd450Frexp] = "Frexp";
624 names[GLSLstd450FrexpStruct] = "FrexpStruct";
625 names[GLSLstd450Ldexp] = "Ldexp";
626 names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
627 names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
628 names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
629 names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
630 names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
631 names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
632 names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
633 names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
634 names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
635 names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
636 names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
637 names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
638 names[GLSLstd450Length] = "Length";
639 names[GLSLstd450Distance] = "Distance";
640 names[GLSLstd450Cross] = "Cross";
641 names[GLSLstd450Normalize] = "Normalize";
642 names[GLSLstd450FaceForward] = "FaceForward";
643 names[GLSLstd450Reflect] = "Reflect";
644 names[GLSLstd450Refract] = "Refract";
645 names[GLSLstd450FindILsb] = "FindILsb";
646 names[GLSLstd450FindSMsb] = "FindSMsb";
647 names[GLSLstd450FindUMsb] = "FindUMsb";
648 names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
649 names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
650 names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
651 names[GLSLstd450NMin] = "NMin";
652 names[GLSLstd450NMax] = "NMax";
653 names[GLSLstd450NClamp] = "NClamp";
656 static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
658 if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
659 switch (entrypoint) {
660 case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
661 case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
662 case WriteInvocationAMD: return "WriteInvocationAMD";
663 case MbcntAMD: return "MbcntAMD";
664 default: return "Bad";
666 } else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
667 switch (entrypoint) {
668 case FMin3AMD: return "FMin3AMD";
669 case UMin3AMD: return "UMin3AMD";
670 case SMin3AMD: return "SMin3AMD";
671 case FMax3AMD: return "FMax3AMD";
672 case UMax3AMD: return "UMax3AMD";
673 case SMax3AMD: return "SMax3AMD";
674 case FMid3AMD: return "FMid3AMD";
675 case UMid3AMD: return "UMid3AMD";
676 case SMid3AMD: return "SMid3AMD";
677 default: return "Bad";
679 } else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
680 switch (entrypoint) {
681 case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
682 default: return "Bad";
685 else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
686 switch (entrypoint) {
687 case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
688 case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
689 case TimeAMD: return "TimeAMD";
698 static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
700 if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
701 strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
702 strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
703 strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
704 strcmp(name, spv::E_SPV_NVX_multiview_per_view_attributes) == 0 ||
705 strcmp(name, spv::E_SPV_NV_fragment_shader_barycentric) == 0 ||
706 strcmp(name, spv::E_SPV_NV_mesh_shader) == 0 ||
707 strcmp(name, spv::E_SPV_NV_shader_image_footprint) == 0) {
708 switch (entrypoint) {
710 case BuiltInViewportMaskNV: return "ViewportMaskNV";
711 case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
712 case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
713 case BuiltInPositionPerViewNV: return "PositionPerViewNV";
714 case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
715 case BuiltInBaryCoordNV: return "BaryCoordNV";
716 case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV";
717 case BuiltInTaskCountNV: return "TaskCountNV";
718 case BuiltInPrimitiveCountNV: return "PrimitiveCountNV";
719 case BuiltInPrimitiveIndicesNV: return "PrimitiveIndicesNV";
720 case BuiltInClipDistancePerViewNV: return "ClipDistancePerViewNV";
721 case BuiltInCullDistancePerViewNV: return "CullDistancePerViewNV";
722 case BuiltInLayerPerViewNV: return "LayerPerViewNV";
723 case BuiltInMeshViewCountNV: return "MeshViewCountNV";
724 case BuiltInMeshViewIndicesNV: return "MeshViewIndicesNV";
727 case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
728 case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
729 case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
730 case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
731 case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV";
732 case CapabilityMeshShadingNV: return "MeshShadingNV";
733 case CapabilityImageFootprintNV: return "ImageFootprintNV";
734 case CapabilitySampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
737 case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
738 case DecorationPassthroughNV: return "PassthroughNV";
739 case DecorationViewportRelativeNV: return "ViewportRelativeNV";
740 case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
741 case DecorationPerVertexNV: return "PerVertexNV";
742 case DecorationPerPrimitiveNV: return "PerPrimitiveNV";
743 case DecorationPerViewNV: return "PerViewNV";
744 case DecorationPerTaskNV: return "PerTaskNV";
746 default: return "Bad";
752 void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
754 SpirvStream SpirvStream(out, stream);
756 GLSLstd450GetDebugNames(GlslStd450DebugNames);
757 SpirvStream.validate();
758 SpirvStream.processInstructions();
761 }; // end namespace spv