SPV reflection: Add OpModuleProcessed for compile options.

This commit is contained in:
John Kessenich 2017-07-20 20:00:36 -06:00
parent 3d1b709676
commit 2a27116cae
11 changed files with 336 additions and 40 deletions

View File

@ -880,11 +880,30 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
builder.clearAccessChain();
builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
glslangIntermediate->getVersion());
if (options.generateDebugInfo) {
builder.setSourceFile(glslangIntermediate->getSourceFile());
builder.setSourceText(glslangIntermediate->getSourceText());
builder.setEmitOpLines();
builder.setSourceFile(glslangIntermediate->getSourceFile());
// Set the source shader's text. If for SPV version 1.0, include
// a preamble in comments stating the OpModuleProcessed instructions.
// Otherwise, emit those as actual instructions.
std::string text;
const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
for (int p = 0; p < (int)processes.size(); ++p) {
if (glslangIntermediate->getSpv().spv < 0x00010100) {
text.append("// OpModuleProcessed ");
text.append(processes[p]);
text.append("\n");
} else
builder.addModuleProcessed(processes[p]);
}
if (glslangIntermediate->getSpv().spv < 0x00010100 && (int)processes.size() > 0)
text.append("#line 1\n");
text.append(glslangIntermediate->getSourceText());
builder.setSourceText(text);
}
stdBuiltins = builder.import("GLSL.std.450");
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);

View File

@ -2430,6 +2430,7 @@ void Builder::dump(std::vector<unsigned int>& out) const
// Debug instructions
dumpInstructions(out, strings);
dumpModuleProcesses(out);
dumpSourceInstructions(out);
for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
Instruction sourceExtInst(0, 0, OpSourceExtension);
@ -2637,4 +2638,15 @@ void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector
}
}
void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
{
for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
// TODO: switch this out for the 1.1 headers
const spv::Op OpModuleProcessed = (spv::Op)330;
Instruction moduleProcessed(OpModuleProcessed);
moduleProcessed.addStringOperand(moduleProcesses[i]);
moduleProcessed.dump(out);
}
}
}; // end spv namespace

View File

@ -79,6 +79,7 @@ public:
}
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 addExtension(const char* ext) { extensions.insert(ext); }
Id import(const char*);
@ -582,6 +583,7 @@ public:
void createSelectionMerge(Block* mergeBlock, unsigned int control);
void dumpSourceInstructions(std::vector<unsigned int>&) const;
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
void dumpModuleProcesses(std::vector<unsigned int>&) const;
SourceLanguage source;
int sourceVersion;
@ -591,6 +593,7 @@ public:
bool emitOpLines;
std::set<std::string> extensions;
std::vector<const char*> sourceExtensions;
std::vector<const char*> moduleProcesses;
AddressingModel addressModel;
MemoryModel memoryModel;
std::set<spv::Capability> capabilities;

View File

