Merge pull request #2985 from jeremy-lunarg/hayes-nonsemantic-shader-debuginfo-rebase
Implement NonSemantic.Shader.DebugInfo.100 debug instruction generation. These instructions will be generated under the -gV and -gVS command line options. These instructions enable source-level shader debugging with Renderdoc. This is an alpha release of this capability. Additional improvements are forthcoming. Use and feedback are welcome.
This commit is contained in:
commit
284ceb6d45
55 changed files with 11275 additions and 96 deletions
|
|
@ -86,6 +86,8 @@ GLSLANG_EXPORT void glslang_program_SPIRV_generate(glslang_program_t* program, g
|
|||
glslang_spv_options_t spv_options;
|
||||
spv_options.generate_debug_info = false;
|
||||
spv_options.strip_debug_info = false;
|
||||
spv_options.emit_nonsemantic_shader_debug_info = false;
|
||||
spv_options.emit_nonsemantic_shader_debug_source = false;
|
||||
spv_options.disable_optimizer = true;
|
||||
spv_options.optimize_size = false;
|
||||
spv_options.disassemble = false;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ set(HEADERS
|
|||
disassemble.h
|
||||
GLSL.ext.AMD.h
|
||||
GLSL.ext.NV.h
|
||||
NonSemanticDebugPrintf.h)
|
||||
NonSemanticDebugPrintf.h
|
||||
NonSemanticShaderDebugInfo100.h)
|
||||
|
||||
set(SPVREMAP_HEADERS
|
||||
SPVRemapper.h
|
||||
|
|
|
|||
|
|
@ -1578,6 +1578,10 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
|
|||
for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)
|
||||
builder.addInclude(iItr->first, iItr->second);
|
||||
}
|
||||
|
||||
builder.setEmitNonSemanticShaderDebugInfo(options.emitNonSemanticShaderDebugInfo);
|
||||
builder.setEmitNonSemanticShaderDebugSource(options.emitNonSemanticShaderDebugSource);
|
||||
|
||||
stdBuiltins = builder.import("GLSL.std.450");
|
||||
|
||||
spv::AddressingModel addressingModel = spv::AddressingModelLogical;
|
||||
|
|
@ -2526,6 +2530,14 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
|||
return false;
|
||||
}
|
||||
|
||||
// Force variable declaration - Debug Mode Only
|
||||
if (node->getOp() == glslang::EOpDeclare) {
|
||||
builder.clearAccessChain();
|
||||
node->getOperand()->traverse(this);
|
||||
builder.clearAccessChain();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start by evaluating the operand
|
||||
|
||||
// Does it need a swizzle inversion? If so, evaluation is inverted;
|
||||
|
|
@ -2786,32 +2798,38 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
|
||||
|
||||
switch (node->getOp()) {
|
||||
case glslang::EOpScope:
|
||||
case glslang::EOpSequence:
|
||||
{
|
||||
if (preVisit)
|
||||
if (visit == glslang::EvPreVisit) {
|
||||
++sequenceDepth;
|
||||
else
|
||||
if (sequenceDepth == 1) {
|
||||
// If this is the parent node of all the functions, we want to see them
|
||||
// early, so all call points have actual SPIR-V functions to reference.
|
||||
// In all cases, still let the traverser visit the children for us.
|
||||
makeFunctions(node->getAsAggregate()->getSequence());
|
||||
|
||||
// Also, we want all globals initializers to go into the beginning of the entry point, before
|
||||
// anything else gets there, so visit out of order, doing them all now.
|
||||
makeGlobalInitializers(node->getAsAggregate()->getSequence());
|
||||
|
||||
//Pre process linker objects for ray tracing stages
|
||||
if (glslangIntermediate->isRayTracingStage())
|
||||
collectRayTracingLinkerObjects();
|
||||
|
||||
// Initializers are done, don't want to visit again, but functions and link objects need to be processed,
|
||||
// so do them manually.
|
||||
visitFunctions(node->getAsAggregate()->getSequence());
|
||||
|
||||
return false;
|
||||
} else {
|
||||
if (node->getOp() == glslang::EOpScope)
|
||||
builder.enterScope(0);
|
||||
}
|
||||
} else {
|
||||
if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope)
|
||||
builder.leaveScope();
|
||||
--sequenceDepth;
|
||||
|
||||
if (sequenceDepth == 1) {
|
||||
// If this is the parent node of all the functions, we want to see them
|
||||
// early, so all call points have actual SPIR-V functions to reference.
|
||||
// In all cases, still let the traverser visit the children for us.
|
||||
makeFunctions(node->getAsAggregate()->getSequence());
|
||||
|
||||
// Also, we want all globals initializers to go into the beginning of the entry point, before
|
||||
// anything else gets there, so visit out of order, doing them all now.
|
||||
makeGlobalInitializers(node->getAsAggregate()->getSequence());
|
||||
|
||||
//Pre process linker objects for ray tracing stages
|
||||
if (glslangIntermediate->isRayTracingStage())
|
||||
collectRayTracingLinkerObjects();
|
||||
|
||||
// Initializers are done, don't want to visit again, but functions and link objects need to be processed,
|
||||
// so do them manually.
|
||||
visitFunctions(node->getAsAggregate()->getSequence());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -2840,6 +2858,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
if (isShaderEntryPoint(node)) {
|
||||
inEntryPoint = true;
|
||||
builder.setBuildPoint(shaderEntry->getLastBlock());
|
||||
builder.enterFunction(shaderEntry);
|
||||
currentFunction = shaderEntry;
|
||||
} else {
|
||||
handleFunctionEntry(node);
|
||||
|
|
@ -3826,8 +3845,8 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
|
|||
// by a block-ending branch. But we don't want to put any other body/test
|
||||
// instructions in it, since the body/test may have arbitrary instructions,
|
||||
// including merges of its own.
|
||||
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
||||
builder.setBuildPoint(&blocks.head);
|
||||
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
|
||||
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
|
||||
if (node->testFirst() && node->getTest()) {
|
||||
spv::Block& test = builder.makeNewBlock();
|
||||
|
|
@ -4046,7 +4065,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
|||
initializer = builder.makeNullConstant(spvType);
|
||||
}
|
||||
|
||||
return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer);
|
||||
return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false);
|
||||
}
|
||||
|
||||
// Return type Id of the sampled type.
|
||||
|
|
@ -4134,7 +4153,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
|||
if (explicitLayout != glslang::ElpNone)
|
||||
spvType = builder.makeUintType(32);
|
||||
else
|
||||
spvType = builder.makeBoolType();
|
||||
spvType = builder.makeBoolType(false);
|
||||
break;
|
||||
case glslang::EbtInt:
|
||||
spvType = builder.makeIntType(32);
|
||||
|
|
@ -4454,14 +4473,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
|||
// except sometimes for blocks
|
||||
std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
|
||||
for (int i = 0; i < (int)glslangMembers->size(); i++) {
|
||||
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
|
||||
if (glslangMember.hiddenMember()) {
|
||||
auto& glslangMember = (*glslangMembers)[i];
|
||||
if (glslangMember.type->hiddenMember()) {
|
||||
++memberDelta;
|
||||
if (type.getBasicType() == glslang::EbtBlock)
|
||||
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
|
||||
} else {
|
||||
if (type.getBasicType() == glslang::EbtBlock) {
|
||||
if (filterMember(glslangMember)) {
|
||||
if (filterMember(*glslangMember.type)) {
|
||||
memberDelta++;
|
||||
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
|
||||
continue;
|
||||
|
|
@ -4469,7 +4488,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
|||
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta;
|
||||
}
|
||||
// modify just this child's view of the qualifier
|
||||
glslang::TQualifier memberQualifier = glslangMember.getQualifier();
|
||||
glslang::TQualifier memberQualifier = glslangMember.type->getQualifier();
|
||||
InheritQualifiers(memberQualifier, qualifier);
|
||||
|
||||
// manually inherit location
|
||||
|
|
@ -4480,25 +4499,38 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
|
|||
bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
|
||||
i == (int)glslangMembers->size() - 1;
|
||||
|
||||
// Make forward pointers for any pointer members, and create a list of members to
|
||||
// convert to spirv types after creating the struct.
|
||||
if (glslangMember.isReference()) {
|
||||
if (forwardPointers.find(glslangMember.getReferentType()) == forwardPointers.end()) {
|
||||
deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier));
|
||||
}
|
||||
spvMembers.push_back(
|
||||
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember,
|
||||
true));
|
||||
} else {
|
||||
spvMembers.push_back(
|
||||
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember,
|
||||
false));
|
||||
// Make forward pointers for any pointer members.
|
||||
if (glslangMember.type->isReference() &&
|
||||
forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) {
|
||||
deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier));
|
||||
}
|
||||
|
||||
// Create the member type.
|
||||
auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember,
|
||||
glslangMember.type->isReference());
|
||||
spvMembers.push_back(spvMember);
|
||||
|
||||
// Update the builder with the type's location so that we can create debug types for the structure members.
|
||||
// There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now,
|
||||
// it is stored in the builder and consumed during the construction of composite debug types.
|
||||
// TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the
|
||||
// quick and dirty approaches that were tried.
|
||||
// Advantages of this approach:
|
||||
// + Relatively clean. No direct calls into debug type system.
|
||||
// + Handles nested recursive structures.
|
||||
// Disadvantages of this approach:
|
||||
// + Not as clean as desired. Traverser queries/sets persistent state. This is fragile.
|
||||
// + Table lookup during creation of composite debug types. This really shouldn't be necessary.
|
||||
if(options.emitNonSemanticShaderDebugInfo) {
|
||||
builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str();
|
||||
builder.debugTypeLocs[spvMember].line = glslangMember.loc.line;
|
||||
builder.debugTypeLocs[spvMember].column = glslangMember.loc.column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the SPIR-V type
|
||||
spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str());
|
||||
spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false);
|
||||
if (! HasNonLayoutQualifiers(type, qualifier))
|
||||
structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
|
||||
|
||||
|
|
@ -5092,6 +5124,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
|
|||
// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
|
||||
|
||||
std::vector<spv::Id> paramTypes;
|
||||
std::vector<char const*> paramNames;
|
||||
std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
|
||||
glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
|
||||
|
||||
|
|
@ -5116,10 +5149,14 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
|
|||
paramTypes.push_back(typeId);
|
||||
}
|
||||
|
||||
for (auto const parameter:parameters) {
|
||||
paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str());
|
||||
}
|
||||
|
||||
spv::Block* functionBlock;
|
||||
spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
|
||||
convertGlslangToSpvType(glslFunction->getType()),
|
||||
glslFunction->getName().c_str(), paramTypes,
|
||||
glslFunction->getName().c_str(), paramTypes, paramNames,
|
||||
paramDecorations, &functionBlock);
|
||||
if (implicitThis)
|
||||
function->setImplicitThis();
|
||||
|
|
@ -5209,6 +5246,7 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate
|
|||
currentFunction = functionMap[node->getName().c_str()];
|
||||
spv::Block* functionBlock = currentFunction->getEntryBlock();
|
||||
builder.setBuildPoint(functionBlock);
|
||||
builder.enterFunction(currentFunction);
|
||||
}
|
||||
|
||||
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
|
||||
|
|
|
|||
171
SPIRV/NonSemanticShaderDebugInfo100.h
Normal file
171
SPIRV/NonSemanticShaderDebugInfo100.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// Copyright (c) 2018 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and/or associated documentation files (the "Materials"),
|
||||
// to deal in the Materials without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Materials, and to permit persons to whom the
|
||||
// Materials are furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
// IN THE MATERIALS.
|
||||
|
||||
#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
|
||||
#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
NonSemanticShaderDebugInfo100Version = 100,
|
||||
NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff
|
||||
};
|
||||
enum {
|
||||
NonSemanticShaderDebugInfo100Revision = 6,
|
||||
NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100Instructions {
|
||||
NonSemanticShaderDebugInfo100DebugInfoNone = 0,
|
||||
NonSemanticShaderDebugInfo100DebugCompilationUnit = 1,
|
||||
NonSemanticShaderDebugInfo100DebugTypeBasic = 2,
|
||||
NonSemanticShaderDebugInfo100DebugTypePointer = 3,
|
||||
NonSemanticShaderDebugInfo100DebugTypeQualifier = 4,
|
||||
NonSemanticShaderDebugInfo100DebugTypeArray = 5,
|
||||
NonSemanticShaderDebugInfo100DebugTypeVector = 6,
|
||||
NonSemanticShaderDebugInfo100DebugTypedef = 7,
|
||||
NonSemanticShaderDebugInfo100DebugTypeFunction = 8,
|
||||
NonSemanticShaderDebugInfo100DebugTypeEnum = 9,
|
||||
NonSemanticShaderDebugInfo100DebugTypeComposite = 10,
|
||||
NonSemanticShaderDebugInfo100DebugTypeMember = 11,
|
||||
NonSemanticShaderDebugInfo100DebugTypeInheritance = 12,
|
||||
NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13,
|
||||
NonSemanticShaderDebugInfo100DebugTypeTemplate = 14,
|
||||
NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15,
|
||||
NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16,
|
||||
NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17,
|
||||
NonSemanticShaderDebugInfo100DebugGlobalVariable = 18,
|
||||
NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19,
|
||||
NonSemanticShaderDebugInfo100DebugFunction = 20,
|
||||
NonSemanticShaderDebugInfo100DebugLexicalBlock = 21,
|
||||
NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22,
|
||||
NonSemanticShaderDebugInfo100DebugScope = 23,
|
||||
NonSemanticShaderDebugInfo100DebugNoScope = 24,
|
||||
NonSemanticShaderDebugInfo100DebugInlinedAt = 25,
|
||||
NonSemanticShaderDebugInfo100DebugLocalVariable = 26,
|
||||
NonSemanticShaderDebugInfo100DebugInlinedVariable = 27,
|
||||
NonSemanticShaderDebugInfo100DebugDeclare = 28,
|
||||
NonSemanticShaderDebugInfo100DebugValue = 29,
|
||||
NonSemanticShaderDebugInfo100DebugOperation = 30,
|
||||
NonSemanticShaderDebugInfo100DebugExpression = 31,
|
||||
NonSemanticShaderDebugInfo100DebugMacroDef = 32,
|
||||
NonSemanticShaderDebugInfo100DebugMacroUndef = 33,
|
||||
NonSemanticShaderDebugInfo100DebugImportedEntity = 34,
|
||||
NonSemanticShaderDebugInfo100DebugSource = 35,
|
||||
NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101,
|
||||
NonSemanticShaderDebugInfo100DebugSourceContinued = 102,
|
||||
NonSemanticShaderDebugInfo100DebugLine = 103,
|
||||
NonSemanticShaderDebugInfo100DebugNoLine = 104,
|
||||
NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105,
|
||||
NonSemanticShaderDebugInfo100DebugStoragePath = 106,
|
||||
NonSemanticShaderDebugInfo100DebugEntryPoint = 107,
|
||||
NonSemanticShaderDebugInfo100DebugTypeMatrix = 108,
|
||||
NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff
|
||||
};
|
||||
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugInfoFlags {
|
||||
NonSemanticShaderDebugInfo100None = 0x0000,
|
||||
NonSemanticShaderDebugInfo100FlagIsProtected = 0x01,
|
||||
NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02,
|
||||
NonSemanticShaderDebugInfo100FlagIsPublic = 0x03,
|
||||
NonSemanticShaderDebugInfo100FlagIsLocal = 0x04,
|
||||
NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08,
|
||||
NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10,
|
||||
NonSemanticShaderDebugInfo100FlagArtificial = 0x20,
|
||||
NonSemanticShaderDebugInfo100FlagExplicit = 0x40,
|
||||
NonSemanticShaderDebugInfo100FlagPrototyped = 0x80,
|
||||
NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100,
|
||||
NonSemanticShaderDebugInfo100FlagStaticMember = 0x200,
|
||||
NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400,
|
||||
NonSemanticShaderDebugInfo100FlagLValueReference = 0x800,
|
||||
NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000,
|
||||
NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000,
|
||||
NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000,
|
||||
NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000,
|
||||
NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000,
|
||||
NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000,
|
||||
NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100BuildIdentifierFlags {
|
||||
NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01,
|
||||
NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding {
|
||||
NonSemanticShaderDebugInfo100Unspecified = 0,
|
||||
NonSemanticShaderDebugInfo100Address = 1,
|
||||
NonSemanticShaderDebugInfo100Boolean = 2,
|
||||
NonSemanticShaderDebugInfo100Float = 3,
|
||||
NonSemanticShaderDebugInfo100Signed = 4,
|
||||
NonSemanticShaderDebugInfo100SignedChar = 5,
|
||||
NonSemanticShaderDebugInfo100Unsigned = 6,
|
||||
NonSemanticShaderDebugInfo100UnsignedChar = 7,
|
||||
NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugCompositeType {
|
||||
NonSemanticShaderDebugInfo100Class = 0,
|
||||
NonSemanticShaderDebugInfo100Structure = 1,
|
||||
NonSemanticShaderDebugInfo100Union = 2,
|
||||
NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugTypeQualifier {
|
||||
NonSemanticShaderDebugInfo100ConstType = 0,
|
||||
NonSemanticShaderDebugInfo100VolatileType = 1,
|
||||
NonSemanticShaderDebugInfo100RestrictType = 2,
|
||||
NonSemanticShaderDebugInfo100AtomicType = 3,
|
||||
NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugOperation {
|
||||
NonSemanticShaderDebugInfo100Deref = 0,
|
||||
NonSemanticShaderDebugInfo100Plus = 1,
|
||||
NonSemanticShaderDebugInfo100Minus = 2,
|
||||
NonSemanticShaderDebugInfo100PlusUconst = 3,
|
||||
NonSemanticShaderDebugInfo100BitPiece = 4,
|
||||
NonSemanticShaderDebugInfo100Swap = 5,
|
||||
NonSemanticShaderDebugInfo100Xderef = 6,
|
||||
NonSemanticShaderDebugInfo100StackValue = 7,
|
||||
NonSemanticShaderDebugInfo100Constu = 8,
|
||||
NonSemanticShaderDebugInfo100Fragment = 9,
|
||||
NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticShaderDebugInfo100DebugImportedEntity {
|
||||
NonSemanticShaderDebugInfo100ImportedModule = 0,
|
||||
NonSemanticShaderDebugInfo100ImportedDeclaration = 1,
|
||||
NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
|
||||
|
|
@ -59,12 +59,15 @@ namespace spv {
|
|||
|
||||
Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
|
||||
spvVersion(spvVersion),
|
||||
source(SourceLanguageUnknown),
|
||||
sourceLang(SourceLanguageUnknown),
|
||||
sourceVersion(0),
|
||||
sourceFileStringId(NoResult),
|
||||
currentLine(0),
|
||||
currentFile(nullptr),
|
||||
currentFileId(NoResult),
|
||||
lastDebugScopeId(NoResult),
|
||||
emitOpLines(false),
|
||||
emitNonSemanticShaderDebugInfo(false),
|
||||
addressModel(AddressingModelLogical),
|
||||
memoryModel(MemoryModelGLSL450),
|
||||
builderNumber(magicNumber),
|
||||
|
|
@ -98,8 +101,12 @@ void Builder::setLine(int lineNum)
|
|||
{
|
||||
if (lineNum != 0 && lineNum != currentLine) {
|
||||
currentLine = lineNum;
|
||||
if (emitOpLines)
|
||||
addLine(sourceFileStringId, currentLine, 0);
|
||||
if (emitOpLines) {
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
addDebugScopeAndLine(currentFileId, currentLine, 0);
|
||||
else
|
||||
addLine(sourceFileStringId, currentLine, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +125,10 @@ void Builder::setLine(int lineNum, const char* filename)
|
|||
currentFile = filename;
|
||||
if (emitOpLines) {
|
||||
spv::Id strId = getStringId(filename);
|
||||
addLine(strId, currentLine, 0);
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
addDebugScopeAndLine(strId, currentLine, 0);
|
||||
else
|
||||
addLine(strId, currentLine, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -132,22 +142,49 @@ void Builder::addLine(Id fileName, int lineNum, int column)
|
|||
buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
|
||||
}
|
||||
|
||||
void Builder::addDebugScopeAndLine(Id fileName, int lineNum, int column)
|
||||
{
|
||||
if (currentDebugScopeId.top() != lastDebugScopeId) {
|
||||
spv::Id resultId = getUniqueId();
|
||||
Instruction* scopeInst = new Instruction(resultId, makeVoidType(), OpExtInst);
|
||||
scopeInst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope);
|
||||
scopeInst->addIdOperand(currentDebugScopeId.top());
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(scopeInst));
|
||||
lastDebugScopeId = currentDebugScopeId.top();
|
||||
}
|
||||
spv::Id resultId = getUniqueId();
|
||||
Instruction* lineInst = new Instruction(resultId, makeVoidType(), OpExtInst);
|
||||
lineInst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine);
|
||||
lineInst->addIdOperand(makeDebugSource(fileName));
|
||||
lineInst->addIdOperand(makeUintConstant(lineNum));
|
||||
lineInst->addIdOperand(makeUintConstant(lineNum));
|
||||
lineInst->addIdOperand(makeUintConstant(column));
|
||||
lineInst->addIdOperand(makeUintConstant(column));
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(lineInst));
|
||||
}
|
||||
|
||||
// For creating new groupedTypes (will return old type if the requested one was already made).
|
||||
Id Builder::makeVoidType()
|
||||
{
|
||||
Instruction* type;
|
||||
if (groupedTypes[OpTypeVoid].size() == 0) {
|
||||
type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
|
||||
Id typeId = getUniqueId();
|
||||
type = new Instruction(typeId, NoType, OpTypeVoid);
|
||||
groupedTypes[OpTypeVoid].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
// Core OpTypeVoid used for debug void type
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
debugId[typeId] = typeId;
|
||||
} else
|
||||
type = groupedTypes[OpTypeVoid].back();
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeBoolType()
|
||||
Id Builder::makeBoolType(bool const compilerGenerated)
|
||||
{
|
||||
Instruction* type;
|
||||
if (groupedTypes[OpTypeBool].size() == 0) {
|
||||
|
|
@ -158,6 +195,12 @@ Id Builder::makeBoolType()
|
|||
} else
|
||||
type = groupedTypes[OpTypeBool].back();
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
|
||||
{
|
||||
auto const debugResultId = makeBoolDebugType(32);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +215,12 @@ Id Builder::makeSamplerType()
|
|||
} else
|
||||
type = groupedTypes[OpTypeSampler].back();
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -268,6 +317,12 @@ Id Builder::makeIntegerType(int width, bool hasSign)
|
|||
break;
|
||||
}
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeIntegerDebugType(width, hasSign);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -305,6 +360,12 @@ Id Builder::makeFloatType(int width)
|
|||
break;
|
||||
}
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeFloatDebugType(width);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +373,7 @@ Id Builder::makeFloatType(int width)
|
|||
// See makeStructResultType() for non-decorated structs
|
||||
// needed as the result of some instructions, which does
|
||||
// check for duplicates.
|
||||
Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
|
||||
Id Builder::makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated)
|
||||
{
|
||||
// Don't look for previous one, because in the general case,
|
||||
// structs can be duplicated except for decorations.
|
||||
|
|
@ -326,6 +387,12 @@ Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
|
|||
module.mapInstruction(type);
|
||||
addName(type->getResultId(), name);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
|
||||
{
|
||||
auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -372,6 +439,12 @@ Id Builder::makeVectorType(Id component, int size)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeVectorDebugType(component, size);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -398,6 +471,12 @@ Id Builder::makeMatrixType(Id component, int cols, int rows)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeMatrixDebugType(column, cols);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -484,6 +563,12 @@ Id Builder::makeArrayType(Id element, Id sizeId, int stride)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeArrayDebugType(element, sizeId);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +579,12 @@ Id Builder::makeRuntimeArray(Id element)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0));
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -513,11 +604,25 @@ Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
|
|||
}
|
||||
}
|
||||
if (! mismatch)
|
||||
{
|
||||
// If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void)
|
||||
// function type is created for the wrapper function. However, nonsemantic shader debug information is disabled
|
||||
// while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create
|
||||
// the associated debug function type if it hasn't been created yet.
|
||||
if(emitNonSemanticShaderDebugInfo && debugId[type->getResultId()] == 0) {
|
||||
assert(sourceLang == spv::SourceLanguageHLSL);
|
||||
assert(getTypeClass(returnType) == OpTypeVoid && paramTypes.size() == 0);
|
||||
|
||||
Id debugTypeId = makeDebugFunctionType(returnType, {});
|
||||
debugId[type->getResultId()] = debugTypeId;
|
||||
}
|
||||
return type->getResultId();
|
||||
}
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
|
||||
Id typeId = getUniqueId();
|
||||
type = new Instruction(typeId, NoType, OpTypeFunction);
|
||||
type->addIdOperand(returnType);
|
||||
for (int p = 0; p < (int)paramTypes.size(); ++p)
|
||||
type->addIdOperand(paramTypes[p]);
|
||||
|
|
@ -525,9 +630,34 @@ Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
// make debug type and map it
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
Id debugTypeId = makeDebugFunctionType(returnType, paramTypes);
|
||||
debugId[typeId] = debugTypeId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes)
|
||||
{
|
||||
assert(debugId[returnType] != 0);
|
||||
|
||||
Id typeId = getUniqueId();
|
||||
auto type = new Instruction(typeId, makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction);
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
|
||||
type->addIdOperand(debugId[returnType]);
|
||||
for (auto const paramType : paramTypes) {
|
||||
assert(isPointerType(paramType) || isArrayType(paramType));
|
||||
type->addIdOperand(debugId[getContainedTypeId(paramType)]);
|
||||
}
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
return typeId;
|
||||
}
|
||||
|
||||
Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
|
||||
ImageFormat format)
|
||||
{
|
||||
|
|
@ -609,6 +739,22 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo
|
|||
}
|
||||
#endif
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto TypeName = [&dim]() -> char const* {
|
||||
switch (dim) {
|
||||
case Dim1D: return "type.1d.image";
|
||||
case Dim2D: return "type.2d.image";
|
||||
case Dim3D: return "type.3d.image";
|
||||
case DimCube: return "type.cube.image";
|
||||
default: return "type.image";
|
||||
}
|
||||
};
|
||||
|
||||
auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
|
|
@ -630,9 +776,389 @@ Id Builder::makeSampledImageType(Id imageType)
|
|||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
{
|
||||
auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true);
|
||||
debugId[type->getResultId()] = debugResultId;
|
||||
}
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDebugInfoNone()
|
||||
{
|
||||
if (debugInfoNone != 0)
|
||||
return debugInfoNone;
|
||||
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone);
|
||||
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
|
||||
module.mapInstruction(inst);
|
||||
|
||||
debugInfoNone = inst->getResultId();
|
||||
|
||||
return debugInfoNone;
|
||||
}
|
||||
|
||||
Id Builder::makeBoolDebugType(int const size)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
|
||||
type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
|
||||
if (type->getIdOperand(0) == getStringId("bool") &&
|
||||
type->getIdOperand(1) == static_cast<unsigned int>(size) &&
|
||||
type->getIdOperand(2) == NonSemanticShaderDebugInfo100Boolean)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
|
||||
|
||||
type->addIdOperand(getStringId("bool")); // name id
|
||||
type->addIdOperand(makeUintConstant(size)); // size id
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); // encoding id
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeIntegerDebugType(int const width, bool const hasSign)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
|
||||
type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
|
||||
if (type->getIdOperand(0) == (hasSign ? getStringId("int") : getStringId("uint")) &&
|
||||
type->getIdOperand(1) == static_cast<unsigned int>(width) &&
|
||||
type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfo100Signed : NonSemanticShaderDebugInfo100Unsigned))
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
|
||||
if(hasSign == true) {
|
||||
type->addIdOperand(getStringId("int")); // name id
|
||||
} else {
|
||||
type->addIdOperand(getStringId("uint")); // name id
|
||||
}
|
||||
type->addIdOperand(makeUintConstant(width)); // size id
|
||||
if(hasSign == true) {
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); // encoding id
|
||||
} else {
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); // encoding id
|
||||
}
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeFloatDebugType(int const width)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
|
||||
type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
|
||||
if (type->getIdOperand(0) == getStringId("float") &&
|
||||
type->getIdOperand(1) == static_cast<unsigned int>(width) &&
|
||||
type->getIdOperand(2) == NonSemanticShaderDebugInfo100Float)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
|
||||
type->addIdOperand(getStringId("float")); // name id
|
||||
type->addIdOperand(makeUintConstant(width)); // size id
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); // encoding id
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType)
|
||||
{
|
||||
assert(sequenceType == NonSemanticShaderDebugInfo100DebugTypeArray ||
|
||||
sequenceType == NonSemanticShaderDebugInfo100DebugTypeVector);
|
||||
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) {
|
||||
type = groupedDebugTypes[sequenceType][t];
|
||||
if (type->getIdOperand(0) == baseType &&
|
||||
type->getIdOperand(1) == makeUintConstant(componentCount))
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(sequenceType);
|
||||
type->addIdOperand(debugId[baseType]); // base type
|
||||
type->addIdOperand(componentCount); // component count
|
||||
|
||||
groupedDebugTypes[sequenceType].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeArrayDebugType(Id const baseType, Id const componentCount)
|
||||
{
|
||||
return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfo100DebugTypeArray);
|
||||
}
|
||||
|
||||
Id Builder::makeVectorDebugType(Id const baseType, int const componentCount)
|
||||
{
|
||||
return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfo100DebugTypeVector);;
|
||||
}
|
||||
|
||||
Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].size(); ++t) {
|
||||
type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix][t];
|
||||
if (type->getIdOperand(0) == vectorType &&
|
||||
type->getIdOperand(1) == makeUintConstant(vectorCount))
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix);
|
||||
type->addIdOperand(debugId[vectorType]); // vector type id
|
||||
type->addIdOperand(makeUintConstant(vectorCount)); // component count id
|
||||
type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc)
|
||||
{
|
||||
assert(debugId[memberType] != 0);
|
||||
|
||||
Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember);
|
||||
type->addIdOperand(getStringId(debugTypeLoc.name)); // name id
|
||||
type->addIdOperand(debugId[memberType]); // type id
|
||||
type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
|
||||
type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero
|
||||
type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id
|
||||
type->addIdOperand(makeUintConstant(0)); // TODO: offset id
|
||||
type->addIdOperand(makeUintConstant(0)); // TODO: size id
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be
|
||||
// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names.
|
||||
Id Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
|
||||
NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType)
|
||||
{
|
||||
// Create the debug member types.
|
||||
std::vector<Id> memberDebugTypes;
|
||||
for(auto const memberType : memberTypes) {
|
||||
assert(debugTypeLocs.find(memberType) != debugTypeLocs.end());
|
||||
|
||||
memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType]));
|
||||
|
||||
// TODO: Need to rethink this method of passing location information.
|
||||
// debugTypeLocs.erase(memberType);
|
||||
}
|
||||
|
||||
// Create The structure debug type.
|
||||
Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite);
|
||||
type->addIdOperand(getStringId(name)); // name id
|
||||
type->addIdOperand(makeUintConstant(tag)); // tag id
|
||||
type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
|
||||
type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
|
||||
type->addIdOperand(makeUintConstant(0)); // TODO: column id
|
||||
type->addIdOperand(makeDebugCompilationUnit()); // scope id
|
||||
if(isOpaqueType == true) {
|
||||
// Prepend '@' to opaque types.
|
||||
type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id
|
||||
type->addIdOperand(makeDebugInfoNone()); // size id
|
||||
} else {
|
||||
type->addIdOperand(getStringId(name)); // linkage name id
|
||||
type->addIdOperand(makeUintConstant(0)); // TODO: size id
|
||||
}
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
|
||||
assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty()));
|
||||
for(auto const memberDebugType : memberDebugTypes) {
|
||||
type->addIdOperand(memberDebugType);
|
||||
}
|
||||
|
||||
groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type);
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDebugSource(const Id fileName) {
|
||||
if (debugSourceId.find(fileName) != debugSourceId.end())
|
||||
return debugSourceId[fileName];
|
||||
spv::Id resultId = getUniqueId();
|
||||
Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
|
||||
sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource);
|
||||
sourceInst->addIdOperand(fileName);
|
||||
if (emitNonSemanticShaderDebugSource) {
|
||||
spv::Id sourceId = 0;
|
||||
if (fileName == sourceFileStringId) {
|
||||
sourceId = getStringId(sourceText);
|
||||
} else {
|
||||
auto incItr = includeFiles.find(fileName);
|
||||
assert(incItr != includeFiles.end());
|
||||
sourceId = getStringId(*incItr->second);
|
||||
}
|
||||
sourceInst->addIdOperand(sourceId);
|
||||
}
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
|
||||
module.mapInstruction(sourceInst);
|
||||
debugSourceId[fileName] = resultId;
|
||||
return resultId;
|
||||
}
|
||||
|
||||
Id Builder::makeDebugCompilationUnit() {
|
||||
if (nonSemanticShaderCompilationUnitId != 0)
|
||||
return nonSemanticShaderCompilationUnitId;
|
||||
spv::Id resultId = getUniqueId();
|
||||
Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
|
||||
sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit);
|
||||
sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number
|
||||
sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number
|
||||
sourceInst->addIdOperand(makeDebugSource(sourceFileStringId));
|
||||
sourceInst->addIdOperand(makeUintConstant(sourceLang));
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
|
||||
module.mapInstruction(sourceInst);
|
||||
nonSemanticShaderCompilationUnitId = resultId;
|
||||
return resultId;
|
||||
}
|
||||
|
||||
Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable)
|
||||
{
|
||||
assert(type != 0);
|
||||
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable);
|
||||
inst->addIdOperand(getStringId(name)); // name id
|
||||
inst->addIdOperand(type); // type id
|
||||
inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
|
||||
inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
|
||||
inst->addIdOperand(makeUintConstant(0)); // TODO: column id
|
||||
inst->addIdOperand(makeDebugCompilationUnit()); // scope id
|
||||
inst->addIdOperand(getStringId(name)); // linkage name id
|
||||
inst->addIdOperand(variable); // variable id
|
||||
inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); // flags id
|
||||
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
|
||||
module.mapInstruction(inst);
|
||||
|
||||
return inst->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable);
|
||||
inst->addIdOperand(getStringId(name)); // name id
|
||||
inst->addIdOperand(type); // type id
|
||||
inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
|
||||
inst->addIdOperand(makeUintConstant(currentLine)); // line id
|
||||
inst->addIdOperand(makeUintConstant(0)); // TODO: column id
|
||||
inst->addIdOperand(currentDebugScopeId.top()); // scope id
|
||||
inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id
|
||||
if(argNumber != 0) {
|
||||
inst->addIdOperand(makeUintConstant(argNumber));
|
||||
}
|
||||
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
|
||||
module.mapInstruction(inst);
|
||||
|
||||
return inst->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDebugExpression()
|
||||
{
|
||||
if (debugExpression != 0)
|
||||
return debugExpression;
|
||||
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression);
|
||||
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
|
||||
module.mapInstruction(inst);
|
||||
|
||||
debugExpression = inst->getResultId();
|
||||
|
||||
return debugExpression;
|
||||
}
|
||||
|
||||
Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const localVariable)
|
||||
{
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare);
|
||||
inst->addIdOperand(debugLocalVariable); // debug local variable id
|
||||
inst->addIdOperand(localVariable); // local variable id
|
||||
inst->addIdOperand(makeDebugExpression()); // expression id
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
|
||||
|
||||
return inst->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDebugValue(Id const debugLocalVariable, Id const value)
|
||||
{
|
||||
Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
|
||||
inst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugValue);
|
||||
inst->addIdOperand(debugLocalVariable); // debug local variable id
|
||||
inst->addIdOperand(value); // value id
|
||||
inst->addIdOperand(makeDebugExpression()); // expression id
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
|
||||
|
||||
return inst->getResultId();
|
||||
}
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
Id Builder::makeAccelerationStructureType()
|
||||
{
|
||||
|
|
@ -920,6 +1446,17 @@ bool Builder::isSpecConstantOpCode(Op opcode) const
|
|||
}
|
||||
}
|
||||
|
||||
bool Builder::isRayTracingOpCode(Op opcode) const
|
||||
{
|
||||
switch (opcode) {
|
||||
case OpTypeAccelerationStructureKHR:
|
||||
case OpTypeRayQueryKHR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Id Builder::makeNullConstant(Id typeId)
|
||||
{
|
||||
Instruction* constant;
|
||||
|
|
@ -1136,6 +1673,19 @@ Id Builder::makeFpConstant(Id type, double d, bool specConstant)
|
|||
return NoResult;
|
||||
}
|
||||
|
||||
Id Builder::importNonSemanticShaderDebugInfoInstructions()
|
||||
{
|
||||
assert(emitNonSemanticShaderDebugInfo == true);
|
||||
|
||||
if(nonSemanticShaderDebugInfo == 0)
|
||||
{
|
||||
this->addExtension(spv::E_SPV_KHR_non_semantic_info);
|
||||
nonSemanticShaderDebugInfo = this->import("NonSemantic.Shader.DebugInfo.100");
|
||||
}
|
||||
|
||||
return nonSemanticShaderDebugInfo;
|
||||
}
|
||||
|
||||
Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps)
|
||||
{
|
||||
Instruction* constant = 0;
|
||||
|
|
@ -1447,23 +1997,34 @@ Function* Builder::makeEntryPoint(const char* entryPoint)
|
|||
assert(! entryPointFunction);
|
||||
|
||||
Block* entry;
|
||||
std::vector<Id> params;
|
||||
std::vector<Id> paramsTypes;
|
||||
std::vector<char const*> paramNames;
|
||||
std::vector<std::vector<Decoration>> decorations;
|
||||
|
||||
entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
|
||||
auto const returnType = makeVoidType();
|
||||
|
||||
restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
|
||||
if(sourceLang == spv::SourceLanguageHLSL) {
|
||||
emitNonSemanticShaderDebugInfo = false;
|
||||
}
|
||||
|
||||
entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, paramsTypes, paramNames, decorations, &entry);
|
||||
|
||||
emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
|
||||
|
||||
return entryPointFunction;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
|
||||
const std::vector<Id>& paramTypes,
|
||||
const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames,
|
||||
const std::vector<std::vector<Decoration>>& decorations, Block **entry)
|
||||
{
|
||||
// Make the function and initial instructions in it
|
||||
Id typeId = makeFunctionType(returnType, paramTypes);
|
||||
Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
|
||||
Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
|
||||
Id funcId = getUniqueId();
|
||||
Function* function = new Function(funcId, returnType, typeId, firstParamId, module);
|
||||
|
||||
// Set up the precisions
|
||||
setPrecision(function->getId(), precision);
|
||||
|
|
@ -1475,11 +2036,39 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const
|
|||
}
|
||||
}
|
||||
|
||||
// Make the debug function instruction
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
Id nameId = getStringId(unmangleFunctionName(name));
|
||||
Id debugFuncId = makeDebugFunction(function, nameId, typeId);
|
||||
debugId[funcId] = debugFuncId;
|
||||
currentDebugScopeId.push(debugFuncId);
|
||||
lastDebugScopeId = NoResult;
|
||||
}
|
||||
|
||||
// CFG
|
||||
if (entry) {
|
||||
*entry = new Block(getUniqueId(), *function);
|
||||
function->addBlock(*entry);
|
||||
setBuildPoint(*entry);
|
||||
assert(entry != nullptr);
|
||||
*entry = new Block(getUniqueId(), *function);
|
||||
function->addBlock(*entry);
|
||||
setBuildPoint(*entry);
|
||||
|
||||
// DebugScope and DebugLine for parameter DebugDeclares
|
||||
if (emitNonSemanticShaderDebugInfo && (int)paramTypes.size() > 0) {
|
||||
addDebugScopeAndLine(currentFileId, currentLine, 0);
|
||||
}
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
assert(paramTypes.size() == paramNames.size());
|
||||
for(size_t p = 0; p < paramTypes.size(); ++p)
|
||||
{
|
||||
auto const& paramType = paramTypes[p];
|
||||
assert(isPointerType(paramType) || isArrayType(paramType));
|
||||
assert(debugId[getContainedTypeId(paramType)] != 0);
|
||||
auto const& paramName = paramNames[p];
|
||||
auto const debugLocalVariableId = createDebugLocalVariable(debugId[getContainedTypeId(paramType)], paramName, p+1);
|
||||
debugId[firstParamId + p] = debugLocalVariableId;
|
||||
|
||||
makeDebugDeclare(debugLocalVariableId, firstParamId + p);
|
||||
}
|
||||
}
|
||||
|
||||
if (name)
|
||||
|
|
@ -1487,9 +2076,62 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const
|
|||
|
||||
functions.push_back(std::unique_ptr<Function>(function));
|
||||
|
||||
// Clear debug scope stack
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
currentDebugScopeId.pop();
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
Id Builder::makeDebugFunction(Function* function, Id nameId, Id funcTypeId) {
|
||||
assert(function != nullptr);
|
||||
assert(nameId != 0);
|
||||
assert(funcTypeId != 0);
|
||||
assert(debugId[funcTypeId] != 0);
|
||||
|
||||
Id funcId = getUniqueId();
|
||||
auto type = new Instruction(funcId, makeVoidType(), OpExtInst);
|
||||
type->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction);
|
||||
type->addIdOperand(nameId);
|
||||
type->addIdOperand(debugId[funcTypeId]);
|
||||
type->addIdOperand(makeDebugSource(currentFileId)); // Will be fixed later when true filename available
|
||||
type->addIdOperand(makeUintConstant(currentLine)); // Will be fixed later when true line available
|
||||
type->addIdOperand(makeUintConstant(0)); // column
|
||||
type->addIdOperand(makeDebugCompilationUnit()); // scope
|
||||
type->addIdOperand(nameId); // linkage name
|
||||
type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
|
||||
type->addIdOperand(makeUintConstant(currentLine)); // TODO(greg-lunarg): correct scope line
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
|
||||
module.mapInstruction(type);
|
||||
return funcId;
|
||||
}
|
||||
|
||||
Id Builder::makeDebugLexicalBlock(uint32_t line) {
|
||||
Id lexId = getUniqueId();
|
||||
auto lex = new Instruction(lexId, makeVoidType(), OpExtInst);
|
||||
lex->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock);
|
||||
lex->addIdOperand(makeDebugSource(currentFileId));
|
||||
lex->addIdOperand(makeUintConstant(line));
|
||||
lex->addIdOperand(makeUintConstant(0)); // column
|
||||
lex->addIdOperand(currentDebugScopeId.top()); // scope
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(lex));
|
||||
module.mapInstruction(lex);
|
||||
return lexId;
|
||||
}
|
||||
|
||||
std::string Builder::unmangleFunctionName(std::string const& name) const
|
||||
{
|
||||
assert(name.length() > 0);
|
||||
|
||||
if(name.rfind('(') != std::string::npos) {
|
||||
return name.substr(0, name.rfind('('));
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::makeReturn(bool implicit, Id retVal)
|
||||
{
|
||||
|
|
@ -1504,6 +2146,48 @@ void Builder::makeReturn(bool implicit, Id retVal)
|
|||
createAndSetNoPredecessorBlock("post-return");
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::enterScope(uint32_t line)
|
||||
{
|
||||
// Generate new lexical scope debug instruction
|
||||
Id lexId = makeDebugLexicalBlock(line);
|
||||
currentDebugScopeId.push(lexId);
|
||||
lastDebugScopeId = NoResult;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::leaveScope()
|
||||
{
|
||||
// Pop current scope from stack and clear current scope
|
||||
currentDebugScopeId.pop();
|
||||
lastDebugScopeId = NoResult;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::enterFunction(Function const* function)
|
||||
{
|
||||
// Save and disable debugInfo for HLSL entry point function. It is a wrapper
|
||||
// function with no user code in it.
|
||||
restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
|
||||
if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) {
|
||||
emitNonSemanticShaderDebugInfo = false;
|
||||
}
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
// Initialize scope state
|
||||
Id funcId = function->getFuncId();
|
||||
currentDebugScopeId.push(debugId[funcId]);
|
||||
// Create DebugFunctionDefinition
|
||||
spv::Id resultId = getUniqueId();
|
||||
Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst);
|
||||
defInst->addIdOperand(nonSemanticShaderDebugInfo);
|
||||
defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition);
|
||||
defInst->addIdOperand(debugId[funcId]);
|
||||
defInst->addIdOperand(funcId);
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(defInst));
|
||||
}
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
void Builder::leaveFunction()
|
||||
{
|
||||
|
|
@ -1519,6 +2203,12 @@ void Builder::leaveFunction()
|
|||
makeReturn(true, createUndefined(function.getReturnType()));
|
||||
}
|
||||
}
|
||||
|
||||
// Clear function scope from debug scope stack
|
||||
if (emitNonSemanticShaderDebugInfo)
|
||||
currentDebugScopeId.pop();
|
||||
|
||||
emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
|
|
@ -1529,7 +2219,8 @@ void Builder::makeStatementTerminator(spv::Op opcode, const char *name)
|
|||
}
|
||||
|
||||
// Comments in header
|
||||
Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer)
|
||||
Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer,
|
||||
bool const compilerGenerated)
|
||||
{
|
||||
Id pointerType = makePointer(storageClass, type);
|
||||
Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
|
||||
|
|
@ -1541,11 +2232,27 @@ Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id t
|
|||
case StorageClassFunction:
|
||||
// Validation rules require the declaration in the entry block
|
||||
buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
|
||||
{
|
||||
auto const debugLocalVariableId = createDebugLocalVariable(debugId[type], name);
|
||||
debugId[inst->getResultId()] = debugLocalVariableId;
|
||||
|
||||
// TODO: Remove?
|
||||
// makeDebugDeclare(debugLocalVariableId, inst->getResultId());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
|
||||
module.mapInstruction(inst);
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo && !isRayTracingOpCode(getOpCode(type)))
|
||||
{
|
||||
auto const debugResultId = createDebugGlobalVariable(debugId[type], name, inst->getResultId());
|
||||
debugId[inst->getResultId()] = debugResultId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1605,6 +2312,15 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce
|
|||
}
|
||||
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
|
||||
|
||||
if (emitNonSemanticShaderDebugInfo && !isGlobalVariable(lValue))
|
||||
{
|
||||
if(debugId.find(lValue) != debugId.end())
|
||||
{
|
||||
auto const debugLocalVariableId = debugId[lValue];
|
||||
makeDebugValue(debugLocalVariableId, rValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
|
|
@ -3271,10 +3987,10 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te
|
|||
const int opSourceWordCount = 4;
|
||||
const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
|
||||
|
||||
if (source != SourceLanguageUnknown) {
|
||||
if (sourceLang != SourceLanguageUnknown) {
|
||||
// OpSource Language Version File Source
|
||||
Instruction sourceInst(NoResult, NoType, OpSource);
|
||||
sourceInst.addImmediateOperand(source);
|
||||
sourceInst.addImmediateOperand(sourceLang);
|
||||
sourceInst.addImmediateOperand(sourceVersion);
|
||||
// File operand
|
||||
if (fileId != NoResult) {
|
||||
|
|
@ -3307,6 +4023,7 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te
|
|||
// Dump an OpSource[Continued] sequence for the source and every include file
|
||||
void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
|
||||
{
|
||||
if (emitNonSemanticShaderDebugInfo) return;
|
||||
dumpSourceInstructions(sourceFileStringId, sourceText, out);
|
||||
for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
|
||||
dumpSourceInstructions(iItr->first, *iItr->second, out);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@
|
|||
#include "Logger.h"
|
||||
#include "spirv.hpp"
|
||||
#include "spvIR.h"
|
||||
namespace spv {
|
||||
#include "GLSL.ext.KHR.h"
|
||||
#include "NonSemanticShaderDebugInfo100.h"
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
|
@ -82,7 +86,7 @@ public:
|
|||
|
||||
void setSource(spv::SourceLanguage lang, int version)
|
||||
{
|
||||
source = lang;
|
||||
sourceLang = lang;
|
||||
sourceVersion = version;
|
||||
}
|
||||
spv::Id getStringId(const std::string& str)
|
||||
|
|
@ -106,11 +110,25 @@ public:
|
|||
void setSourceFile(const std::string& file)
|
||||
{
|
||||
sourceFileStringId = getStringId(file);
|
||||
currentFileId = sourceFileStringId;
|
||||
}
|
||||
void setSourceText(const std::string& text) { sourceText = text; }
|
||||
void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
|
||||
void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
|
||||
void setEmitOpLines() { emitOpLines = true; }
|
||||
void setEmitNonSemanticShaderDebugInfo(bool const emit)
|
||||
{
|
||||
emitNonSemanticShaderDebugInfo = emit;
|
||||
|
||||
if(emit)
|
||||
{
|
||||
importNonSemanticShaderDebugInfoInstructions();
|
||||
}
|
||||
}
|
||||
void setEmitNonSemanticShaderDebugSource(bool const src)
|
||||
{
|
||||
emitNonSemanticShaderDebugSource = src;
|
||||
}
|
||||
void addExtension(const char* ext) { extensions.insert(ext); }
|
||||
void removeExtension(const char* ext)
|
||||
{
|
||||
|
|
@ -163,10 +181,11 @@ public:
|
|||
void setLine(int line, const char* filename);
|
||||
// Low-level OpLine. See setLine() for a layered helper.
|
||||
void addLine(Id fileName, int line, int column);
|
||||
void addDebugScopeAndLine(Id fileName, int line, int column);
|
||||
|
||||
// For creating new types (will return old type if the requested one was already made).
|
||||
Id makeVoidType();
|
||||
Id makeBoolType();
|
||||
Id makeBoolType(bool const compilerGenerated = true);
|
||||
Id makePointer(StorageClass, Id pointee);
|
||||
Id makeForwardPointer(StorageClass);
|
||||
Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
|
||||
|
|
@ -174,7 +193,7 @@ public:
|
|||
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||
Id makeFloatType(int width);
|
||||
Id makeStructType(const std::vector<Id>& members, const char*);
|
||||
Id makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated = true);
|
||||
Id makeStructResultType(Id type0, Id type1);
|
||||
Id makeVectorType(Id component, int size);
|
||||
Id makeMatrixType(Id component, int cols, int rows);
|
||||
|
|
@ -187,6 +206,36 @@ public:
|
|||
Id makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols);
|
||||
Id makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands);
|
||||
|
||||
// SPIR-V NonSemantic Shader DebugInfo Instructions
|
||||
struct DebugTypeLoc {
|
||||
std::string name {};
|
||||
int line {0};
|
||||
int column {0};
|
||||
};
|
||||
std::unordered_map<Id, DebugTypeLoc> debugTypeLocs;
|
||||
Id makeDebugInfoNone();
|
||||
Id makeBoolDebugType(int const size);
|
||||
Id makeIntegerDebugType(int const width, bool const hasSign);
|
||||
Id makeFloatDebugType(int const width);
|
||||
Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType);
|
||||
Id makeArrayDebugType(Id const baseType, Id const componentCount);
|
||||
Id makeVectorDebugType(Id const baseType, int const componentCount);
|
||||
Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true);
|
||||
Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc);
|
||||
Id makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
|
||||
NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false);
|
||||
Id makeDebugSource(const Id fileName);
|
||||
Id makeDebugCompilationUnit();
|
||||
Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable);
|
||||
Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0);
|
||||
Id makeDebugExpression();
|
||||
Id makeDebugDeclare(Id const debugLocalVariable, Id const localVariable);
|
||||
Id makeDebugValue(Id const debugLocalVariable, Id const value);
|
||||
Id makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes);
|
||||
Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId);
|
||||
Id makeDebugLexicalBlock(uint32_t line);
|
||||
std::string unmangleFunctionName(std::string const& name) const;
|
||||
|
||||
// accelerationStructureNV type
|
||||
Id makeAccelerationStructureType();
|
||||
// rayQueryEXT type
|
||||
|
|
@ -261,6 +310,8 @@ public:
|
|||
// See if a resultId is valid for use as an initializer.
|
||||
bool isValidInitializer(Id resultId) const { return isConstant(resultId) || isGlobalVariable(resultId); }
|
||||
|
||||
bool isRayTracingOpCode(Op opcode) const;
|
||||
|
||||
int getScalarTypeWidth(Id typeId) const
|
||||
{
|
||||
Id scalarTypeId = getScalarTypeId(typeId);
|
||||
|
|
@ -322,6 +373,8 @@ public:
|
|||
Id makeFloat16Constant(float f16, bool specConstant = false);
|
||||
Id makeFpConstant(Id type, double d, bool specConstant = false);
|
||||
|
||||
Id importNonSemanticShaderDebugInfoInstructions();
|
||||
|
||||
// Turn the array of constants into a proper spv constant of the requested type.
|
||||
Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
|
||||
|
||||
|
|
@ -344,7 +397,12 @@ public:
|
|||
void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector<const char*>& strings);
|
||||
|
||||
// At the end of what block do the next create*() instructions go?
|
||||
void setBuildPoint(Block* bp) { buildPoint = bp; }
|
||||
// Also reset current last DebugScope and current source line to unknown
|
||||
void setBuildPoint(Block* bp) {
|
||||
buildPoint = bp;
|
||||
lastDebugScopeId = NoResult;
|
||||
currentLine = 0;
|
||||
}
|
||||
Block* getBuildPoint() const { return buildPoint; }
|
||||
|
||||
// Make the entry-point function. The returned pointer is only valid
|
||||
|
|
@ -355,12 +413,22 @@ public:
|
|||
// Return the function, pass back the entry.
|
||||
// The returned pointer is only valid for the lifetime of this builder.
|
||||
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name,
|
||||
const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
|
||||
const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames,
|
||||
const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
|
||||
|
||||
// Create a return. An 'implicit' return is one not appearing in the source
|
||||
// code. In the case of an implicit return, no post-return block is inserted.
|
||||
void makeReturn(bool implicit, Id retVal = 0);
|
||||
|
||||
// Initialize state and generate instructions for new lexical scope
|
||||
void enterScope(uint32_t line);
|
||||
|
||||
// Set state and generate instructions to exit current lexical scope
|
||||
void leaveScope();
|
||||
|
||||
// Prepare builder for generation of instructions for a function.
|
||||
void enterFunction(Function const* function);
|
||||
|
||||
// Generate all the code needed to finish up a function.
|
||||
void leaveFunction();
|
||||
|
||||
|
|
@ -369,8 +437,8 @@ public:
|
|||
void makeStatementTerminator(spv::Op opcode, const char *name);
|
||||
|
||||
// Create a global or function local or IO variable.
|
||||
Id createVariable(Decoration precision, StorageClass, Id type, const char* name = nullptr,
|
||||
Id initializer = NoResult);
|
||||
Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr,
|
||||
Id initializer = NoResult, bool const compilerGenerated = true);
|
||||
|
||||
// Create an intermediate with an undefined value.
|
||||
Id createUndefined(Id type);
|
||||
|
|
@ -805,13 +873,23 @@ public:
|
|||
const;
|
||||
|
||||
unsigned int spvVersion; // the version of SPIR-V to emit in the header
|
||||
SourceLanguage source;
|
||||
SourceLanguage sourceLang;
|
||||
int sourceVersion;
|
||||
spv::Id sourceFileStringId;
|
||||
spv::Id nonSemanticShaderCompilationUnitId {0};
|
||||
spv::Id nonSemanticShaderDebugInfo {0};
|
||||
spv::Id debugInfoNone {0};
|
||||
spv::Id debugExpression {0}; // Debug expression with zero operations.
|
||||
std::string sourceText;
|
||||
int currentLine;
|
||||
const char* currentFile;
|
||||
spv::Id currentFileId;
|
||||
std::stack<spv::Id> currentDebugScopeId;
|
||||
spv::Id lastDebugScopeId;
|
||||
bool emitOpLines;
|
||||
bool emitNonSemanticShaderDebugInfo;
|
||||
bool restoreNonSemanticShaderDebugInfo;
|
||||
bool emitNonSemanticShaderDebugSource;
|
||||
std::set<std::string> extensions;
|
||||
std::vector<const char*> sourceExtensions;
|
||||
std::vector<const char*> moduleProcesses;
|
||||
|
|
@ -845,6 +923,8 @@ public:
|
|||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
|
||||
// map type opcodes to type instructions
|
||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
|
||||
// map type opcodes to debug type instructions
|
||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedDebugTypes;
|
||||
// list of OpConstantNull instructions
|
||||
std::vector<Instruction*> nullConstants;
|
||||
|
||||
|
|
@ -860,6 +940,12 @@ public:
|
|||
// map from include file name ids to their contents
|
||||
std::map<spv::Id, const std::string*> includeFiles;
|
||||
|
||||
// map from core id to debug id
|
||||
std::map <spv::Id, spv::Id> debugId;
|
||||
|
||||
// map from file name string id to DebugSource id
|
||||
std::unordered_map<spv::Id, spv::Id> debugSourceId;
|
||||
|
||||
// The stream for outputting warnings and errors.
|
||||
SpvBuildLogger* logger;
|
||||
}; // end Builder class
|
||||
|
|
|
|||
|
|
@ -53,14 +53,14 @@
|
|||
namespace glslang {
|
||||
|
||||
struct SpvOptions {
|
||||
SpvOptions() : generateDebugInfo(false), stripDebugInfo(false), disableOptimizer(true),
|
||||
optimizeSize(false), disassemble(false), validate(false) { }
|
||||
bool generateDebugInfo;
|
||||
bool stripDebugInfo;
|
||||
bool disableOptimizer;
|
||||
bool optimizeSize;
|
||||
bool disassemble;
|
||||
bool validate;
|
||||
bool generateDebugInfo {false};
|
||||
bool stripDebugInfo {false};
|
||||
bool disableOptimizer {true};
|
||||
bool optimizeSize {false};
|
||||
bool disassemble {false};
|
||||
bool validate {false};
|
||||
bool emitNonSemanticShaderDebugInfo {false};
|
||||
bool emitNonSemanticShaderDebugSource{ false };
|
||||
};
|
||||
|
||||
#if ENABLE_OPT
|
||||
|
|
|
|||
|
|
@ -349,6 +349,7 @@ public:
|
|||
const std::vector<Block*>& getBlocks() const { return blocks; }
|
||||
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
||||
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
||||
Id getFuncId() const { return functionInstruction.getResultId(); }
|
||||
void setReturnPrecision(Decoration precision)
|
||||
{
|
||||
if (precision == DecorationRelaxedPrecision)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue