mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
Add --no-link option
Adds the --no-link option which outputs the compiled shader binaries without linking them. This is a first step towards allowing users to create SPIR-v binary, non-executable libraries. When using the --no-link option, all functions are decorated with the Export linkage attribute.
This commit is contained in:
parent
a4aceb57de
commit
4c57db1595
@ -133,7 +133,7 @@ public:
|
||||
bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
|
||||
bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
|
||||
|
||||
void finishSpv();
|
||||
void finishSpv(bool compileOnly);
|
||||
void dumpSpv(std::vector<unsigned int>& out);
|
||||
|
||||
protected:
|
||||
@ -167,6 +167,7 @@ protected:
|
||||
bool filterMember(const glslang::TType& member);
|
||||
spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
|
||||
glslang::TLayoutPacking, const glslang::TQualifier&);
|
||||
spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType);
|
||||
void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
|
||||
const glslang::TQualifier&, spv::Id, const std::vector<spv::Id>& spvMembers);
|
||||
spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false);
|
||||
@ -1588,8 +1589,12 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
|
||||
builder.addCapability(spv::CapabilityVariablePointers);
|
||||
}
|
||||
|
||||
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
|
||||
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
|
||||
// If not linking, there is no entry point
|
||||
if (!options.compileOnly) {
|
||||
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
|
||||
entryPoint =
|
||||
builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
|
||||
}
|
||||
|
||||
// Add the source extensions
|
||||
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
|
||||
@ -1939,23 +1944,26 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
|
||||
}
|
||||
|
||||
// Finish creating SPV, after the traversal is complete.
|
||||
void TGlslangToSpvTraverser::finishSpv()
|
||||
void TGlslangToSpvTraverser::finishSpv(bool compileOnly)
|
||||
{
|
||||
// Finish the entry point function
|
||||
if (! entryPointTerminated) {
|
||||
builder.setBuildPoint(shaderEntry->getLastBlock());
|
||||
builder.leaveFunction();
|
||||
}
|
||||
// If not linking, an entry point is not expected
|
||||
if (!compileOnly) {
|
||||
// Finish the entry point function
|
||||
if (!entryPointTerminated) {
|
||||
builder.setBuildPoint(shaderEntry->getLastBlock());
|
||||
builder.leaveFunction();
|
||||
}
|
||||
|
||||
// finish off the entry-point SPV instruction by adding the Input/Output <id>
|
||||
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
||||
entryPoint->addIdOperand(*it);
|
||||
// finish off the entry-point SPV instruction by adding the Input/Output <id>
|
||||
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
||||
entryPoint->addIdOperand(*it);
|
||||
}
|
||||
|
||||
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||
// based on the resulting SPIR-V.
|
||||
// Note: WebGPU code generation must have the opportunity to aggressively
|
||||
// prune unreachable merge blocks and continue targets.
|
||||
builder.postProcess();
|
||||
builder.postProcess(compileOnly);
|
||||
}
|
||||
|
||||
// Write the SPV into 'out'.
|
||||
@ -2840,9 +2848,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
// 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());
|
||||
// Global initializers is specific to the shader entry point, which does not exist in compile-only mode
|
||||
if (!options.compileOnly) {
|
||||
// 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())
|
||||
@ -4329,6 +4340,16 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
|
||||
}
|
||||
|
||||
spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType)
|
||||
{
|
||||
switch (linkType) {
|
||||
case glslang::ELinkExport:
|
||||
return spv::LinkageTypeExport;
|
||||
default:
|
||||
return spv::LinkageTypeMax;
|
||||
}
|
||||
}
|
||||
|
||||
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
|
||||
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
|
||||
// Mutually recursive with convertGlslangStructToSpvType().
|
||||
@ -5396,10 +5417,10 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF
|
||||
}
|
||||
|
||||
spv::Block* functionBlock;
|
||||
spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()),
|
||||
convertGlslangToSpvType(glslFunction->getType()),
|
||||
glslFunction->getName().c_str(), paramTypes, paramNames,
|
||||
paramDecorations, &functionBlock);
|
||||
spv::Function* function = builder.makeFunctionEntry(
|
||||
TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),
|
||||
glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,
|
||||
paramNames, paramDecorations, &functionBlock);
|
||||
if (implicitThis)
|
||||
function->setImplicitThis();
|
||||
|
||||
@ -10102,7 +10123,7 @@ void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>&
|
||||
|
||||
TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
|
||||
root->traverse(&it);
|
||||
it.finishSpv();
|
||||
it.finishSpv(options->compileOnly);
|
||||
it.dumpSpv(spirv);
|
||||
|
||||
#if ENABLE_OPT
|
||||
|
@ -1835,6 +1835,10 @@ Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, co
|
||||
// Currently relying on the fact that all 'value' of interest are small non-negative values.
|
||||
void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
|
||||
{
|
||||
// entryPoint can be null if we are in compile-only mode
|
||||
if (!entryPoint)
|
||||
return;
|
||||
|
||||
Instruction* instr = new Instruction(OpExecutionMode);
|
||||
instr->addIdOperand(entryPoint->getId());
|
||||
instr->addImmediateOperand(mode);
|
||||
@ -1850,6 +1854,10 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int val
|
||||
|
||||
void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector<unsigned>& literals)
|
||||
{
|
||||
// entryPoint can be null if we are in compile-only mode
|
||||
if (!entryPoint)
|
||||
return;
|
||||
|
||||
Instruction* instr = new Instruction(OpExecutionMode);
|
||||
instr->addIdOperand(entryPoint->getId());
|
||||
instr->addImmediateOperand(mode);
|
||||
@ -1861,6 +1869,10 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const s
|
||||
|
||||
void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector<Id>& operandIds)
|
||||
{
|
||||
// entryPoint can be null if we are in compile-only mode
|
||||
if (!entryPoint)
|
||||
return;
|
||||
|
||||
Instruction* instr = new Instruction(OpExecutionModeId);
|
||||
instr->addIdOperand(entryPoint->getId());
|
||||
instr->addImmediateOperand(mode);
|
||||
@ -1944,6 +1956,16 @@ void Builder::addDecoration(Id id, Decoration decoration, const std::vector<cons
|
||||
decorations.push_back(std::unique_ptr<Instruction>(dec));
|
||||
}
|
||||
|
||||
void Builder::addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType) {
|
||||
Instruction* dec = new Instruction(OpDecorate);
|
||||
dec->addIdOperand(id);
|
||||
dec->addImmediateOperand(spv::DecorationLinkageAttributes);
|
||||
dec->addStringOperand(name);
|
||||
dec->addImmediateOperand(linkType);
|
||||
|
||||
decorations.push_back(std::unique_ptr<Instruction>(dec));
|
||||
}
|
||||
|
||||
void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
|
||||
{
|
||||
if (decoration == spv::DecorationMax)
|
||||
@ -2048,7 +2070,7 @@ Function* Builder::makeEntryPoint(const char* entryPoint)
|
||||
emitNonSemanticShaderDebugInfo = false;
|
||||
}
|
||||
|
||||
entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, paramsTypes, paramNames, decorations, &entry);
|
||||
entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, LinkageTypeMax, paramsTypes, paramNames, decorations, &entry);
|
||||
|
||||
emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
|
||||
|
||||
@ -2056,7 +2078,7 @@ Function* Builder::makeEntryPoint(const char* entryPoint)
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
|
||||
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
|
||||
const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames,
|
||||
const std::vector<std::vector<Decoration>>& decorations, Block **entry)
|
||||
{
|
||||
@ -2064,7 +2086,7 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const
|
||||
Id typeId = makeFunctionType(returnType, paramTypes);
|
||||
Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
|
||||
Id funcId = getUniqueId();
|
||||
Function* function = new Function(funcId, returnType, typeId, firstParamId, module);
|
||||
Function* function = new Function(funcId, returnType, typeId, firstParamId, linkType, name, module);
|
||||
|
||||
// Set up the precisions
|
||||
setPrecision(function->getId(), precision);
|
||||
@ -2234,6 +2256,12 @@ void Builder::enterFunction(Function const* function)
|
||||
defInst->addIdOperand(funcId);
|
||||
buildPoint->addInstruction(std::unique_ptr<Instruction>(defInst));
|
||||
}
|
||||
|
||||
if (auto linkType = function->getLinkType(); linkType != LinkageTypeMax) {
|
||||
Id funcId = function->getFuncId();
|
||||
addCapability(CapabilityLinkage);
|
||||
addLinkageDecoration(funcId, function->getExportName(), linkType);
|
||||
}
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
|
@ -393,6 +393,7 @@ public:
|
||||
void addDecoration(Id, Decoration, const char*);
|
||||
void addDecoration(Id, Decoration, const std::vector<unsigned>& literals);
|
||||
void addDecoration(Id, Decoration, const std::vector<const char*>& strings);
|
||||
void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType);
|
||||
void addDecorationId(Id id, Decoration, Id idDecoration);
|
||||
void addDecorationId(Id id, Decoration, const std::vector<Id>& operandIds);
|
||||
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
|
||||
@ -417,7 +418,8 @@ 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<char const*>& paramNames,
|
||||
LinkageType linkType, const std::vector<Id>& paramTypes,
|
||||
const std::vector<char const*>& paramNames,
|
||||
const std::vector<std::vector<Decoration>>& precisions, Block **entry = nullptr);
|
||||
|
||||
// Create a return. An 'implicit' return is one not appearing in the source
|
||||
@ -828,7 +830,7 @@ public:
|
||||
|
||||
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||
// based on the resulting SPIR-V.
|
||||
void postProcess();
|
||||
void postProcess(bool compileOnly);
|
||||
|
||||
// Prune unreachable blocks in the CFG and remove unneeded decorations.
|
||||
void postProcessCFG();
|
||||
|
@ -483,9 +483,13 @@ void Builder::postProcessFeatures() {
|
||||
}
|
||||
|
||||
// comment in header
|
||||
void Builder::postProcess() {
|
||||
postProcessCFG();
|
||||
postProcessFeatures();
|
||||
void Builder::postProcess(bool compileOnly)
|
||||
{
|
||||
// postProcessCFG needs an entrypoint to determine what is reachable, but if we are not creating an "executable" shader, we don't have an entrypoint
|
||||
if (!compileOnly)
|
||||
postProcessCFG();
|
||||
|
||||
postProcessFeatures();
|
||||
}
|
||||
|
||||
}; // end spv namespace
|
||||
|
@ -61,6 +61,7 @@ struct SpvOptions {
|
||||
bool validate {false};
|
||||
bool emitNonSemanticShaderDebugInfo {false};
|
||||
bool emitNonSemanticShaderDebugSource{ false };
|
||||
bool compileOnly{false};
|
||||
};
|
||||
|
||||
#if ENABLE_OPT
|
||||
|
@ -323,7 +323,7 @@ void inReadableOrder(Block* root, std::function<void(Block*, ReachReason, Block*
|
||||
|
||||
class Function {
|
||||
public:
|
||||
Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
|
||||
Function(Id id, Id resultType, Id functionType, Id firstParam, LinkageType linkage, const std::string& name, Module& parent);
|
||||
virtual ~Function()
|
||||
{
|
||||
for (int i = 0; i < (int)parameterInstructions.size(); ++i)
|
||||
@ -402,6 +402,9 @@ public:
|
||||
end.dump(out);
|
||||
}
|
||||
|
||||
LinkageType getLinkType() const { return linkType; }
|
||||
const char* getExportName() const { return exportName.c_str(); }
|
||||
|
||||
protected:
|
||||
Function(const Function&);
|
||||
Function& operator=(Function&);
|
||||
@ -414,6 +417,8 @@ protected:
|
||||
bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument
|
||||
bool reducedPrecisionReturn;
|
||||
std::set<int> reducedPrecisionParams; // list of parameter indexes that need a relaxed precision arg
|
||||
LinkageType linkType;
|
||||
std::string exportName;
|
||||
};
|
||||
|
||||
//
|
||||
@ -473,10 +478,11 @@ protected:
|
||||
// Add both
|
||||
// - the OpFunction instruction
|
||||
// - all the OpFunctionParameter instructions
|
||||
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
|
||||
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, LinkageType linkage, const std::string& name, Module& parent)
|
||||
: parent(parent), lineInstruction(nullptr),
|
||||
functionInstruction(id, resultType, OpFunction), implicitThis(false),
|
||||
reducedPrecisionReturn(false)
|
||||
reducedPrecisionReturn(false),
|
||||
linkType(linkage)
|
||||
{
|
||||
// OpFunction
|
||||
functionInstruction.addImmediateOperand(FunctionControlMaskNone);
|
||||
@ -492,6 +498,11 @@ __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParam
|
||||
parent.mapInstruction(param);
|
||||
parameterInstructions.push_back(param);
|
||||
}
|
||||
|
||||
// If importing/exporting, save the function name (without the mangled parameters) for the linkage decoration
|
||||
if (linkType != LinkageTypeMax) {
|
||||
exportName = name.substr(0, name.find_first_of('('));
|
||||
}
|
||||
}
|
||||
|
||||
__inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
|
||||
|
@ -73,40 +73,41 @@ extern "C" {
|
||||
}
|
||||
|
||||
// Command-line options
|
||||
enum TOptions {
|
||||
EOptionNone = 0,
|
||||
EOptionIntermediate = (1 << 0),
|
||||
EOptionSuppressInfolog = (1 << 1),
|
||||
EOptionMemoryLeakMode = (1 << 2),
|
||||
EOptionRelaxedErrors = (1 << 3),
|
||||
EOptionGiveWarnings = (1 << 4),
|
||||
EOptionLinkProgram = (1 << 5),
|
||||
EOptionMultiThreaded = (1 << 6),
|
||||
EOptionDumpConfig = (1 << 7),
|
||||
EOptionDumpReflection = (1 << 8),
|
||||
EOptionSuppressWarnings = (1 << 9),
|
||||
EOptionDumpVersions = (1 << 10),
|
||||
EOptionSpv = (1 << 11),
|
||||
EOptionHumanReadableSpv = (1 << 12),
|
||||
EOptionVulkanRules = (1 << 13),
|
||||
EOptionDefaultDesktop = (1 << 14),
|
||||
EOptionOutputPreprocessed = (1 << 15),
|
||||
EOptionOutputHexadecimal = (1 << 16),
|
||||
EOptionReadHlsl = (1 << 17),
|
||||
EOptionCascadingErrors = (1 << 18),
|
||||
EOptionAutoMapBindings = (1 << 19),
|
||||
EOptionFlattenUniformArrays = (1 << 20),
|
||||
EOptionNoStorageFormat = (1 << 21),
|
||||
EOptionKeepUncalled = (1 << 22),
|
||||
EOptionHlslOffsets = (1 << 23),
|
||||
EOptionHlslIoMapping = (1 << 24),
|
||||
EOptionAutoMapLocations = (1 << 25),
|
||||
EOptionDebug = (1 << 26),
|
||||
EOptionStdin = (1 << 27),
|
||||
EOptionOptimizeDisable = (1 << 28),
|
||||
EOptionOptimizeSize = (1 << 29),
|
||||
EOptionInvertY = (1 << 30),
|
||||
EOptionDumpBareVersion = (1 << 31),
|
||||
enum TOptions : uint64_t {
|
||||
EOptionNone = 0,
|
||||
EOptionIntermediate = (1ull << 0),
|
||||
EOptionSuppressInfolog = (1ull << 1),
|
||||
EOptionMemoryLeakMode = (1ull << 2),
|
||||
EOptionRelaxedErrors = (1ull << 3),
|
||||
EOptionGiveWarnings = (1ull << 4),
|
||||
EOptionLinkProgram = (1ull << 5),
|
||||
EOptionMultiThreaded = (1ull << 6),
|
||||
EOptionDumpConfig = (1ull << 7),
|
||||
EOptionDumpReflection = (1ull << 8),
|
||||
EOptionSuppressWarnings = (1ull << 9),
|
||||
EOptionDumpVersions = (1ull << 10),
|
||||
EOptionSpv = (1ull << 11),
|
||||
EOptionHumanReadableSpv = (1ull << 12),
|
||||
EOptionVulkanRules = (1ull << 13),
|
||||
EOptionDefaultDesktop = (1ull << 14),
|
||||
EOptionOutputPreprocessed = (1ull << 15),
|
||||
EOptionOutputHexadecimal = (1ull << 16),
|
||||
EOptionReadHlsl = (1ull << 17),
|
||||
EOptionCascadingErrors = (1ull << 18),
|
||||
EOptionAutoMapBindings = (1ull << 19),
|
||||
EOptionFlattenUniformArrays = (1ull << 20),
|
||||
EOptionNoStorageFormat = (1ull << 21),
|
||||
EOptionKeepUncalled = (1ull << 22),
|
||||
EOptionHlslOffsets = (1ull << 23),
|
||||
EOptionHlslIoMapping = (1ull << 24),
|
||||
EOptionAutoMapLocations = (1ull << 25),
|
||||
EOptionDebug = (1ull << 26),
|
||||
EOptionStdin = (1ull << 27),
|
||||
EOptionOptimizeDisable = (1ull << 28),
|
||||
EOptionOptimizeSize = (1ull << 29),
|
||||
EOptionInvertY = (1ull << 30),
|
||||
EOptionDumpBareVersion = (1ull << 31),
|
||||
EOptionCompileOnly = (1ull << 32),
|
||||
};
|
||||
bool targetHlslFunctionality1 = false;
|
||||
bool SpvToolsDisassembler = false;
|
||||
@ -166,7 +167,7 @@ void ProcessConfigFile()
|
||||
}
|
||||
|
||||
int ReflectOptions = EShReflectionDefault;
|
||||
int Options = 0;
|
||||
std::underlying_type_t<TOptions> Options = EOptionNone;
|
||||
const char* ExecutableName = nullptr;
|
||||
const char* binaryFileName = nullptr;
|
||||
const char* depencyFileName = nullptr;
|
||||
@ -889,6 +890,8 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
|
||||
bumpArg();
|
||||
} else if (lowerword == "version") {
|
||||
Options |= EOptionDumpVersions;
|
||||
} else if (lowerword == "no-link") {
|
||||
Options |= EOptionCompileOnly;
|
||||
} else if (lowerword == "help") {
|
||||
usage();
|
||||
break;
|
||||
@ -1310,6 +1313,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
//
|
||||
|
||||
glslang::TProgram& program = *new glslang::TProgram;
|
||||
const bool compileOnly = (Options & EOptionCompileOnly) != 0;
|
||||
for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
|
||||
const auto &compUnit = *it;
|
||||
for (int i = 0; i < compUnit.count; i++) {
|
||||
@ -1326,6 +1330,9 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
shader->setSourceEntryPoint(sourceEntryPointName);
|
||||
}
|
||||
|
||||
if (compileOnly)
|
||||
shader->setCompileOnly();
|
||||
|
||||
shader->setOverrideVersion(GlslVersion);
|
||||
|
||||
std::string intrinsicString = getIntrinsic(compUnit.text, compUnit.count);
|
||||
@ -1445,7 +1452,8 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
if (! shader->parse(GetResources(), defaultVersion, false, messages, includer))
|
||||
CompileFailed = true;
|
||||
|
||||
program.addShader(shader);
|
||||
if (!compileOnly)
|
||||
program.addShader(shader);
|
||||
|
||||
if (! (Options & EOptionSuppressInfolog) &&
|
||||
! (Options & EOptionMemoryLeakMode)) {
|
||||
@ -1460,27 +1468,28 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
// Program-level processing...
|
||||
//
|
||||
|
||||
// Link
|
||||
if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
|
||||
LinkFailed = true;
|
||||
|
||||
// Map IO
|
||||
if (Options & EOptionSpv) {
|
||||
if (!program.mapIO())
|
||||
if (!compileOnly) {
|
||||
// Link
|
||||
if (!(Options & EOptionOutputPreprocessed) && !program.link(messages))
|
||||
LinkFailed = true;
|
||||
}
|
||||
|
||||
// Report
|
||||
if (! (Options & EOptionSuppressInfolog) &&
|
||||
! (Options & EOptionMemoryLeakMode)) {
|
||||
PutsIfNonEmpty(program.getInfoLog());
|
||||
PutsIfNonEmpty(program.getInfoDebugLog());
|
||||
}
|
||||
// Map IO
|
||||
if (Options & EOptionSpv) {
|
||||
if (!program.mapIO())
|
||||
LinkFailed = true;
|
||||
}
|
||||
|
||||
// Reflect
|
||||
if (Options & EOptionDumpReflection) {
|
||||
program.buildReflection(ReflectOptions);
|
||||
program.dumpReflection();
|
||||
// Report
|
||||
if (!(Options & EOptionSuppressInfolog) && !(Options & EOptionMemoryLeakMode)) {
|
||||
PutsIfNonEmpty(program.getInfoLog());
|
||||
PutsIfNonEmpty(program.getInfoDebugLog());
|
||||
}
|
||||
|
||||
// Reflect
|
||||
if (Options & EOptionDumpReflection) {
|
||||
program.buildReflection(ReflectOptions);
|
||||
program.dumpReflection();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> outputFiles;
|
||||
@ -1490,44 +1499,58 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
if (CompileFailed || LinkFailed)
|
||||
printf("SPIR-V is not generated for failed compile or link\n");
|
||||
else {
|
||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||
if (program.getIntermediate((EShLanguage)stage)) {
|
||||
std::vector<unsigned int> spirv;
|
||||
spv::SpvBuildLogger logger;
|
||||
glslang::SpvOptions spvOptions;
|
||||
if (Options & EOptionDebug) {
|
||||
spvOptions.generateDebugInfo = true;
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
spvOptions.emitNonSemanticShaderDebugInfo = true;
|
||||
if (emitNonSemanticShaderDebugSource) {
|
||||
spvOptions.emitNonSemanticShaderDebugSource = true;
|
||||
}
|
||||
}
|
||||
} else if (stripDebugInfo)
|
||||
spvOptions.stripDebugInfo = true;
|
||||
spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
|
||||
spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
|
||||
spvOptions.disassemble = SpvToolsDisassembler;
|
||||
spvOptions.validate = SpvToolsValidate;
|
||||
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions);
|
||||
|
||||
// Dump the spv to a file or stdout, etc., but only if not doing
|
||||
// memory/perf testing, as it's not internal to programmatic use.
|
||||
if (! (Options & EOptionMemoryLeakMode)) {
|
||||
printf("%s", logger.getAllMessages().c_str());
|
||||
if (Options & EOptionOutputHexadecimal) {
|
||||
if (!glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage), variableName))
|
||||
exit(EFailUsage);
|
||||
} else {
|
||||
if (!glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage)))
|
||||
exit(EFailUsage);
|
||||
}
|
||||
|
||||
outputFiles.push_back(GetBinaryName((EShLanguage)stage));
|
||||
if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv))
|
||||
spv::Disassemble(std::cout, spirv);
|
||||
std::vector<glslang::TIntermediate*> intermediates;
|
||||
if (!compileOnly) {
|
||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||
if (auto* i = program.getIntermediate((EShLanguage)stage)) {
|
||||
intermediates.emplace_back(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto* shader : shaders) {
|
||||
if (auto* i = shader->getIntermediate()) {
|
||||
intermediates.emplace_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto* intermediate : intermediates) {
|
||||
std::vector<unsigned int> spirv;
|
||||
spv::SpvBuildLogger logger;
|
||||
glslang::SpvOptions spvOptions;
|
||||
if (Options & EOptionDebug) {
|
||||
spvOptions.generateDebugInfo = true;
|
||||
if (emitNonSemanticShaderDebugInfo) {
|
||||
spvOptions.emitNonSemanticShaderDebugInfo = true;
|
||||
if (emitNonSemanticShaderDebugSource) {
|
||||
spvOptions.emitNonSemanticShaderDebugSource = true;
|
||||
}
|
||||
}
|
||||
} else if (stripDebugInfo)
|
||||
spvOptions.stripDebugInfo = true;
|
||||
spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
|
||||
spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
|
||||
spvOptions.disassemble = SpvToolsDisassembler;
|
||||
spvOptions.validate = SpvToolsValidate;
|
||||
spvOptions.compileOnly = compileOnly;
|
||||
glslang::GlslangToSpv(*intermediate, spirv, &logger, &spvOptions);
|
||||
|
||||
// Dump the spv to a file or stdout, etc., but only if not doing
|
||||
// memory/perf testing, as it's not internal to programmatic use.
|
||||
if (!(Options & EOptionMemoryLeakMode)) {
|
||||
printf("%s", logger.getAllMessages().c_str());
|
||||
const auto filename = GetBinaryName(intermediate->getStage());
|
||||
if (Options & EOptionOutputHexadecimal) {
|
||||
if (!glslang::OutputSpvHex(spirv, filename, variableName))
|
||||
exit(EFailUsage);
|
||||
} else {
|
||||
if (!glslang::OutputSpvBin(spirv, filename))
|
||||
exit(EFailUsage);
|
||||
}
|
||||
|
||||
outputFiles.push_back(filename);
|
||||
if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv))
|
||||
spv::Disassemble(std::cout, spirv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2075,7 +2098,10 @@ void usage()
|
||||
" --variable-name <name>\n"
|
||||
" --vn <name> creates a C header file that contains a\n"
|
||||
" uint32_t array named <name>\n"
|
||||
" initialized with the shader binary code\n");
|
||||
" initialized with the shader binary code\n"
|
||||
" --no-link Only compile shader; do not link (GLSL-only)\n"
|
||||
" NOTE: this option will set the export linkage\n"
|
||||
" attribute on all functions\n");
|
||||
|
||||
exit(EFailUsage);
|
||||
}
|
||||
|
36
Test/baseResults/spv.exportFunctions.comp.out
Normal file
36
Test/baseResults/spv.exportFunctions.comp.out
Normal file
@ -0,0 +1,36 @@
|
||||
spv.exportFunctions.comp
|
||||
// Module Version 10000
|
||||
// Generated by (magic number): 8000b
|
||||
// Id's are bound by 22
|
||||
|
||||
Capability Shader
|
||||
Capability Linkage
|
||||
1: ExtInstImport "GLSL.std.450"
|
||||
MemoryModel Logical GLSL450
|
||||
Source GLSL 450
|
||||
Name 7 "add(f1;f1;"
|
||||
Name 5 "a"
|
||||
Name 6 "b"
|
||||
Name 11 "foo("
|
||||
Decorate 7(add(f1;f1;) Linkage Attributes 6579297 0
|
||||
Decorate 11(foo() Linkage Attributes 7303014 0
|
||||
2: TypeFloat 32
|
||||
3: TypePointer Function 2(float)
|
||||
4: TypeFunction 2(float) 3(ptr) 3(ptr)
|
||||
9: TypeInt 32 1
|
||||
10: TypeFunction 9(int)
|
||||
17: TypeVoid
|
||||
19: 9(int) Constant 0
|
||||
7(add(f1;f1;): 2(float) Function None 4
|
||||
5(a): 3(ptr) FunctionParameter
|
||||
6(b): 3(ptr) FunctionParameter
|
||||
8: Label
|
||||
13: 2(float) Load 5(a)
|
||||
14: 2(float) Load 6(b)
|
||||
15: 2(float) FAdd 13 14
|
||||
ReturnValue 15
|
||||
FunctionEnd
|
||||
11(foo(): 9(int) Function None 10
|
||||
12: Label
|
||||
ReturnValue 19
|
||||
FunctionEnd
|
9
Test/spv.exportFunctions.comp
Normal file
9
Test/spv.exportFunctions.comp
Normal file
@ -0,0 +1,9 @@
|
||||
#version 450
|
||||
|
||||
float add(float a, float b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int foo() {
|
||||
return 0;
|
||||
}
|
@ -101,6 +101,8 @@ namespace glslang {
|
||||
|
||||
if (name == "nonwritable") return EatNonWritable;
|
||||
if (name == "nonreadable") return EatNonReadable;
|
||||
|
||||
if (name == "export") return EatExport;
|
||||
} else if (nameSpace.size() > 0)
|
||||
return EatNone;
|
||||
|
||||
|
@ -226,6 +226,7 @@ typedef struct glslang_spv_options_s {
|
||||
bool validate;
|
||||
bool emit_nonsemantic_shader_debug_info;
|
||||
bool emit_nonsemantic_shader_debug_source;
|
||||
bool compile_only;
|
||||
} glslang_spv_options_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1108,6 +1108,11 @@ enum TOperator {
|
||||
EOpImageBlockMatchSSDQCOM,
|
||||
};
|
||||
|
||||
enum TLinkType {
|
||||
ELinkNone,
|
||||
ELinkExport,
|
||||
};
|
||||
|
||||
class TIntermTraverser;
|
||||
class TIntermOperator;
|
||||
class TIntermAggregate;
|
||||
@ -1325,9 +1330,11 @@ public:
|
||||
virtual const TString& getMethodName() const { return method; }
|
||||
virtual TIntermTyped* getObject() const { return object; }
|
||||
virtual void traverse(TIntermTraverser*);
|
||||
void setExport() { linkType = ELinkExport; }
|
||||
protected:
|
||||
TIntermTyped* object;
|
||||
TString method;
|
||||
TLinkType linkType;
|
||||
};
|
||||
|
||||
//
|
||||
@ -1700,6 +1707,9 @@ public:
|
||||
const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
|
||||
void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; }
|
||||
const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; }
|
||||
|
||||
void setLinkType(TLinkType l) { linkType = l; }
|
||||
TLinkType getLinkType() const { return linkType; }
|
||||
protected:
|
||||
TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
|
||||
TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
|
||||
@ -1711,6 +1721,7 @@ protected:
|
||||
bool debug;
|
||||
TPragmaTable* pragmaTable;
|
||||
TSpirvInstruction spirvInst;
|
||||
TLinkType linkType = ELinkNone;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -1243,6 +1243,8 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc,
|
||||
error(loc, "function cannot take any parameter(s)", function.getName().c_str(), "");
|
||||
if (function.getType().getBasicType() != EbtVoid)
|
||||
error(loc, "", function.getType().getBasicTypeString().c_str(), "entry point cannot return a value");
|
||||
if (function.getLinkType() != ELinkNone)
|
||||
error(loc, "main function cannot be exported", "", "");
|
||||
}
|
||||
|
||||
//
|
||||
@ -1279,6 +1281,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc,
|
||||
} else
|
||||
paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc);
|
||||
}
|
||||
paramNodes->setLinkType(function.getLinkType());
|
||||
intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc);
|
||||
loopNestingLevel = 0;
|
||||
statementNestingLevel = 0;
|
||||
|
@ -196,6 +196,7 @@ public:
|
||||
struct TPragma contextPragma;
|
||||
int beginInvocationInterlockCount;
|
||||
int endInvocationInterlockCount;
|
||||
bool compileOnly = false;
|
||||
|
||||
protected:
|
||||
TParseContextBase(TParseContextBase&);
|
||||
|
@ -796,7 +796,8 @@ bool ProcessDeferred(
|
||||
bool requireNonempty,
|
||||
TShader::Includer& includer,
|
||||
const std::string sourceEntryPointName = "",
|
||||
const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above
|
||||
const TEnvironment* environment = nullptr, // optional way of fully setting all versions, overriding the above
|
||||
bool compileOnly = false)
|
||||
{
|
||||
// This must be undone (.pop()) by the caller, after it finishes consuming the created tree.
|
||||
GetThreadPoolAllocator().push();
|
||||
@ -942,6 +943,7 @@ bool ProcessDeferred(
|
||||
std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(*symbolTable, intermediate, version, profile, source,
|
||||
stage, compiler->infoSink,
|
||||
spvVersion, forwardCompatible, messages, false, sourceEntryPointName));
|
||||
parseContext->compileOnly = compileOnly;
|
||||
TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer);
|
||||
|
||||
// only GLSL (bison triggered, really) needs an externally set scan context
|
||||
@ -1279,14 +1281,15 @@ bool CompileDeferred(
|
||||
TIntermediate& intermediate,// returned tree, etc.
|
||||
TShader::Includer& includer,
|
||||
const std::string sourceEntryPointName = "",
|
||||
TEnvironment* environment = nullptr)
|
||||
TEnvironment* environment = nullptr,
|
||||
bool compileOnly = false)
|
||||
{
|
||||
DoFullParse parser;
|
||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||
preamble, optLevel, resources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
|
||||
forwardCompatible, messages, intermediate, parser,
|
||||
true, includer, sourceEntryPointName, environment);
|
||||
true, includer, sourceEntryPointName, environment, compileOnly);
|
||||
}
|
||||
|
||||
} // end anonymous namespace for local functions
|
||||
@ -1867,7 +1870,7 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
|
||||
preamble, EShOptNone, builtInResources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile, overrideVersion,
|
||||
forwardCompatible, messages, *intermediate, includer, sourceEntryPointName,
|
||||
&environment);
|
||||
&environment, compileOnly);
|
||||
}
|
||||
|
||||
// Fill in a string with the result of preprocessing ShaderStrings
|
||||
|
@ -246,7 +246,8 @@ public:
|
||||
TSymbol(name),
|
||||
mangledName(*name + '('),
|
||||
op(tOp),
|
||||
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0)
|
||||
defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0),
|
||||
linkType(ELinkNone)
|
||||
{
|
||||
returnType.shallowCopy(retType);
|
||||
declaredBuiltIn = retType.getQualifier().builtIn;
|
||||
@ -326,6 +327,9 @@ public:
|
||||
|
||||
virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
|
||||
|
||||
void setExport() { linkType = ELinkExport; }
|
||||
TLinkType getLinkType() const { return linkType; }
|
||||
|
||||
protected:
|
||||
explicit TFunction(const TFunction&);
|
||||
TFunction& operator=(const TFunction&);
|
||||
@ -347,6 +351,7 @@ protected:
|
||||
int defaultParamCount;
|
||||
|
||||
TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers
|
||||
TLinkType linkType;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -123,6 +123,8 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const
|
||||
return EatPartialCount;
|
||||
else if (name == "subgroup_uniform_control_flow")
|
||||
return EatSubgroupUniformControlFlow;
|
||||
else if (name == "export")
|
||||
return EatExport;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
@ -355,6 +357,7 @@ void TParseContext::handleFunctionAttributes(const TSourceLoc& loc, const TAttri
|
||||
|
||||
switch (it->name) {
|
||||
case EatSubgroupUniformControlFlow:
|
||||
requireExtensions(loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute");
|
||||
intermediate.setSubgroupUniformControlFlow();
|
||||
break;
|
||||
default:
|
||||
|
@ -120,6 +120,7 @@ namespace glslang {
|
||||
EatNonWritable,
|
||||
EatNonReadable,
|
||||
EatSubgroupUniformControlFlow,
|
||||
EatExport,
|
||||
};
|
||||
|
||||
class TIntermAggregate;
|
||||
|
@ -941,24 +941,25 @@ identifier_list
|
||||
function_prototype
|
||||
: function_declarator RIGHT_PAREN {
|
||||
$$.function = $1;
|
||||
if (parseContext.compileOnly) $$.function->setExport();
|
||||
$$.loc = $2.loc;
|
||||
}
|
||||
| function_declarator RIGHT_PAREN attribute {
|
||||
$$.function = $1;
|
||||
if (parseContext.compileOnly) $$.function->setExport();
|
||||
$$.loc = $2.loc;
|
||||
parseContext.requireExtensions($2.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute");
|
||||
parseContext.handleFunctionAttributes($2.loc, *$3);
|
||||
}
|
||||
| attribute function_declarator RIGHT_PAREN {
|
||||
$$.function = $2;
|
||||
if (parseContext.compileOnly) $$.function->setExport();
|
||||
$$.loc = $3.loc;
|
||||
parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute");
|
||||
parseContext.handleFunctionAttributes($3.loc, *$1);
|
||||
}
|
||||
| attribute function_declarator RIGHT_PAREN attribute {
|
||||
$$.function = $2;
|
||||
if (parseContext.compileOnly) $$.function->setExport();
|
||||
$$.loc = $3.loc;
|
||||
parseContext.requireExtensions($3.loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute");
|
||||
parseContext.handleFunctionAttributes($3.loc, *$1);
|
||||
parseContext.handleFunctionAttributes($3.loc, *$4);
|
||||
}
|
||||
@ -4088,6 +4089,7 @@ function_definition
|
||||
parseContext.error($1.loc, "function does not return a value:", "", $1.function->getName().c_str());
|
||||
parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]);
|
||||
$$ = parseContext.intermediate.growAggregate($1.intermNode, $3);
|
||||
$$->getAsAggregate()->setLinkType($1.function->getLinkType());
|
||||
parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.function->getType(), $1.loc);
|
||||
$$->getAsAggregate()->setName($1.function->getMangledName().c_str());
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -524,7 +524,7 @@ extern int yydebug;
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 97 "MachineIndependent/glslang.y"
|
||||
#line 72 "MachineIndependent/glslang.y"
|
||||
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
|
@ -573,6 +573,9 @@ public:
|
||||
void setEnvInputVulkanRulesRelaxed() { environment.input.vulkanRulesRelaxed = true; }
|
||||
bool getEnvInputVulkanRulesRelaxed() const { return environment.input.vulkanRulesRelaxed; }
|
||||
|
||||
void setCompileOnly() { compileOnly = true; }
|
||||
bool getCompileOnly() const { return compileOnly; }
|
||||
|
||||
// Interface to #include handlers.
|
||||
//
|
||||
// To support #include, a client of Glslang does the following:
|
||||
@ -722,6 +725,9 @@ protected:
|
||||
|
||||
TEnvironment environment;
|
||||
|
||||
// Indicates this shader is meant to be used without linking
|
||||
bool compileOnly = false;
|
||||
|
||||
friend class TProgram;
|
||||
|
||||
private:
|
||||
|
@ -65,6 +65,7 @@ std::string FileNameAsCustomTestSuffixIoMap(
|
||||
}
|
||||
|
||||
using CompileVulkanToSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
|
||||
using CompileVulkanToSpirvTestNoLink = GlslangTest<::testing::TestWithParam<std::string>>;
|
||||
using CompileVulkanToSpirvDeadCodeElimTest = GlslangTest<::testing::TestWithParam<std::string>>;
|
||||
using CompileVulkanToDebugSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
|
||||
using CompileVulkan1_1ToSpirvTest = GlslangTest<::testing::TestWithParam<std::string>>;
|
||||
@ -92,6 +93,16 @@ TEST_P(CompileVulkanToSpirvTest, FromFile)
|
||||
Target::Spv);
|
||||
}
|
||||
|
||||
// Compiling GLSL to SPIR-V under Vulkan semantics without linking. Expected to successfully generate SPIR-V.
|
||||
TEST_P(CompileVulkanToSpirvTestNoLink, FromFile)
|
||||
{
|
||||
options().compileOnly = true;
|
||||
// NOTE: Vulkan 1.3 is currently required to use the linkage capability
|
||||
// TODO(ncesario) make sure this is actually necessary
|
||||
loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), Source::GLSL, Semantics::Vulkan,
|
||||
glslang::EShTargetVulkan_1_3, glslang::EShTargetSpv_1_0, Target::Spv);
|
||||
}
|
||||
|
||||
TEST_P(CompileVulkanToSpirvDeadCodeElimTest, FromFile)
|
||||
{
|
||||
loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(),
|
||||
@ -534,6 +545,14 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
FileNameAsCustomTestSuffix
|
||||
);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Glsl, CompileVulkanToSpirvTestNoLink,
|
||||
::testing::ValuesIn(std::vector<std::string>({
|
||||
"spv.exportFunctions.comp",
|
||||
})),
|
||||
FileNameAsCustomTestSuffix
|
||||
);
|
||||
|
||||
// Cases with deliberately unreachable code.
|
||||
// By default the compiler will aggressively eliminate
|
||||
// unreachable merges and continues.
|
||||
|
@ -248,36 +248,58 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (options().compileOnly)
|
||||
shader.setCompileOnly();
|
||||
|
||||
bool success = compile(
|
||||
&shader, code, entryPointName, controls, nullptr, &shaderName);
|
||||
|
||||
glslang::TProgram program;
|
||||
program.addShader(&shader);
|
||||
success &= program.link(controls);
|
||||
if (success)
|
||||
program.mapIO();
|
||||
spv::SpvBuildLogger logger;
|
||||
std::vector<uint32_t> spirv_binary;
|
||||
|
||||
if (success && (controls & EShMsgSpvRules)) {
|
||||
spv::SpvBuildLogger logger;
|
||||
std::vector<uint32_t> spirv_binary;
|
||||
if (!options().compileOnly) {
|
||||
program.addShader(&shader);
|
||||
success &= program.link(controls);
|
||||
if (success)
|
||||
program.mapIO();
|
||||
|
||||
if (success && (controls & EShMsgSpvRules)) {
|
||||
options().disableOptimizer = !enableOptimizer;
|
||||
options().generateDebugInfo = enableDebug;
|
||||
options().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo;
|
||||
options().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo;
|
||||
glslang::GlslangToSpv(*program.getIntermediate(stage), spirv_binary, &logger, &options());
|
||||
} else {
|
||||
return {{
|
||||
{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},
|
||||
},
|
||||
program.getInfoLog(),
|
||||
program.getInfoDebugLog(),
|
||||
true,
|
||||
"",
|
||||
""};
|
||||
}
|
||||
} else {
|
||||
options().disableOptimizer = !enableOptimizer;
|
||||
options().generateDebugInfo = enableDebug;
|
||||
options().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo;
|
||||
options().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo;
|
||||
glslang::GlslangToSpv(*program.getIntermediate(stage),
|
||||
spirv_binary, &logger, &options());
|
||||
|
||||
std::ostringstream disassembly_stream;
|
||||
spv::Parameterize();
|
||||
spv::Disassemble(disassembly_stream, spirv_binary);
|
||||
bool validation_result = !options().validate || logger.getAllMessages().empty();
|
||||
return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
|
||||
program.getInfoLog(), program.getInfoDebugLog(),
|
||||
validation_result, logger.getAllMessages(), disassembly_stream.str()};
|
||||
} else {
|
||||
return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
|
||||
program.getInfoLog(), program.getInfoDebugLog(), true, "", ""};
|
||||
glslang::GlslangToSpv(*shader.getIntermediate(), spirv_binary, &logger, &options());
|
||||
}
|
||||
|
||||
std::ostringstream disassembly_stream;
|
||||
spv::Parameterize();
|
||||
spv::Disassemble(disassembly_stream, spirv_binary);
|
||||
bool validation_result = !options().validate || logger.getAllMessages().empty();
|
||||
return {{
|
||||
{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},
|
||||
},
|
||||
program.getInfoLog(),
|
||||
program.getInfoDebugLog(),
|
||||
validation_result,
|
||||
logger.getAllMessages(),
|
||||
disassembly_stream.str()};
|
||||
}
|
||||
|
||||
// Compiles and links the given source |code| of the given shader
|
||||
|
Loading…
Reference in New Issue
Block a user