@ -152,6 +152,7 @@ int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
int VulkanClientVersion = 100; // would map to, say, Vulkan 1.0
int OpenGLClientVersion = 450; // doesn't influence anything yet, but maps to OpenGL 4.50
unsigned int TargetVersion = 0x00001000; // maps to, say, SPIR-V 1.0
std::vector<std::string> Processes; // what should be recorded by OpModuleProcessed, or equivalent
std::array<unsigned int, EShLangCount> baseSamplerBinding;
std::array<unsigned int, EShLangCount> baseTextureBinding;
@ -175,6 +176,9 @@ public:
text.append("#define ");
fixLine(def);
Processes.push_back("D");
Processes.back().append(def);
// The first "=" needs to turn into a space
const size_t equal = def.find_first_of("=");
if (equal != def.npos)
@ -189,6 +193,10 @@ public:
{
text.append("#undef ");
fixLine(undef);
Processes.push_back("U");
Processes.back().append(undef);
text.append(undef);
text.append("\n");
}
@ -421,6 +429,8 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
} else if (lowerword == "no-storage-format" || // synonyms
lowerword == "nsf") {
Options |= EOptionNoStorageFormat;
} else if (lowerword == "relaxed-errors") {
Options |= EOptionRelaxedErrors;
} else if (lowerword == "resource-set-bindings" || // synonyms
lowerword == "resource-set-binding" ||
lowerword == "rsb") {
@ -459,6 +469,8 @@ void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItem
sourceEntryPointName = argv[1];
bumpArg();
break;
} else if (lowerword == "suppress-warnings") {
Options |= EOptionSuppressWarnings;
} else if (lowerword == "target-env") {
if (argc > 1) {
if (strcmp(argv[1], "vulkan1.0") == 0) {
@ -737,6 +749,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
shader->setSourceEntryPoint(sourceEntryPointName);
if (UserPreamble.isSet())
shader->setPreamble(UserPreamble.get());
shader->addProcesses(Processes);
shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
@ -1162,11 +1175,11 @@ void usage()
" -m memory leak mode\n"
" -o <file> save binary to <file>, requires a binary option (e.g., -V)\n"
" -q dump reflection query database\n"
" -r relaxed semantic error-checking mode\n"
" -r synonym for --relaxed-errors\n"
" -s silent mode\n"
" -t multi-threaded mode\n"
" -v print version strings\n"
" -w suppress warnings (except as required by #extension : warn)\n"
" -w synonym for --suppress-warnings\n"
" -x save binary output as text-based 32-bit hexadecimal numbers\n"
" --auto-map-bindings automatically bind uniform variables\n"
" without explicit bindings.\n"
@ -1185,6 +1198,7 @@ void usage()
" --ku synonym for --keep-uncalled\n"
" --no-storage-format use Unknown image format\n"
" --nsf synonym for --no-storage-format\n"
" --relaxed-errors relaxed GLSL semantic error-checking mode\n"
" --resource-set-binding [stage] name set binding\n"
" Set descriptor set and binding for individual resources\n"
" --resource-set-binding [stage] set\n"
@ -1206,11 +1220,13 @@ void usage()
" --source-entrypoint name the given shader source function is\n"
" renamed to be the entry point given in -e\n"
" --sep synonym for --source-entrypoint\n"
" --target-env {vulkan1.0|opengl} set the execution environment the generated\n"
" code will execute in (as opposed to language\n"
" semantics selected by --client)\n"
" default is 'vulkan1.0' under '--client vulkan'\n"
" default is 'opengl' under '--client opengl'\n"
" --suppress-warnings suppress GLSL warnings\n"
" (except as required by #extension : warn)\n"
" --target-env {vulkan1.0|opengl} set the execution environment code will\n"
" execute in (as opposed to language\n"
" semantics selected by --client) defaults:\n"
" 'vulkan1.0' under '--client vulkan<ver>'\n"
" 'opengl' under '--client opengl<ver>'\n"
" --variable-name <name> Creates a C header file that contains a\n"
" uint32_t array named <name>\n"
" initialized with the shader binary code.\n"

View File

@ -7,9 +7,19 @@ spv.debugInfo.frag
2: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Fragment 5 "main" 24 52
ExecutionMode 5 OriginUpperLeft
ExecutionMode 5 OriginLowerLeft
1: String "spv.debugInfo.frag"
Source GLSL 450 1 "#version 450
Source GLSL 450 1 "// OpModuleProcessed no-storage-format
// OpModuleProcessed resource-set-binding 3
// OpModuleProcessed auto-map-locations
// OpModuleProcessed client opengl100
// OpModuleProcessed target-env opengl
// OpModuleProcessed relaxed-errors
// OpModuleProcessed suppress-warnings
// OpModuleProcessed hlsl-offsets
// OpModuleProcessed entry-point main
#line 1
#version 450
struct S {
int a;
@ -84,8 +94,8 @@ void main()
MemberDecorate 53(S) 0 Offset 0
MemberDecorate 54(ubuf) 0 Offset 0
Decorate 54(ubuf) Block
Decorate 56 DescriptorSet 0
Decorate 69(s2d) DescriptorSet 0
Decorate 56 DescriptorSet 3
Decorate 69(s2d) DescriptorSet 3
3: TypeVoid
4: TypeFunction 3
7: TypeInt 32 1

View File

@ -0,0 +1,58 @@
spv.hlslDebugInfo.vert
// Module Version 10000
// Generated by (magic number): 80001
// Id's are bound by 19
Capability Shader
2: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
EntryPoint Vertex 5 "newMain" 17
1: String "spv.hlslDebugInfo.vert"
Source HLSL 500 1 "// OpModuleProcessed entry-point newMain
// OpModuleProcessed shift-sampler-binding 2
// OpModuleProcessed shift-texture-binding 4
// OpModuleProcessed shift-image-binding 1
// OpModuleProcessed shift-UBO-binding 6
// OpModuleProcessed shift-ssbo-binding 3
// OpModuleProcessed shift-uav-binding 5
// OpModuleProcessed flatten-uniform-arrays
// OpModuleProcessed no-storage-format
// OpModuleProcessed resource-set-binding t0 0 0
// OpModuleProcessed hlsl-iomap
// OpModuleProcessed auto-map-bindings
// OpModuleProcessed auto-map-locations
// OpModuleProcessed client vulkan100
// OpModuleProcessed target-env vulkan1.0
// OpModuleProcessed source-entrypoint origMain
// OpModuleProcessed hlsl-offsets
#line 1
float4 origMain() : SV_Position
{
return (float4)0;
}
"
Name 5 "newMain"
Name 10 "@newMain("
Name 17 "@entryPointOutput"
Decorate 17(@entryPointOutput) BuiltIn Position
3: TypeVoid
4: TypeFunction 3
7: TypeFloat 32
8: TypeVector 7(float) 4
9: TypeFunction 8(fvec4)
12: 7(float) Constant 0
13: 8(fvec4) ConstantComposite 12 12 12 12
16: TypePointer Output 8(fvec4)
17(@entryPointOutput): 16(ptr) Variable Output
5(newMain): 3 Function None 4
6: Label
Line 1 2 0
18: 8(fvec4) FunctionCall 10(@newMain()
Store 17(@entryPointOutput) 18
Return
FunctionEnd
10(@newMain(): 8(fvec4) Function None 9
11: Label
Line 1 3 0
ReturnValue 13
FunctionEnd

View File

@ -116,8 +116,12 @@ diff -b $BASEDIR/spv.noBuiltInLoc.vert.out $TARGETDIR/spv.noBuiltInLoc.vert.out
# Testing debug information
#
echo Testing SPV Debug Information
$EXE -g -H spv.debugInfo.frag > $TARGETDIR/spv.debugInfo.frag.out
$EXE -g --relaxed-errors --suppress-warnings --aml --hlsl-offsets --nsf \
-G -H spv.debugInfo.frag --rsb frag 3 > $TARGETDIR/spv.debugInfo.frag.out
diff -b $BASEDIR/spv.debugInfo.frag.out $TARGETDIR/spv.debugInfo.frag.out || HASERROR=1
$EXE -g -D -e newMain -g --amb --aml --fua --hlsl-iomap --nsf --sib 1 --ssb 2 --sbb 3 --stb 4 --suavb 5 --sub 6 \
--sep origMain -H spv.hlslDebugInfo.vert --rsb vert t0 0 0 > $TARGETDIR/spv.hlslDebugInfo.frag.out
diff -b $BASEDIR/spv.hlslDebugInfo.frag.out $TARGETDIR/spv.hlslDebugInfo.frag.out || HASERROR=1
#
# Testing Includer

View File

@ -0,0 +1,4 @@
float4 origMain() : SV_Position
{
return (float4)0;
}

View File

@ -675,6 +675,22 @@ void TranslateEnvironment(const TEnvironment* environment, EShMessages& messages
}
}
// Most processes are recorded when set in the intermediate representation,
// These are the few that are not.
void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName)
{
if ((messages & EShMsgRelaxedErrors) != 0)
intermediate.addProcess("relaxed-errors");
if ((messages & EShMsgSuppressWarnings) != 0)
intermediate.addProcess("suppress-warnings");
if ((messages & EShMsgKeepUncalled) != 0)
intermediate.addProcess("keep-uncalled");
if (sourceEntryPointName.size() > 0) {
intermediate.addProcess("source-entrypoint");
intermediate.addProcessArgument(sourceEntryPointName);
}
}
// This is the common setup and cleanup code for PreprocessDeferred and
// CompileDeferred.
// It takes any callable with a signature of
@ -798,6 +814,7 @@ bool ProcessDeferred(
intermediate.setVersion(version);
intermediate.setProfile(profile);
intermediate.setSpv(spvVersion);
RecordProcesses(intermediate, messages, sourceEntryPointName);
if (spvVersion.vulkan >= 100)
intermediate.setOriginUpperLeft();
if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
@ -1641,6 +1658,11 @@ void TShader::setSourceEntryPoint(const char* name)
sourceEntryPointName = name;
}
void TShader::addProcesses(const std::vector<std::string>& p)
{
intermediate->addProcesses(p);
}
// Set binding base for sampler types
void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
// Set binding base for texture types (SRV)
@ -1658,7 +1680,7 @@ void TShader::setShiftSsboBinding(unsigned int base) { intermediate->setShift
// Enables binding automapping using TIoMapper
void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
// Fragile: currently within one stage: simple auto-assignment of location
void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); }
void TShader::setAutoMapLocations(bool map) { intermediate->setAutoMapLocations(map); }
// See comment above TDefaultHlslIoMapper in iomapper.cpp:
void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslIoMapping(hlslIoMap); }
void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }

View File

@ -150,6 +150,54 @@ struct TXfbBuffer {
bool containsDouble;
};
// Track a set of strings describing how the module was processed.
// Using the form:
// process arg0 arg1 arg2 ...
// process arg0 arg1 arg2 ...
// where everything is textual, and there can be zero or more arguments
class TProcesses {
public:
TProcesses() {}
~TProcesses() {}
void addProcess(const char* process)
{
processes.push_back(process);
}
void addProcess(const std::string& process)
{
processes.push_back(process);
}
void addArgument(int arg)
{
processes.back().append(" ");
std::string argString = std::to_string(arg);
processes.back().append(argString);
}
void addArgument(const char* arg)
{
processes.back().append(" ");
processes.back().append(arg);
}
void addArgument(const std::string& arg)
{
processes.back().append(" ");
processes.back().append(arg);
}
void addIfNonZero(const char* process, int value)
{
if (value != 0) {
addProcess(process);
addArgument(value);
}
}
const std::vector<std::string>& getProcesses() const { return processes; }
private:
std::vector<std::string> processes;
};
class TSymbolTable;
class TSymbol;
class TVariable;
@ -201,46 +249,135 @@ public:
void setSource(EShSource s) { source = s; }
EShSource getSource() const { return source; }
void setEntryPointName(const char* ep) { entryPointName = ep; }
void setEntryPointName(const char* ep)
{
entryPointName = ep;
processes.addProcess("entry-point");
processes.addArgument(entryPointName);
}
void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
const std::string& getEntryPointName() const { return entryPointName; }
const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
void setShiftSamplerBinding(unsigned int shift) { shiftSamplerBinding = shift; }
void setShiftSamplerBinding(unsigned int shift)
{
shiftSamplerBinding = shift;
processes.addIfNonZero("shift-sampler-binding", shift);
}
unsigned int getShiftSamplerBinding() const { return shiftSamplerBinding; }
void setShiftTextureBinding(unsigned int shift) { shiftTextureBinding = shift; }
void setShiftTextureBinding(unsigned int shift)
{
shiftTextureBinding = shift;
processes.addIfNonZero("shift-texture-binding", shift);
}
unsigned int getShiftTextureBinding() const { return shiftTextureBinding; }
void setShiftImageBinding(unsigned int shift) { shiftImageBinding = shift; }
void setShiftImageBinding(unsigned int shift)
{
shiftImageBinding = shift;
processes.addIfNonZero("shift-image-binding", shift);
}
unsigned int getShiftImageBinding() const { return shiftImageBinding; }
void setShiftUboBinding(unsigned int shift) { shiftUboBinding = shift; }
unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setShiftSsboBinding(unsigned int shift) { shiftSsboBinding = shift; }
unsigned int getShiftSsboBinding() const { return shiftSsboBinding; }
void setShiftUavBinding(unsigned int shift) { shiftUavBinding = shift; }
unsigned int getShiftUavBinding() const { return shiftUavBinding; }
void setResourceSetBinding(const std::vector<std::string>& shift) { resourceSetBinding = shift; }
void setShiftUboBinding(unsigned int shift)
{
shiftUboBinding = shift;
processes.addIfNonZero("shift-UBO-binding", shift);
}
unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setShiftSsboBinding(unsigned int shift)
{
shiftSsboBinding = shift;
processes.addIfNonZero("shift-ssbo-binding", shift);
}
unsigned int getShiftSsboBinding() const { return shiftSsboBinding; }
void setShiftUavBinding(unsigned int shift)
{
shiftUavBinding = shift;
processes.addIfNonZero("shift-uav-binding", shift);
}
unsigned int getShiftUavBinding() const { return shiftUavBinding; }
void setResourceSetBinding(const std::vector<std::string>& shift)
{
resourceSetBinding = shift;
if (shift.size() > 0) {
processes.addProcess("resource-set-binding");
for (int s = 0; s < (int)shift.size(); ++s)
processes.addArgument(shift[s]);
}
}
const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; }
void setAutoMapLocations(bool map) { autoMapLocations = map; }
bool getAutoMapLocations() const { return autoMapLocations; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setNoStorageFormat(bool b) { useUnknownFormat = b; }
bool getNoStorageFormat() const { return useUnknownFormat; }
void setHlslOffsets() { hlslOffsets = true; }
void setAutoMapBindings(bool map)
{
autoMapBindings = map;
if (autoMapBindings)
processes.addProcess("auto-map-bindings");
}
bool getAutoMapBindings() const { return autoMapBindings; }
void setAutoMapLocations(bool map)
{
autoMapLocations = map;
if (autoMapLocations)
processes.addProcess("auto-map-locations");
}
bool getAutoMapLocations() const { return autoMapLocations; }
void setFlattenUniformArrays(bool flatten)
{
flattenUniformArrays = flatten;
if (flattenUniformArrays)
processes.addProcess("flatten-uniform-arrays");
}
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setNoStorageFormat(bool b)
{
useUnknownFormat = b;
if (useUnknownFormat)
processes.addProcess("no-storage-format");
}
bool getNoStorageFormat() const { return useUnknownFormat; }
void setHlslOffsets()
{
hlslOffsets = true;
if (hlslOffsets)
processes.addProcess("hlsl-offsets");
}
bool usingHlslOFfsets() const { return hlslOffsets; }
void setUseStorageBuffer() { useStorageBuffer = true; }
void setUseStorageBuffer()
{
useStorageBuffer = true;
processes.addProcess("use-storage-buffer");
}
bool usingStorageBuffer() const { return useStorageBuffer; }
void setHlslIoMapping(bool b) { hlslIoMapping = b; }
bool usingHlslIoMapping() { return hlslIoMapping; }
void setHlslIoMapping(bool b)
{
hlslIoMapping = b;
if (hlslIoMapping)
processes.addProcess("hlsl-iomap");
}
bool usingHlslIoMapping() { return hlslIoMapping; }
void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
void setVersion(int v) { version = v; }
int getVersion() const { return version; }
void setProfile(EProfile p) { profile = p; }
EProfile getProfile() const { return profile; }
void setSpv(const SpvVersion& s) { spvVersion = s; }
void setSpv(const SpvVersion& s)
{
spvVersion = s;
// client processes
if (spvVersion.vulkan > 0)
processes.addProcess("client vulkan100");
if (spvVersion.openGl > 0)
processes.addProcess("client opengl100");
// target-environment processes
if (spvVersion.vulkan == 100)
processes.addProcess("target-env vulkan1.0");
else if (spvVersion.vulkan > 0)
processes.addProcess("target-env vulkanUnknown");
if (spvVersion.openGl > 0)
processes.addProcess("target-env opengl");
}
const SpvVersion& getSpv() const { return spvVersion; }
EShLanguage getStage() const { return language; }
void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
@ -462,6 +599,13 @@ public:
const std::string& getSourceFile() const { return sourceFile; }
void addSourceText(const char* text) { sourceText = sourceText + text; }
const std::string& getSourceText() const { return sourceText; }
void addProcesses(const std::vector<std::string>& p) {
for (int i = 0; i < (int)p.size(); ++i)
processes.addProcess(p[i]);
}
void addProcess(const std::string& process) { processes.addProcess(process); }
void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
const char* const implicitThisName = "@this";
@ -558,6 +702,9 @@ protected:
std::string sourceFile;
std::string sourceText;
// for OpModuleProcessed, or equivalent
TProcesses processes;
private:
void operator=(TIntermediate&); // prevent assignments
};

View File

@ -346,6 +346,7 @@ public:
void setPreamble(const char* s) { preamble = s; }
void setEntryPoint(const char* entryPoint);
void setSourceEntryPoint(const char* sourceEntryPointName);
void addProcesses(const std::vector<std::string>&);
void setShiftSamplerBinding(unsigned int base);
void setShiftTextureBinding(unsigned int base);
void setShiftImageBinding(unsigned int base);