HLSL: use HLSL parser to parse HLSL intrinsic prototypes, enable int/bool mats

This PR adds a CreateParseContext() fn analogous to CreateBuiltInParseables(),
to create a language specific built in parser.  (This code was present before
but not encapsualted in a fn).  This can now be used to create a source language
specific parser for builtins.

Along with this, the code creating HLSL intrinsic prototypes can now produce
them in HLSL syntax, rather than GLSL syntax.  This relaxes certain prior
restrictions at the parser level.  Lower layers (e.g, SPIR-V) may still have
such restrictions, such as around Nx1 matrices: this code does not impact
that.

This PR also fleshes out matrix types for bools and ints, both of which were
partially in place before.  This was easier than maintaining the restrictions
in the HLSL prototype generator to avoid creating protoypes with those types.

Many tests change because the result type from intrinsics moves from "global"
to "temp".

Several new tests are added for the new types.
This commit is contained in:
steve-lunarg 2016-11-15 10:11:04 -07:00
parent fabe7d6a61
commit 0842dbb39a
43 changed files with 3729 additions and 2033 deletions

View file

@ -81,6 +81,28 @@ TBuiltInParseables* CreateBuiltInParseables(TInfoSink& infoSink, EShSource sourc
}
}
// Create a language specific version of a parse context.
TParseContextBase* CreateParseContext(TSymbolTable& symbolTable, TIntermediate& intermediate,
int version, EProfile profile, EShSource source,
EShLanguage language, TInfoSink& infoSink,
SpvVersion spvVersion, bool forwardCompatible, EShMessages messages,
bool parsingBuiltIns)
{
switch (source) {
case EShSourceGlsl:
intermediate.setEntryPointName("main");
return new TParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
language, infoSink, forwardCompatible, messages);
case EShSourceHlsl:
return new HlslParseContext(symbolTable, intermediate, parsingBuiltIns, version, profile, spvVersion,
language, infoSink, forwardCompatible, messages);
default:
infoSink.info.message(EPrefixInternalError, "Unable to determine source language");
return nullptr;
}
}
// Local mapping functions for making arrays of symbol tables....
const int VersionCount = 15; // index range in MapVersionToIndex
@ -188,17 +210,22 @@ TPoolAllocator* PerProcessGPA = 0;
//
// Parse and add to the given symbol table the content of the given shader string.
//
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink,
TSymbolTable& symbolTable)
bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
EShSource source, TInfoSink& infoSink, TSymbolTable& symbolTable)
{
TIntermediate intermediate(language, version, profile);
TParseContext parseContext(symbolTable, intermediate, true, version, profile, spvVersion, language, infoSink);
intermediate.setSource(source);
std::unique_ptr<TParseContextBase> parseContext(CreateParseContext(symbolTable, intermediate, version, profile, source,
language, infoSink, spvVersion, true, EShMsgDefault,
true));
TShader::ForbidInclude includer;
TPpContext ppContext(parseContext, "", includer);
TScanContext scanContext(parseContext);
parseContext.setScanContext(&scanContext);
parseContext.setPpContext(&ppContext);
TPpContext ppContext(*parseContext, "", includer);
TScanContext scanContext(*parseContext);
parseContext->setScanContext(&scanContext);
parseContext->setPpContext(&ppContext);
//
// Push the symbol table to give it an initial scope. This
@ -217,7 +244,7 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
return true;
TInputScanner input(1, builtInShaders, builtInLengths);
if (! parseContext.parseShaderStrings(ppContext, input) != 0) {
if (! parseContext->parseShaderStrings(ppContext, input) != 0) {
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
printf("Unable to parse built-ins\n%s\n", infoSink.info.c_str());
printf("%s\n", builtInShaders[0]);
@ -237,10 +264,12 @@ int CommonIndex(EProfile profile, EShLanguage language)
// To initialize per-stage shared tables, with the common table already complete.
//
void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int version, EProfile profile, const SpvVersion& spvVersion,
EShLanguage language, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables)
EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable,
TSymbolTable** symbolTables)
{
(*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]);
InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, infoSink, *symbolTables[language]);
InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source,
infoSink, *symbolTables[language]);
builtInParseables.identifyBuiltIns(version, profile, spvVersion, language, *symbolTables[language]);
if (profile == EEsProfile && version >= 300)
(*symbolTables[language]).setNoBuiltInRedeclarations();
@ -259,32 +288,40 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS
builtInParseables->initialize(version, profile, spvVersion);
// do the common tables
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, infoSink, *commonTable[EPcGeneral]);
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangVertex, source,
infoSink, *commonTable[EPcGeneral]);
if (profile == EEsProfile)
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, infoSink, *commonTable[EPcFragment]);
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, EShLangFragment, source,
infoSink, *commonTable[EPcFragment]);
// do the per-stage tables
// always have vertex and fragment
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangVertex, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source,
infoSink, commonTable, symbolTables);
// check for tessellation
if ((profile != EEsProfile && version >= 150) ||
(profile == EEsProfile && version >= 310)) {
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessControl, source,
infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTessEvaluation, source,
infoSink, commonTable, symbolTables);
}
// check for geometry
if ((profile != EEsProfile && version >= 150) ||
(profile == EEsProfile && version >= 310))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangGeometry, source,
infoSink, commonTable, symbolTables);
// check for compute
if ((profile != EEsProfile && version >= 420) ||
(profile == EEsProfile && version >= 310))
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, infoSink, commonTable, symbolTables);
InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source,
infoSink, commonTable, symbolTables);
return true;
}
@ -295,7 +332,7 @@ bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& inf
std::unique_ptr<TBuiltInParseables> builtInParseables(CreateBuiltInParseables(infoSink, source));
builtInParseables->initialize(*resources, version, profile, spvVersion, language);
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, infoSink, symbolTable);
InitializeSymbolTable(builtInParseables->getCommonString(), version, profile, spvVersion, language, source, infoSink, symbolTable);
builtInParseables->identifyBuiltIns(version, profile, spvVersion, language, symbolTable, *resources);
return true;
@ -694,15 +731,10 @@ bool ProcessDeferred(
// Now we can process the full shader under proper symbols and rules.
//
TParseContextBase* parseContext;
if (source == EShSourceHlsl) {
parseContext = new HlslParseContext(symbolTable, intermediate, false, version, profile, spvVersion,
compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
} else {
intermediate.setEntryPointName("main");
parseContext = new TParseContext(symbolTable, intermediate, false, version, profile, spvVersion,
compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
}
TParseContextBase* parseContext = CreateParseContext(symbolTable, intermediate, version, profile, source,
compiler->getLanguage(), compiler->infoSink,
spvVersion, forwardCompatible, messages, false);
TPpContext ppContext(*parseContext, names[numPre]? names[numPre]: "", includer);
// only GLSL (bison triggered, really) needs an externally set scan context
@ -940,7 +972,7 @@ struct DoPreprocessing {
struct DoFullParse{
bool operator()(TParseContextBase& parseContext, TPpContext& ppContext,
TInputScanner& fullInput, bool versionWillBeError,
TSymbolTable& symbolTable, TIntermediate& intermediate,
TSymbolTable&, TIntermediate& intermediate,
EShOptimizationLevel optLevel, EShMessages messages)
{
bool success = true;