HLSL: Refactor attribute implementation.
- make it sharable with GLSL - correct the case insensitivity - remove the map; queries are not needed, all entries need processing - make it easier to build bottom up (will help GLSL parsing) - support semantic checking and reporting - allow front-end dependent semantics and attribute name mapping
This commit is contained in:
@@ -34,157 +34,73 @@
|
||||
//
|
||||
|
||||
#include "hlslAttributes.h"
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include "hlslParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
// Map the given string to an attribute enum from TAttributeType,
|
||||
// or EatNone if invalid.
|
||||
TAttributeType TAttributeMap::attributeFromName(const TString& nameSpace, const TString& name)
|
||||
TAttributeType HlslParseContext::attributeFromName(const TString& nameSpace, const TString& name) const
|
||||
{
|
||||
// These are case insensitive.
|
||||
TString lowername(name);
|
||||
std::transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
|
||||
TString lowernameSpace(nameSpace);
|
||||
std::transform(lowernameSpace.begin(), lowernameSpace.end(), lowernameSpace.begin(), ::tolower);
|
||||
|
||||
// handle names within a namespace
|
||||
|
||||
if (lowernameSpace == "vk") {
|
||||
if (lowername == "input_attachment_index")
|
||||
if (nameSpace == "vk") {
|
||||
if (name == "input_attachment_index")
|
||||
return EatInputAttachment;
|
||||
else if (lowername == "location")
|
||||
else if (name == "location")
|
||||
return EatLocation;
|
||||
else if (lowername == "binding")
|
||||
else if (name == "binding")
|
||||
return EatBinding;
|
||||
else if (lowername == "global_cbuffer_binding")
|
||||
else if (name == "global_cbuffer_binding")
|
||||
return EatGlobalBinding;
|
||||
else if (lowername == "builtin")
|
||||
else if (name == "builtin")
|
||||
return EatBuiltIn;
|
||||
else if (lowername == "constant_id")
|
||||
else if (name == "constant_id")
|
||||
return EatConstantId;
|
||||
else if (lowername == "push_constant")
|
||||
else if (name == "push_constant")
|
||||
return EatPushConstant;
|
||||
} else if (lowernameSpace.size() > 0)
|
||||
} else if (nameSpace.size() > 0)
|
||||
return EatNone;
|
||||
|
||||
// handle names with no namespace
|
||||
|
||||
if (lowername == "allow_uav_condition")
|
||||
if (name == "allow_uav_condition")
|
||||
return EatAllow_uav_condition;
|
||||
else if (lowername == "branch")
|
||||
else if (name == "branch")
|
||||
return EatBranch;
|
||||
else if (lowername == "call")
|
||||
else if (name == "call")
|
||||
return EatCall;
|
||||
else if (lowername == "domain")
|
||||
else if (name == "domain")
|
||||
return EatDomain;
|
||||
else if (lowername == "earlydepthstencil")
|
||||
else if (name == "earlydepthstencil")
|
||||
return EatEarlyDepthStencil;
|
||||
else if (lowername == "fastopt")
|
||||
else if (name == "fastopt")
|
||||
return EatFastOpt;
|
||||
else if (lowername == "flatten")
|
||||
else if (name == "flatten")
|
||||
return EatFlatten;
|
||||
else if (lowername == "forcecase")
|
||||
else if (name == "forcecase")
|
||||
return EatForceCase;
|
||||
else if (lowername == "instance")
|
||||
else if (name == "instance")
|
||||
return EatInstance;
|
||||
else if (lowername == "maxtessfactor")
|
||||
else if (name == "maxtessfactor")
|
||||
return EatMaxTessFactor;
|
||||
else if (lowername == "maxvertexcount")
|
||||
else if (name == "maxvertexcount")
|
||||
return EatMaxVertexCount;
|
||||
else if (lowername == "numthreads")
|
||||
else if (name == "numthreads")
|
||||
return EatNumThreads;
|
||||
else if (lowername == "outputcontrolpoints")
|
||||
else if (name == "outputcontrolpoints")
|
||||
return EatOutputControlPoints;
|
||||
else if (lowername == "outputtopology")
|
||||
else if (name == "outputtopology")
|
||||
return EatOutputTopology;
|
||||
else if (lowername == "partitioning")
|
||||
else if (name == "partitioning")
|
||||
return EatPartitioning;
|
||||
else if (lowername == "patchconstantfunc")
|
||||
else if (name == "patchconstantfunc")
|
||||
return EatPatchConstantFunc;
|
||||
else if (lowername == "unroll")
|
||||
else if (name == "unroll")
|
||||
return EatUnroll;
|
||||
else if (lowername == "loop")
|
||||
else if (name == "loop")
|
||||
return EatLoop;
|
||||
else
|
||||
return EatNone;
|
||||
}
|
||||
|
||||
// Look up entry, inserting if it's not there, and if name is a valid attribute name
|
||||
// as known by attributeFromName.
|
||||
TAttributeType TAttributeMap::setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value)
|
||||
{
|
||||
if (name == nullptr)
|
||||
return EatNone;
|
||||
|
||||
const TAttributeType attr = attributeFromName(nameSpace, *name);
|
||||
|
||||
if (attr != EatNone)
|
||||
attributes[attr] = value;
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
// Look up entry (const version), and return aggregate node. This cannot change the map.
|
||||
const TIntermAggregate* TAttributeMap::operator[](TAttributeType attr) const
|
||||
{
|
||||
const auto entry = attributes.find(attr);
|
||||
|
||||
return (entry == attributes.end()) ? nullptr : entry->second;
|
||||
}
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool TAttributeMap::contains(TAttributeType attr) const
|
||||
{
|
||||
return attributes.find(attr) != attributes.end();
|
||||
}
|
||||
|
||||
// extract integers out of attribute arguments stored in attribute aggregate
|
||||
bool TAttributeMap::getInt(TAttributeType attr, int& value, int argNum) const
|
||||
{
|
||||
const TConstUnion* intConst = getConstUnion(attr, EbtInt, argNum);
|
||||
|
||||
if (intConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = intConst->getIConst();
|
||||
return true;
|
||||
};
|
||||
|
||||
// extract strings out of attribute arguments stored in attribute aggregate.
|
||||
// convert to lower case if converToLower is true (for case-insensitive compare convenience)
|
||||
bool TAttributeMap::getString(TAttributeType attr, TString& value, int argNum, bool convertToLower) const
|
||||
{
|
||||
const TConstUnion* stringConst = getConstUnion(attr, EbtString, argNum);
|
||||
|
||||
if (stringConst == nullptr)
|
||||
return false;
|
||||
|
||||
value = *stringConst->getSConst();
|
||||
|
||||
// Convenience.
|
||||
if (convertToLower)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper to get attribute const union. Returns nullptr on failure.
|
||||
const TConstUnion* TAttributeMap::getConstUnion(TAttributeType attr, TBasicType basicType, int argNum) const
|
||||
{
|
||||
const TIntermAggregate* attrAgg = (*this)[attr];
|
||||
if (attrAgg == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (argNum >= int(attrAgg->getSequence().size()))
|
||||
return nullptr;
|
||||
|
||||
const TConstUnion* constVal = &attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
|
||||
if (constVal == nullptr || constVal->getType() != basicType)
|
||||
return nullptr;
|
||||
|
||||
return constVal;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
@@ -38,93 +38,22 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "../glslang/MachineIndependent/attribute.h"
|
||||
#include "../glslang/MachineIndependent/SymbolTable.h"
|
||||
#include "hlslScanContext.h"
|
||||
#include "../glslang/Include/Common.h"
|
||||
|
||||
namespace glslang {
|
||||
enum TAttributeType {
|
||||
EatNone,
|
||||
EatAllow_uav_condition,
|
||||
EatBranch,
|
||||
EatCall,
|
||||
EatDomain,
|
||||
EatEarlyDepthStencil,
|
||||
EatFastOpt,
|
||||
EatFlatten,
|
||||
EatForceCase,
|
||||
EatInstance,
|
||||
EatMaxTessFactor,
|
||||
EatNumThreads,
|
||||
EatMaxVertexCount,
|
||||
EatOutputControlPoints,
|
||||
EatOutputTopology,
|
||||
EatPartitioning,
|
||||
EatPatchConstantFunc,
|
||||
EatPatchSize,
|
||||
EatUnroll,
|
||||
EatLoop,
|
||||
EatBinding,
|
||||
EatGlobalBinding,
|
||||
EatLocation,
|
||||
EatInputAttachment,
|
||||
EatBuiltIn,
|
||||
EatPushConstant,
|
||||
EatConstantId
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
// Allow use of TAttributeType enum in hash_map without calling code having to cast.
|
||||
template <> struct hash<glslang::TAttributeType> {
|
||||
std::size_t operator()(glslang::TAttributeType attr) const {
|
||||
return std::hash<int>()(int(attr));
|
||||
}
|
||||
};
|
||||
} // end namespace std
|
||||
|
||||
namespace glslang {
|
||||
class TIntermAggregate;
|
||||
|
||||
class TAttributeMap {
|
||||
public:
|
||||
int size() const { return (int)attributes.size(); }
|
||||
|
||||
// Search for and potentially add the attribute into the map. Return the
|
||||
// attribute type enum for it, if found, else EatNone.
|
||||
TAttributeType setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value);
|
||||
|
||||
// Const lookup: search for (but do not modify) the attribute in the map.
|
||||
const TIntermAggregate* operator[](TAttributeType) const;
|
||||
|
||||
// True if entry exists in map (even if value is nullptr)
|
||||
bool contains(TAttributeType) const;
|
||||
|
||||
// Obtain attribute as integer
|
||||
bool getInt(TAttributeType attr, int& value, int argNum = 0) const;
|
||||
|
||||
// Obtain attribute as string, with optional to-lower transform
|
||||
bool getString(TAttributeType attr, TString& value, int argNum = 0, bool convertToLower = true) const;
|
||||
|
||||
protected:
|
||||
// Helper to get attribute const union
|
||||
const TConstUnion* getConstUnion(TAttributeType attr, TBasicType, int argNum) const;
|
||||
|
||||
// Find an attribute enum given its name.
|
||||
static TAttributeType attributeFromName(const TString& nameSpace, const TString& name);
|
||||
|
||||
std::unordered_map<TAttributeType, TIntermAggregate*> attributes;
|
||||
};
|
||||
|
||||
class TFunctionDeclarator {
|
||||
public:
|
||||
TFunctionDeclarator() : function(nullptr), body(nullptr) { }
|
||||
TSourceLoc loc;
|
||||
TFunction* function;
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
TVector<HlslToken>* body;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
|
||||
#endif // HLSLATTRIBUTES_H_
|
||||
|
||||
@@ -396,6 +396,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
if (peekTokenClass(EHTokLeftParen)) {
|
||||
// looks like function parameters
|
||||
|
||||
// merge in the attributes into the return type
|
||||
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true);
|
||||
|
||||
// Potentially rename shader entry point function. No-op most of the time.
|
||||
parseContext.renameShaderFunction(fullName);
|
||||
|
||||
@@ -423,7 +426,13 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
|
||||
}
|
||||
} else {
|
||||
// A variable declaration. Fix the storage qualifier if it's a global.
|
||||
// A variable declaration.
|
||||
|
||||
// merge in the attributes, the first time around, into the shared type
|
||||
if (! declarator_list)
|
||||
parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType);
|
||||
|
||||
// Fix the storage qualifier if it's a global.
|
||||
if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
|
||||
declaredType.getQualifier().storage = EvqUniform;
|
||||
|
||||
@@ -536,13 +545,16 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
|
||||
bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
|
||||
{
|
||||
node = nullptr;
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
|
||||
// fully_specified_type
|
||||
TType type;
|
||||
if (! acceptFullySpecifiedType(type, attributes))
|
||||
return false;
|
||||
|
||||
if (attributes.size() > 0)
|
||||
parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
|
||||
|
||||
// filter out type casts
|
||||
if (peekTokenClass(EHTokLeftParen)) {
|
||||
recedeToken();
|
||||
@@ -578,12 +590,12 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
|
||||
// : type_specifier
|
||||
// | type_qualifier type_specifier
|
||||
//
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes)
|
||||
{
|
||||
TIntermNode* nodeList = nullptr;
|
||||
return acceptFullySpecifiedType(type, nodeList, attributes);
|
||||
}
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributeMap& attributes, bool forbidDeclarators)
|
||||
bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators)
|
||||
{
|
||||
// type_qualifier
|
||||
TQualifier qualifier;
|
||||
@@ -608,7 +620,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
|
||||
parseContext.mergeQualifiers(type.getQualifier(), qualifier);
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(attributes, type);
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, type);
|
||||
|
||||
// further, it can create an anonymous instance of the block
|
||||
// (cbuffer and tbuffer don't consume the next identifier, and
|
||||
@@ -633,9 +645,6 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
|
||||
qualifier.builtIn = type.getQualifier().builtIn;
|
||||
|
||||
type.getQualifier() = qualifier;
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(attributes, type);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2335,7 +2344,7 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
|
||||
// struct_declaration
|
||||
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
bool declarator_list = false;
|
||||
@@ -2346,6 +2355,9 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
|
||||
expected("member type");
|
||||
return false;
|
||||
}
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, memberType);
|
||||
|
||||
// struct_declarator COMMA struct_declarator ...
|
||||
bool functionDefinitionAccepted = false;
|
||||
@@ -2542,7 +2554,7 @@ bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTy
|
||||
bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
|
||||
{
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
// fully_specified_type
|
||||
@@ -2550,6 +2562,9 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
|
||||
if (! acceptFullySpecifiedType(*type, attributes))
|
||||
return false;
|
||||
|
||||
// merge in the attributes
|
||||
parseContext.transferTypeAttributes(token.loc, attributes, *type);
|
||||
|
||||
// identifier
|
||||
HlslToken idToken;
|
||||
acceptIdentifier(idToken);
|
||||
@@ -3386,7 +3401,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
|
||||
statement = nullptr;
|
||||
|
||||
// attributes
|
||||
TAttributeMap attributes;
|
||||
TAttributes attributes;
|
||||
acceptAttributes(attributes);
|
||||
|
||||
// attributed_statement
|
||||
@@ -3458,7 +3473,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
|
||||
// | PATCHCONSTANTFUNC
|
||||
// | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
|
||||
//
|
||||
void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
void HlslGrammar::acceptAttributes(TAttributes& attributes)
|
||||
{
|
||||
// For now, accept the [ XXX(X) ] syntax, but drop all but
|
||||
// numthreads, which is used to set the CS local size.
|
||||
@@ -3529,9 +3544,16 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
return;
|
||||
}
|
||||
|
||||
// Add any values we found into the attribute map. This accepts
|
||||
// (and ignores) values not mapping to a known TAttributeType;
|
||||
attributes.setAttribute(nameSpace, attributeToken.string, expressions);
|
||||
// Add any values we found into the attribute map.
|
||||
if (attributeToken.string != nullptr) {
|
||||
TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string);
|
||||
if (attributeType == EatNone)
|
||||
parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), "");
|
||||
else {
|
||||
TAttributeArgs attributeArgs = { attributeType, expressions };
|
||||
attributes.push_back(attributeArgs);
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -3539,12 +3561,10 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
|
||||
// : IF LEFT_PAREN expression RIGHT_PAREN statement
|
||||
// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
|
||||
//
|
||||
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
TSourceLoc loc = token.loc;
|
||||
|
||||
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
|
||||
|
||||
// IF
|
||||
if (! acceptTokenClass(EHTokIf))
|
||||
return false;
|
||||
@@ -3582,7 +3602,9 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
|
||||
}
|
||||
|
||||
// Put the pieces together
|
||||
statement = intermediate.addSelection(condition, thenElse, loc, control);
|
||||
statement = intermediate.addSelection(condition, thenElse, loc);
|
||||
parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes);
|
||||
|
||||
parseContext.popScope();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
@@ -3592,13 +3614,11 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
|
||||
// switch_statement
|
||||
// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
|
||||
//
|
||||
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
// SWITCH
|
||||
TSourceLoc loc = token.loc;
|
||||
|
||||
const TSelectionControl control = parseContext.handleSelectionControl(attributes);
|
||||
|
||||
if (! acceptTokenClass(EHTokSwitch))
|
||||
return false;
|
||||
|
||||
@@ -3618,7 +3638,8 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
if (statementOkay)
|
||||
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, control);
|
||||
statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr,
|
||||
attributes);
|
||||
|
||||
parseContext.popSwitchSequence();
|
||||
parseContext.popScope();
|
||||
@@ -3632,7 +3653,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
|
||||
// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
|
||||
//
|
||||
// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
|
||||
bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
|
||||
{
|
||||
TSourceLoc loc = token.loc;
|
||||
TIntermTyped* condition = nullptr;
|
||||
@@ -3642,9 +3663,8 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
|
||||
// WHILE or DO or FOR
|
||||
advanceToken();
|
||||
|
||||
const TLoopControl control = parseContext.handleLoopControl(attributes);
|
||||
|
||||
TIntermLoop* loopNode = nullptr;
|
||||
switch (loop) {
|
||||
case EHTokWhile:
|
||||
// so that something declared in the condition is scoped to the lifetime
|
||||
@@ -3670,9 +3690,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
parseContext.popScope();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
|
||||
|
||||
return true;
|
||||
loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
|
||||
statement = loopNode;
|
||||
break;
|
||||
|
||||
case EHTokDo:
|
||||
parseContext.nestLooping(); // this only needs to work right if no errors
|
||||
@@ -3703,9 +3723,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
parseContext.unnestLooping();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
|
||||
|
||||
return true;
|
||||
loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
|
||||
statement = loopNode;
|
||||
break;
|
||||
|
||||
case EHTokFor:
|
||||
{
|
||||
@@ -3747,18 +3767,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
|
||||
return false;
|
||||
}
|
||||
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
|
||||
statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode);
|
||||
|
||||
parseContext.popScope();
|
||||
parseContext.unnestLooping();
|
||||
--parseContext.controlFlowNestingLevel;
|
||||
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
parseContext.handleLoopAttributes(loc, loopNode, attributes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// jump_statement
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TAttributeMap;
|
||||
class TFunctionDeclarator;
|
||||
|
||||
// Should just be the grammar aspect of HLSL.
|
||||
@@ -71,8 +70,8 @@ namespace glslang {
|
||||
bool acceptControlDeclaration(TIntermNode*& node);
|
||||
bool acceptSamplerDeclarationDX9(TType&);
|
||||
bool acceptSamplerState();
|
||||
bool acceptFullySpecifiedType(TType&, const TAttributeMap&);
|
||||
bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributeMap&, bool forbidDeclarators = false);
|
||||
bool acceptFullySpecifiedType(TType&, const TAttributes&);
|
||||
bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false);
|
||||
bool acceptQualifier(TQualifier&);
|
||||
bool acceptLayoutQualifierList(TQualifier&);
|
||||
bool acceptType(TType&);
|
||||
@@ -117,10 +116,10 @@ namespace glslang {
|
||||
bool acceptScopedCompoundStatement(TIntermNode*&);
|
||||
bool acceptStatement(TIntermNode*&);
|
||||
bool acceptNestedStatement(TIntermNode*&);
|
||||
void acceptAttributes(TAttributeMap&);
|
||||
bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&);
|
||||
bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&);
|
||||
bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
|
||||
void acceptAttributes(TAttributes&);
|
||||
bool acceptSelectionStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptSwitchStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptIterationStatement(TIntermNode*&, const TAttributes&);
|
||||
bool acceptJumpStatement(TIntermNode*&);
|
||||
bool acceptCaseLabel(TIntermNode*&);
|
||||
bool acceptDefaultLabel(TIntermNode*&);
|
||||
|
||||
@@ -1620,7 +1620,7 @@ void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc,
|
||||
// Returns an aggregate of parameter-symbol nodes.
|
||||
//
|
||||
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
|
||||
const TAttributeMap& attributes,
|
||||
const TAttributes& attributes,
|
||||
TIntermNode*& entryPointTree)
|
||||
{
|
||||
currentCaller = function.getMangledName();
|
||||
@@ -1717,189 +1717,217 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
|
||||
}
|
||||
|
||||
// Handle all [attrib] attribute for the shader entry point
|
||||
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes)
|
||||
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes)
|
||||
{
|
||||
// Handle entry-point function attributes
|
||||
const TIntermAggregate* numThreads = attributes[EatNumThreads];
|
||||
if (numThreads != nullptr) {
|
||||
const TIntermSequence& sequence = numThreads->getSequence();
|
||||
|
||||
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
||||
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
}
|
||||
|
||||
// MaxVertexCount
|
||||
if (attributes.contains(EatMaxVertexCount)) {
|
||||
int maxVertexCount;
|
||||
|
||||
if (! attributes.getInt(EatMaxVertexCount, maxVertexCount)) {
|
||||
error(loc, "invalid maxvertexcount", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(maxVertexCount))
|
||||
error(loc, "cannot change previously set maxvertexcount attribute", "", "");
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatNumThreads:
|
||||
{
|
||||
const TIntermSequence& sequence = it->args->getSequence();
|
||||
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
||||
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
||||
break;
|
||||
}
|
||||
}
|
||||
case EatMaxVertexCount:
|
||||
{
|
||||
int maxVertexCount;
|
||||
|
||||
// Handle [patchconstantfunction("...")]
|
||||
if (attributes.contains(EatPatchConstantFunc)) {
|
||||
TString pcfName;
|
||||
if (! attributes.getString(EatPatchConstantFunc, pcfName, 0, false)) {
|
||||
error(loc, "invalid patch constant function", "", "");
|
||||
} else {
|
||||
patchConstantFunctionName = pcfName;
|
||||
if (! it->getInt(maxVertexCount)) {
|
||||
error(loc, "invalid maxvertexcount", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(maxVertexCount))
|
||||
error(loc, "cannot change previously set maxvertexcount attribute", "", "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [domain("...")]
|
||||
if (attributes.contains(EatDomain)) {
|
||||
TString domainStr;
|
||||
if (! attributes.getString(EatDomain, domainStr)) {
|
||||
error(loc, "invalid domain", "", "");
|
||||
} else {
|
||||
TLayoutGeometry domain = ElgNone;
|
||||
|
||||
if (domainStr == "tri") {
|
||||
domain = ElgTriangles;
|
||||
} else if (domainStr == "quad") {
|
||||
domain = ElgQuads;
|
||||
} else if (domainStr == "isoline") {
|
||||
domain = ElgIsolines;
|
||||
case EatPatchConstantFunc:
|
||||
{
|
||||
TString pcfName;
|
||||
if (! it->getString(pcfName, 0, false)) {
|
||||
error(loc, "invalid patch constant function", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported domain type", domainStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (language == EShLangTessEvaluation) {
|
||||
if (! intermediate.setInputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
} else {
|
||||
if (! intermediate.setOutputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
patchConstantFunctionName = pcfName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [outputtopology("...")]
|
||||
if (attributes.contains(EatOutputTopology)) {
|
||||
TString topologyStr;
|
||||
if (! attributes.getString(EatOutputTopology, topologyStr)) {
|
||||
error(loc, "invalid outputtopology", "", "");
|
||||
} else {
|
||||
TVertexOrder vertexOrder = EvoNone;
|
||||
TLayoutGeometry primitive = ElgNone;
|
||||
|
||||
if (topologyStr == "point") {
|
||||
intermediate.setPointMode();
|
||||
} else if (topologyStr == "line") {
|
||||
primitive = ElgIsolines;
|
||||
} else if (topologyStr == "triangle_cw") {
|
||||
vertexOrder = EvoCw;
|
||||
primitive = ElgTriangles;
|
||||
} else if (topologyStr == "triangle_ccw") {
|
||||
vertexOrder = EvoCcw;
|
||||
primitive = ElgTriangles;
|
||||
case EatDomain:
|
||||
{
|
||||
// Handle [domain("...")]
|
||||
TString domainStr;
|
||||
if (! it->getString(domainStr)) {
|
||||
error(loc, "invalid domain", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
|
||||
}
|
||||
TLayoutGeometry domain = ElgNone;
|
||||
|
||||
if (vertexOrder != EvoNone) {
|
||||
if (! intermediate.setVertexOrder(vertexOrder)) {
|
||||
error(loc, "cannot change previously set outputtopology",
|
||||
TQualifier::getVertexOrderString(vertexOrder), "");
|
||||
if (domainStr == "tri") {
|
||||
domain = ElgTriangles;
|
||||
} else if (domainStr == "quad") {
|
||||
domain = ElgQuads;
|
||||
} else if (domainStr == "isoline") {
|
||||
domain = ElgIsolines;
|
||||
} else {
|
||||
error(loc, "unsupported domain type", domainStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (language == EShLangTessEvaluation) {
|
||||
if (! intermediate.setInputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
} else {
|
||||
if (! intermediate.setOutputPrimitive(domain))
|
||||
error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
|
||||
}
|
||||
}
|
||||
if (primitive != ElgNone)
|
||||
intermediate.setOutputPrimitive(primitive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle [partitioning("...")]
|
||||
if (attributes.contains(EatPartitioning)) {
|
||||
TString partitionStr;
|
||||
if (! attributes.getString(EatPartitioning, partitionStr)) {
|
||||
error(loc, "invalid partitioning", "", "");
|
||||
} else {
|
||||
TVertexSpacing partitioning = EvsNone;
|
||||
|
||||
if (partitionStr == "integer") {
|
||||
partitioning = EvsEqual;
|
||||
} else if (partitionStr == "fractional_even") {
|
||||
partitioning = EvsFractionalEven;
|
||||
} else if (partitionStr == "fractional_odd") {
|
||||
partitioning = EvsFractionalOdd;
|
||||
//} else if (partition == "pow2") { // TODO: currently nothing to map this to.
|
||||
case EatOutputTopology:
|
||||
{
|
||||
// Handle [outputtopology("...")]
|
||||
TString topologyStr;
|
||||
if (! it->getString(topologyStr)) {
|
||||
error(loc, "invalid outputtopology", "", "");
|
||||
} else {
|
||||
error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
|
||||
}
|
||||
TVertexOrder vertexOrder = EvoNone;
|
||||
TLayoutGeometry primitive = ElgNone;
|
||||
|
||||
if (! intermediate.setVertexSpacing(partitioning))
|
||||
error(loc, "cannot change previously set partitioning",
|
||||
TQualifier::getVertexSpacingString(partitioning), "");
|
||||
if (topologyStr == "point") {
|
||||
intermediate.setPointMode();
|
||||
} else if (topologyStr == "line") {
|
||||
primitive = ElgIsolines;
|
||||
} else if (topologyStr == "triangle_cw") {
|
||||
vertexOrder = EvoCw;
|
||||
primitive = ElgTriangles;
|
||||
} else if (topologyStr == "triangle_ccw") {
|
||||
vertexOrder = EvoCcw;
|
||||
primitive = ElgTriangles;
|
||||
} else {
|
||||
error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
|
||||
}
|
||||
|
||||
if (vertexOrder != EvoNone) {
|
||||
if (! intermediate.setVertexOrder(vertexOrder)) {
|
||||
error(loc, "cannot change previously set outputtopology",
|
||||
TQualifier::getVertexOrderString(vertexOrder), "");
|
||||
}
|
||||
}
|
||||
if (primitive != ElgNone)
|
||||
intermediate.setOutputPrimitive(primitive);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case EatPartitioning:
|
||||
{
|
||||
// Handle [partitioning("...")]
|
||||
TString partitionStr;
|
||||
if (! it->getString(partitionStr)) {
|
||||
error(loc, "invalid partitioning", "", "");
|
||||
} else {
|
||||
TVertexSpacing partitioning = EvsNone;
|
||||
|
||||
if (partitionStr == "integer") {
|
||||
partitioning = EvsEqual;
|
||||
} else if (partitionStr == "fractional_even") {
|
||||
partitioning = EvsFractionalEven;
|
||||
} else if (partitionStr == "fractional_odd") {
|
||||
partitioning = EvsFractionalOdd;
|
||||
//} else if (partition == "pow2") { // TODO: currently nothing to map this to.
|
||||
} else {
|
||||
error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
|
||||
}
|
||||
|
||||
// Handle [outputcontrolpoints("...")]
|
||||
if (attributes.contains(EatOutputControlPoints)) {
|
||||
int ctrlPoints;
|
||||
if (! attributes.getInt(EatOutputControlPoints, ctrlPoints)) {
|
||||
error(loc, "invalid outputcontrolpoints", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(ctrlPoints)) {
|
||||
error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
|
||||
if (! intermediate.setVertexSpacing(partitioning))
|
||||
error(loc, "cannot change previously set partitioning",
|
||||
TQualifier::getVertexSpacingString(partitioning), "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EatOutputControlPoints:
|
||||
{
|
||||
// Handle [outputcontrolpoints("...")]
|
||||
int ctrlPoints;
|
||||
if (! it->getInt(ctrlPoints)) {
|
||||
error(loc, "invalid outputcontrolpoints", "", "");
|
||||
} else {
|
||||
if (! intermediate.setVertices(ctrlPoints)) {
|
||||
error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EatBuiltIn:
|
||||
case EatLocation:
|
||||
// tolerate these because of dual use of entrypoint and type attributes
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to entry point", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the given type with any type-like attribute information in the
|
||||
// attributes.
|
||||
void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, TType& type)
|
||||
void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type,
|
||||
bool allowEntry)
|
||||
{
|
||||
if (attributes.size() == 0)
|
||||
return;
|
||||
|
||||
// location
|
||||
int value;
|
||||
if (attributes.getInt(EatLocation, value))
|
||||
type.getQualifier().layoutLocation = value;
|
||||
|
||||
// binding
|
||||
if (attributes.getInt(EatBinding, value)) {
|
||||
type.getQualifier().layoutBinding = value;
|
||||
type.getQualifier().layoutSet = 0;
|
||||
}
|
||||
|
||||
// set
|
||||
if (attributes.getInt(EatBinding, value, 1))
|
||||
type.getQualifier().layoutSet = value;
|
||||
|
||||
// global cbuffer binding
|
||||
if (attributes.getInt(EatGlobalBinding, value))
|
||||
globalUniformBinding = value;
|
||||
|
||||
// global cbuffer binding
|
||||
if (attributes.getInt(EatGlobalBinding, value, 1))
|
||||
globalUniformSet = value;
|
||||
|
||||
// input attachment
|
||||
if (attributes.getInt(EatInputAttachment, value))
|
||||
type.getQualifier().layoutAttachment = value;
|
||||
|
||||
// PointSize built-in
|
||||
TString builtInString;
|
||||
if (attributes.getString(EatBuiltIn, builtInString, 0, false)) {
|
||||
if (builtInString == "PointSize")
|
||||
type.getQualifier().builtIn = EbvPointSize;
|
||||
}
|
||||
|
||||
// push_constant
|
||||
if (attributes.contains(EatPushConstant))
|
||||
type.getQualifier().layoutPushConstant = true;
|
||||
|
||||
// specialization constant
|
||||
if (attributes.getInt(EatConstantId, value)) {
|
||||
TSourceLoc loc;
|
||||
loc.init();
|
||||
setSpecConstantId(loc, type.getQualifier(), value);
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatLocation:
|
||||
// location
|
||||
if (it->getInt(value))
|
||||
type.getQualifier().layoutLocation = value;
|
||||
break;
|
||||
case EatBinding:
|
||||
// binding
|
||||
if (it->getInt(value)) {
|
||||
type.getQualifier().layoutBinding = value;
|
||||
type.getQualifier().layoutSet = 0;
|
||||
}
|
||||
// set
|
||||
if (it->getInt(value, 1))
|
||||
type.getQualifier().layoutSet = value;
|
||||
break;
|
||||
case EatGlobalBinding:
|
||||
// global cbuffer binding
|
||||
if (it->getInt(value))
|
||||
globalUniformBinding = value;
|
||||
// global cbuffer binding
|
||||
if (it->getInt(value, 1))
|
||||
globalUniformSet = value;
|
||||
break;
|
||||
case EatInputAttachment:
|
||||
// input attachment
|
||||
if (it->getInt(value))
|
||||
type.getQualifier().layoutAttachment = value;
|
||||
break;
|
||||
case EatBuiltIn:
|
||||
// PointSize built-in
|
||||
if (it->getString(builtInString, 0, false)) {
|
||||
if (builtInString == "PointSize")
|
||||
type.getQualifier().builtIn = EbvPointSize;
|
||||
}
|
||||
break;
|
||||
case EatPushConstant:
|
||||
// push_constant
|
||||
type.getQualifier().layoutPushConstant = true;
|
||||
break;
|
||||
case EatConstantId:
|
||||
// specialization constant
|
||||
if (it->getInt(value)) {
|
||||
TSourceLoc loc;
|
||||
loc.init();
|
||||
setSpecConstantId(loc, type.getQualifier(), value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (! allowEntry)
|
||||
warn(loc, "attribute does not apply to a type", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1936,7 +1964,7 @@ void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, T
|
||||
// a subtree that creates the entry point.
|
||||
//
|
||||
TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction,
|
||||
const TAttributeMap& attributes)
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
// Return true if this is a tessellation patch constant function input to a domain shader.
|
||||
const auto isDsPcfInput = [this](const TType& type) {
|
||||
@@ -8792,29 +8820,75 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
|
||||
}
|
||||
|
||||
//
|
||||
// Selection hints
|
||||
// Selection attributes
|
||||
//
|
||||
TSelectionControl HlslParseContext::handleSelectionControl(const TAttributeMap& attributes) const
|
||||
void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (attributes.contains(EatFlatten))
|
||||
return ESelectionControlFlatten;
|
||||
else if (attributes.contains(EatBranch))
|
||||
return ESelectionControlDontFlatten;
|
||||
else
|
||||
return ESelectionControlNone;
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a selection", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Switch attributes
|
||||
//
|
||||
void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (selection == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatFlatten:
|
||||
selection->setFlatten();
|
||||
break;
|
||||
case EatBranch:
|
||||
selection->setDontFlatten();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a switch", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop hints
|
||||
//
|
||||
TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const
|
||||
void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
|
||||
const TAttributes& attributes)
|
||||
{
|
||||
if (attributes.contains(EatUnroll))
|
||||
return ELoopControlUnroll;
|
||||
else if (attributes.contains(EatLoop))
|
||||
return ELoopControlDontUnroll;
|
||||
else
|
||||
return ELoopControlNone;
|
||||
if (loop == nullptr)
|
||||
return;
|
||||
|
||||
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
|
||||
switch (it->name) {
|
||||
case EatUnroll:
|
||||
loop->setUnroll();
|
||||
break;
|
||||
case EatLoop:
|
||||
loop->setDontUnroll();
|
||||
break;
|
||||
default:
|
||||
warn(loc, "attribute does not apply to a loop", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -8959,7 +9033,7 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn
|
||||
// into a switch node.
|
||||
//
|
||||
TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
|
||||
TIntermAggregate* lastStatements, TSelectionControl control)
|
||||
TIntermAggregate* lastStatements, const TAttributes& attributes)
|
||||
{
|
||||
wrapupSwitchSubsequence(lastStatements, nullptr);
|
||||
|
||||
@@ -8986,7 +9060,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
|
||||
|
||||
TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
|
||||
switchNode->setLoc(loc);
|
||||
switchNode->setSelectionControl(control);
|
||||
handleSwitchAttributes(loc, switchNode, attributes);
|
||||
|
||||
return switchNode;
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@
|
||||
|
||||
#include "../glslang/MachineIndependent/parseVersions.h"
|
||||
#include "../glslang/MachineIndependent/ParseHelper.h"
|
||||
#include "../glslang/MachineIndependent/attribute.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TAttributeMap; // forward declare
|
||||
class TFunctionDeclarator;
|
||||
|
||||
class HlslParseContext : public TParseContextBase {
|
||||
@@ -80,10 +80,10 @@ public:
|
||||
bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
||||
void assignToInterface(TVariable& variable);
|
||||
void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
|
||||
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
|
||||
void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
|
||||
void transferTypeAttributes(const TAttributeMap&, TType&);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree);
|
||||
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&);
|
||||
void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&);
|
||||
void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false);
|
||||
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
|
||||
void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
|
||||
void remapNonEntryPointIO(TFunction& function);
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
|
||||
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
|
||||
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, TSelectionControl control);
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&);
|
||||
|
||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||
|
||||
@@ -203,10 +203,11 @@ public:
|
||||
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||
|
||||
// Determine selection control from attributes
|
||||
TSelectionControl handleSelectionControl(const TAttributeMap& attributes) const;
|
||||
void handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection*, const TAttributes& attributes);
|
||||
void handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch*, const TAttributes& attributes);
|
||||
|
||||
// Determine loop control from attributes
|
||||
TLoopControl handleLoopControl(const TAttributeMap& attributes) const;
|
||||
void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes);
|
||||
|
||||
// Share struct buffer deep types
|
||||
void shareStructBufferType(TType&);
|
||||
@@ -217,6 +218,8 @@ public:
|
||||
// Obtain the sampler return type of the given sampler in retType.
|
||||
void getTextureReturnType(const TSampler& sampler, TType& retType) const;
|
||||
|
||||
TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const;
|
||||
|
||||
protected:
|
||||
struct TFlattenData {
|
||||
TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),
|
||||
|
||||
Reference in New Issue
Block a user