HLSL: Sampler/texture declarations, method syntax, partial Sample method
This commit is contained in:
@@ -69,6 +69,11 @@ void HlslGrammar::expected(const char* syntax)
|
||||
parseContext.error(token.loc, "Expected", syntax, "");
|
||||
}
|
||||
|
||||
void HlslGrammar::unimplemented(const char* error)
|
||||
{
|
||||
parseContext.error(token.loc, "Unimplemented", error, "");
|
||||
}
|
||||
|
||||
// Only process the next token if it is an identifier.
|
||||
// Return true if it was an identifier.
|
||||
bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
|
||||
@@ -105,9 +110,136 @@ bool HlslGrammar::acceptCompilationUnit()
|
||||
return true;
|
||||
}
|
||||
|
||||
// sampler_state
|
||||
// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
|
||||
//
|
||||
// sampler_state_assignment
|
||||
// : sampler_state_identifier EQUAL value SEMICOLON
|
||||
//
|
||||
// sampler_state_identifier
|
||||
// : ADDRESSU
|
||||
// | ADDRESSV
|
||||
// | ADDRESSW
|
||||
// | BORDERCOLOR
|
||||
// | FILTER
|
||||
// | MAXANISOTROPY
|
||||
// | MAXLOD
|
||||
// | MINLOD
|
||||
// | MIPLODBIAS
|
||||
//
|
||||
bool HlslGrammar::acceptSamplerState()
|
||||
{
|
||||
// TODO: this should be genericized to accept a list of valid tokens and
|
||||
// return token/value pairs. Presently it is specific to texture values.
|
||||
|
||||
if (! acceptTokenClass(EHTokLeftBrace))
|
||||
return true;
|
||||
|
||||
parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
|
||||
|
||||
do {
|
||||
// read state name
|
||||
HlslToken state;
|
||||
if (! acceptIdentifier(state))
|
||||
break; // end of list
|
||||
|
||||
// FXC accepts any case
|
||||
TString stateName = *state.string;
|
||||
std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
|
||||
|
||||
if (! acceptTokenClass(EHTokAssign)) {
|
||||
expected("assign");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stateName == "minlod" || stateName == "maxlod") {
|
||||
if (! peekTokenClass(EHTokIntConstant)) {
|
||||
expected("integer");
|
||||
return false;
|
||||
}
|
||||
|
||||
TIntermTyped* lod = nullptr;
|
||||
if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
|
||||
return false;
|
||||
} else if (stateName == "maxanisotropy") {
|
||||
if (! peekTokenClass(EHTokIntConstant)) {
|
||||
expected("integer");
|
||||
return false;
|
||||
}
|
||||
|
||||
TIntermTyped* maxAnisotropy = nullptr;
|
||||
if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
|
||||
return false;
|
||||
} else if (stateName == "filter") {
|
||||
HlslToken filterMode;
|
||||
if (! acceptIdentifier(filterMode)) {
|
||||
expected("filter mode");
|
||||
return false;
|
||||
}
|
||||
} else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
|
||||
HlslToken addrMode;
|
||||
if (! acceptIdentifier(addrMode)) {
|
||||
expected("texture address mode");
|
||||
return false;
|
||||
}
|
||||
} else if (stateName == "miplodbias") {
|
||||
TIntermTyped* lodBias = nullptr;
|
||||
if (! acceptLiteral(lodBias)) {
|
||||
expected("lod bias");
|
||||
return false;
|
||||
}
|
||||
} else if (stateName == "bordercolor") {
|
||||
return false;
|
||||
} else {
|
||||
expected("texture state");
|
||||
return false;
|
||||
}
|
||||
|
||||
// SEMICOLON
|
||||
if (! acceptTokenClass(EHTokSemicolon)) {
|
||||
expected("semicolon");
|
||||
return false;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
if (! acceptTokenClass(EHTokRightBrace))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// sampler_declaration_dx9
|
||||
// : SAMPLER identifier EQUAL sampler_type sampler_state
|
||||
//
|
||||
bool HlslGrammar::acceptSamplerDeclarationDX9(TType& type)
|
||||
{
|
||||
if (! acceptTokenClass(EHTokSampler))
|
||||
return false;
|
||||
|
||||
// TODO: remove this when DX9 style declarations are implemented.
|
||||
unimplemented("Direct3D 9 sampler declaration");
|
||||
|
||||
// read sampler name
|
||||
HlslToken name;
|
||||
if (! acceptIdentifier(name)) {
|
||||
expected("sampler name");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! acceptTokenClass(EHTokAssign)) {
|
||||
expected("=");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// declaration
|
||||
// : fully_specified_type declarator_list SEMICOLON
|
||||
// : sampler_declaration_dx9 post_decls SEMICOLON
|
||||
// | fully_specified_type declarator_list SEMICOLON
|
||||
// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
|
||||
// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
|
||||
// | typedef declaration
|
||||
//
|
||||
// declarator_list
|
||||
@@ -134,12 +266,26 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
// typedef
|
||||
bool typedefDecl = acceptTokenClass(EHTokTypedef);
|
||||
|
||||
// fully_specified_type
|
||||
TType type;
|
||||
|
||||
// DX9 sampler declaration use a different syntax
|
||||
if (acceptSamplerDeclarationDX9(type))
|
||||
return true;
|
||||
|
||||
// fully_specified_type
|
||||
if (! acceptFullySpecifiedType(type))
|
||||
return false;
|
||||
if (type.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
|
||||
type.getQualifier().storage = EvqGlobal;
|
||||
|
||||
if (type.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) {
|
||||
if (type.getBasicType() == EbtSampler) {
|
||||
// Sampler/textures are uniform by default (if no explicit qualifier is present) in
|
||||
// HLSL. This line silently converts samplers *explicitly* declared static to uniform,
|
||||
// which is incorrect but harmless.
|
||||
type.getQualifier().storage = EvqUniform;
|
||||
} else {
|
||||
type.getQualifier().storage = EvqGlobal;
|
||||
}
|
||||
}
|
||||
|
||||
// identifier
|
||||
HlslToken idToken;
|
||||
@@ -169,6 +315,12 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
TArraySizes* arraySizes = nullptr;
|
||||
acceptArraySpecifier(arraySizes);
|
||||
|
||||
// samplers accept immediate sampler state
|
||||
if (type.getBasicType() == EbtSampler) {
|
||||
if (! acceptSamplerState())
|
||||
return false;
|
||||
}
|
||||
|
||||
// post_decls
|
||||
acceptPostDecls(type);
|
||||
|
||||
@@ -487,6 +639,143 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
|
||||
}
|
||||
|
||||
|
||||
// sampler_type
|
||||
// : SAMPLER
|
||||
// | SAMPLER1D
|
||||
// | SAMPLER2D
|
||||
// | SAMPLER3D
|
||||
// | SAMPLERCUBE
|
||||
// | SAMPLERSTATE
|
||||
// | SAMPLERCOMPARISONSTATE
|
||||
bool HlslGrammar::acceptSamplerType(TType& type)
|
||||
{
|
||||
// read sampler type
|
||||
const EHlslTokenClass samplerType = peek();
|
||||
|
||||
TSamplerDim dim = EsdNone;
|
||||
|
||||
switch (samplerType) {
|
||||
case EHTokSampler: break;
|
||||
case EHTokSampler1d: dim = Esd1D; break;
|
||||
case EHTokSampler2d: dim = Esd2D; break;
|
||||
case EHTokSampler3d: dim = Esd3D; break;
|
||||
case EHTokSamplerCube: dim = EsdCube; break;
|
||||
case EHTokSamplerState: break;
|
||||
case EHTokSamplerComparisonState: break;
|
||||
default:
|
||||
return false; // not a sampler declaration
|
||||
}
|
||||
|
||||
advanceToken(); // consume the sampler type keyword
|
||||
|
||||
TArraySizes* arraySizes = nullptr; // TODO: array
|
||||
bool shadow = false; // TODO: shadow
|
||||
|
||||
TSampler sampler;
|
||||
sampler.setPureSampler(shadow);
|
||||
|
||||
type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// texture_type
|
||||
// | BUFFER
|
||||
// | TEXTURE1D
|
||||
// | TEXTURE1DARRAY
|
||||
// | TEXTURE2D
|
||||
// | TEXTURE2DARRAY
|
||||
// | TEXTURE3D
|
||||
// | TEXTURECUBE
|
||||
// | TEXTURECUBEARRAY
|
||||
// | TEXTURE2DMS
|
||||
// | TEXTURE2DMSARRAY
|
||||
bool HlslGrammar::acceptTextureType(TType& type)
|
||||
{
|
||||
const EHlslTokenClass textureType = peek();
|
||||
|
||||
TSamplerDim dim = EsdNone;
|
||||
bool array = false;
|
||||
bool ms = false;
|
||||
|
||||
switch (textureType) {
|
||||
case EHTokBuffer: dim = EsdBuffer; break;
|
||||
case EHTokTexture1d: dim = Esd1D; break;
|
||||
case EHTokTexture1darray: dim = Esd1D; array = true; break;
|
||||
case EHTokTexture2d: dim = Esd2D; break;
|
||||
case EHTokTexture2darray: dim = Esd2D; array = true; break;
|
||||
case EHTokTexture3d: dim = Esd3D; break;
|
||||
case EHTokTextureCube: dim = EsdCube; break;
|
||||
case EHTokTextureCubearray: dim = EsdCube; array = true; break;
|
||||
case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
|
||||
case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
|
||||
default:
|
||||
return false; // not a texture declaration
|
||||
}
|
||||
|
||||
advanceToken(); // consume the texture object keyword
|
||||
|
||||
TType txType(EbtFloat, EvqUniform, 4); // default type is float4
|
||||
|
||||
TIntermTyped* msCount = nullptr;
|
||||
|
||||
// texture type: required for multisample types!
|
||||
if (acceptTokenClass(EHTokLeftAngle)) {
|
||||
if (! acceptType(txType)) {
|
||||
expected("scalar or vector type");
|
||||
return false;
|
||||
}
|
||||
|
||||
const TBasicType basicRetType = txType.getBasicType() ;
|
||||
|
||||
if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
|
||||
unimplemented("basic type in texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!txType.isScalar() && !txType.isVector()) {
|
||||
expected("scalar or vector type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (txType.getVectorSize() != 1 && txType.getVectorSize() != 4) {
|
||||
// TODO: handle vec2/3 types
|
||||
expected("vector size not yet supported in texture type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ms && acceptTokenClass(EHTokComma)) {
|
||||
// read sample count for multisample types, if given
|
||||
if (! peekTokenClass(EHTokIntConstant)) {
|
||||
expected("multisample count");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! acceptTokenClass(EHTokRightAngle)) {
|
||||
expected("right angle bracket");
|
||||
return false;
|
||||
}
|
||||
} else if (ms) {
|
||||
expected("texture type for multisample");
|
||||
return false;
|
||||
}
|
||||
|
||||
TArraySizes* arraySizes = nullptr;
|
||||
const bool shadow = txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1);
|
||||
|
||||
TSampler sampler;
|
||||
sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
|
||||
|
||||
type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If token is for a type, update 'type' with the type information,
|
||||
// and return true and advance.
|
||||
// Otherwise, return false, and don't advance
|
||||
@@ -501,6 +790,29 @@ bool HlslGrammar::acceptType(TType& type)
|
||||
return acceptMatrixTemplateType(type);
|
||||
break;
|
||||
|
||||
case EHTokSampler: // fall through
|
||||
case EHTokSampler1d: // ...
|
||||
case EHTokSampler2d: // ...
|
||||
case EHTokSampler3d: // ...
|
||||
case EHTokSamplerCube: // ...
|
||||
case EHTokSamplerState: // ...
|
||||
case EHTokSamplerComparisonState: // ...
|
||||
return acceptSamplerType(type);
|
||||
break;
|
||||
|
||||
case EHTokBuffer: // fall through
|
||||
case EHTokTexture1d: // ...
|
||||
case EHTokTexture1darray: // ...
|
||||
case EHTokTexture2d: // ...
|
||||
case EHTokTexture2darray: // ...
|
||||
case EHTokTexture3d: // ...
|
||||
case EHTokTextureCube: // ...
|
||||
case EHTokTextureCubearray: // ...
|
||||
case EHTokTexture2DMS: // ...
|
||||
case EHTokTexture2DMSarray: // ...
|
||||
return acceptTextureType(type);
|
||||
break;
|
||||
|
||||
case EHTokStruct:
|
||||
return acceptStruct(type);
|
||||
break;
|
||||
@@ -1420,13 +1732,23 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
|
||||
{
|
||||
// DOT IDENTIFIER
|
||||
// includes swizzles and struct members
|
||||
// TODO: possibly includes "method" syntax
|
||||
HlslToken field;
|
||||
if (! acceptIdentifier(field)) {
|
||||
expected("swizzle or member");
|
||||
return false;
|
||||
}
|
||||
|
||||
TIntermTyped* base = node; // preserve for method function calls
|
||||
node = parseContext.handleDotDereference(field.loc, node, *field.string);
|
||||
|
||||
// In the event of a method node, we look for an open paren and accept the function call.
|
||||
if (node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) {
|
||||
if (! acceptFunctionCall(field, node, base)) {
|
||||
expected("function parameters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EOpIndexIndirect:
|
||||
@@ -1489,11 +1811,16 @@ bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
|
||||
// function_call
|
||||
// : [idToken] arguments
|
||||
//
|
||||
bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
|
||||
bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base)
|
||||
{
|
||||
// arguments
|
||||
TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
|
||||
TIntermTyped* arguments = nullptr;
|
||||
|
||||
// methods have an implicit first argument of the calling object.
|
||||
if (base != nullptr)
|
||||
parseContext.handleFunctionArgument(function, arguments, base);
|
||||
|
||||
if (! acceptArguments(function, arguments))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -59,16 +59,21 @@ namespace glslang {
|
||||
HlslGrammar& operator=(const HlslGrammar&);
|
||||
|
||||
void expected(const char*);
|
||||
void unimplemented(const char*);
|
||||
bool acceptIdentifier(HlslToken&);
|
||||
bool acceptCompilationUnit();
|
||||
bool acceptDeclaration(TIntermNode*& node);
|
||||
bool acceptControlDeclaration(TIntermNode*& node);
|
||||
bool acceptSamplerDeclarationDX9(TType&);
|
||||
bool acceptSamplerState();
|
||||
bool acceptFullySpecifiedType(TType&);
|
||||
void acceptQualifier(TQualifier&);
|
||||
bool acceptType(TType&);
|
||||
bool acceptTemplateType(TBasicType&);
|
||||
bool acceptVectorTemplateType(TType&);
|
||||
bool acceptMatrixTemplateType(TType&);
|
||||
bool acceptSamplerType(TType&);
|
||||
bool acceptTextureType(TType&);
|
||||
bool acceptStruct(TType&);
|
||||
bool acceptStructDeclarationList(TTypeList*&);
|
||||
bool acceptFunctionParameters(TFunction&);
|
||||
@@ -82,7 +87,7 @@ namespace glslang {
|
||||
bool acceptUnaryExpression(TIntermTyped*&);
|
||||
bool acceptPostfixExpression(TIntermTyped*&);
|
||||
bool acceptConstructor(TIntermTyped*&);
|
||||
bool acceptFunctionCall(HlslToken, TIntermTyped*&);
|
||||
bool acceptFunctionCall(HlslToken, TIntermTyped*&, TIntermTyped* base = nullptr);
|
||||
bool acceptArguments(TFunction*, TIntermTyped*&);
|
||||
bool acceptLiteral(TIntermTyped*&);
|
||||
bool acceptCompoundStatement(TIntermNode*&);
|
||||
|
||||
@@ -564,12 +564,32 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
|
||||
variableCheck(base);
|
||||
|
||||
//
|
||||
// .length() can't be resolved until we later see the function-calling syntax.
|
||||
// methods can't be resolved until we later see the function-calling syntax.
|
||||
// Save away the name in the AST for now. Processing is completed in
|
||||
// handleLengthMethod().
|
||||
// handleLengthMethod(), etc.
|
||||
//
|
||||
if (field == "length") {
|
||||
return intermediate.addMethod(base, TType(EbtInt), &field, loc);
|
||||
} else if (field == "CalculateLevelOfDetail" ||
|
||||
field == "CalculateLevelOfDetailUnclamped" ||
|
||||
field == "Gather" ||
|
||||
field == "GetDimensions" ||
|
||||
field == "GetSamplePosition" ||
|
||||
field == "Load" ||
|
||||
field == "Sample" ||
|
||||
field == "SampleBias" ||
|
||||
field == "SampleCmp" ||
|
||||
field == "SampleCmpLevelZero" ||
|
||||
field == "SampleGrad" ||
|
||||
field == "SampleLevel") {
|
||||
// If it's not a method on a sampler object, we fall through in case it is a struct member.
|
||||
if (base->getType().getBasicType() == EbtSampler) {
|
||||
const TSampler& texType = base->getType().getSampler();
|
||||
if (! texType.isPureSampler()) {
|
||||
const int vecSize = texType.isShadow() ? 1 : 4;
|
||||
return intermediate.addMethod(base, TType(texType.type, EvqTemporary, vecSize), &field, loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's not .length() if we get to here.
|
||||
@@ -1006,9 +1026,7 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*&
|
||||
|
||||
TIntermTyped* arg0 = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* arg1 = argAggregate->getSequence()[1]->getAsTyped();
|
||||
TBasicType type0 = arg0->getBasicType();
|
||||
|
||||
TIntermTyped* x = intermediate.addConstantUnion(0, loc, true);
|
||||
TIntermTyped* y = intermediate.addConstantUnion(1, loc, true);
|
||||
TIntermTyped* z = intermediate.addConstantUnion(2, loc, true);
|
||||
TIntermTyped* w = intermediate.addConstantUnion(3, loc, true);
|
||||
@@ -1204,6 +1222,49 @@ void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*&
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Decompose sample methods into AST
|
||||
//
|
||||
void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
|
||||
{
|
||||
if (!node || !node->getAsOperator())
|
||||
return;
|
||||
|
||||
const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
|
||||
const TOperator op = node->getAsOperator()->getOp();
|
||||
|
||||
switch (op) {
|
||||
case EOpMethodSample:
|
||||
{
|
||||
TIntermTyped* argTex = argAggregate->getSequence()[0]->getAsTyped();
|
||||
TIntermTyped* argSamp = argAggregate->getSequence()[1]->getAsTyped();
|
||||
TIntermTyped* argCoord = argAggregate->getSequence()[2]->getAsTyped();
|
||||
|
||||
TIntermAggregate* txcombine = new TIntermAggregate(EOpConstructTextureSampler);
|
||||
|
||||
txcombine->getSequence().push_back(argTex);
|
||||
txcombine->getSequence().push_back(argSamp);
|
||||
TSampler samplerType = argTex->getType().getSampler();
|
||||
samplerType.combined = true;
|
||||
txcombine->setType(TType(samplerType, EvqTemporary));
|
||||
txcombine->setLoc(loc);
|
||||
|
||||
TIntermAggregate* txsample = new TIntermAggregate(EOpTexture);
|
||||
txsample->getSequence().push_back(txcombine);
|
||||
txsample->getSequence().push_back(argCoord);
|
||||
txsample->setType(node->getType());
|
||||
txsample->setLoc(loc);
|
||||
node = txsample;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break; // most pass through unchanged
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Handle seeing function call syntax in the grammar, which could be any of
|
||||
// - .length() method
|
||||
@@ -1307,8 +1368,9 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
|
||||
result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
|
||||
}
|
||||
|
||||
decomposeIntrinsic(loc, result, arguments);
|
||||
textureParameters(loc, result, arguments);
|
||||
decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
|
||||
decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions
|
||||
textureParameters(loc, result, arguments); // HLSL->AST texture intrinsics
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg);
|
||||
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
void textureParameters(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
|
||||
|
||||
@@ -65,6 +65,12 @@ const char* BaseTypeName(const char* argOrder, const char* scalarName, const cha
|
||||
default: return "UNKNOWN_TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTextureType(const char argType)
|
||||
{
|
||||
return argType == 'T' || argType == 'i' || argType == 'u';
|
||||
}
|
||||
|
||||
|
||||
// Create and return a type name. This is done in GLSL, not HLSL conventions, until such
|
||||
// time as builtins are parsed using the HLSL parser.
|
||||
@@ -95,6 +101,9 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
|
||||
case 'U': s += "uint"; break;
|
||||
case 'B': s += "bool"; break;
|
||||
case 'S': s += "sampler"; break;
|
||||
case 'T': s += "Texture"; break;
|
||||
case 'i': assert(0); // TODO: ...
|
||||
case 'u': assert(0); // TODO: ...
|
||||
default: s += "UNKNOWN_TYPE"; break;
|
||||
}
|
||||
} else {
|
||||
@@ -105,7 +114,10 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
|
||||
case 'I': s += BaseTypeName(argOrder, "int", "ivec", "imat"); break;
|
||||
case 'U': s += BaseTypeName(argOrder, "uint", "uvec", "umat"); break;
|
||||
case 'B': s += BaseTypeName(argOrder, "bool", "bvec", "bmat"); break;
|
||||
case 'S': s += BaseTypeName(argOrder, "sampler", "sampler", "sampler"); break; // TODO:
|
||||
case 'S': s += BaseTypeName(argOrder, "sampler", "sampler", "sampler"); break;
|
||||
case 'T': s += BaseTypeName(argOrder, "texture", "texture", "texture"); break;
|
||||
case 'i': s += BaseTypeName(argOrder, "itexture", "itexture", "itexture"); break;
|
||||
case 'u': s += BaseTypeName(argOrder, "utexture", "utexture", "utexture"); break;
|
||||
default: s += "UNKNOWN_TYPE"; break;
|
||||
}
|
||||
}
|
||||
@@ -116,35 +128,38 @@ glslang::TString& AppendTypeName(glslang::TString& s, const char* argOrder, cons
|
||||
dim0 = dim1 = fixedVecSize;
|
||||
|
||||
// Add sampler dimensions
|
||||
if (*argType == 'S') {
|
||||
switch (dim0) {
|
||||
case 1: s += "1D"; break;
|
||||
case 2: s += "2D"; break;
|
||||
case 3: s += "3D"; break;
|
||||
case 4: s += "Cube"; break;
|
||||
default: s += "UNKNOWN_SAMPLER"; break;
|
||||
if (*argType == 'S' || IsTextureType(*argType)) {
|
||||
if (*argOrder == 'V') {
|
||||
switch (dim0) {
|
||||
case 1: s += "1D"; break;
|
||||
case 2: s += "2D"; break;
|
||||
case 3: s += "3D"; break;
|
||||
case 4: s += "Cube"; break;
|
||||
default: s += "UNKNOWN_SAMPLER"; break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Non-sampler type:
|
||||
// verify dimensions
|
||||
if (((*argOrder == 'V' || *argOrder == 'M') && (dim0 < 1 || dim0 > 4)) ||
|
||||
(*argOrder == 'M' && (dim1 < 1 || dim1 > 4))) {
|
||||
s += "UNKNOWN_DIMENSION";
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
// verify dimensions
|
||||
if ((*argOrder == 'V' || *argOrder == 'M') && (dim0 < 1 || dim0 > 4) ||
|
||||
(*argOrder == 'M' && (dim1 < 1 || dim1 > 4))) {
|
||||
s += "UNKNOWN_DIMENSION";
|
||||
return s;
|
||||
}
|
||||
|
||||
switch (*argOrder) {
|
||||
case '-': break; // no dimensions for voids
|
||||
case 'S': break; // no dimensions on scalars
|
||||
case 'V': s += ('0' + (char)dim0); break;
|
||||
case 'M':
|
||||
{
|
||||
if (!UseHlslTypes) // GLSL has column first for mat types
|
||||
std::swap(dim0, dim1);
|
||||
s += ('0' + (char)dim0);
|
||||
s += 'x';
|
||||
s += ('0' + (char)dim1);
|
||||
break;
|
||||
switch (*argOrder) {
|
||||
case '-': break; // no dimensions for voids
|
||||
case 'S': break; // no dimensions on scalars
|
||||
case 'V': s += ('0' + (char)dim0); break;
|
||||
case 'M':
|
||||
{
|
||||
if (!UseHlslTypes) // GLSL has column first for mat types
|
||||
std::swap(dim0, dim1);
|
||||
s += ('0' + (char)dim0);
|
||||
s += 'x';
|
||||
s += ('0' + (char)dim1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,17 +175,18 @@ inline bool IsValidGlsl(const char* cname, char retOrder, char retType, char /*a
|
||||
const bool isVec = dim0Max > 1 || argType == 'V';
|
||||
const bool isMat = dim1Max > 1 || argType == 'M';
|
||||
|
||||
if ((isVec && dim0 == 1) || // avoid vec1
|
||||
(isMat && dim0 == 1 && dim1 == 1)) // avoid mat1x1
|
||||
if (!IsTextureType(argType) &&
|
||||
((isVec && dim0 == 1) || // avoid vec1
|
||||
(isMat && dim0 == 1 && dim1 == 1))) // avoid mat1x1
|
||||
return false;
|
||||
|
||||
const std::string name(cname); // for ease of comparison. slow, but temporary, until HLSL parser is online.
|
||||
|
||||
|
||||
if (isMat && dim1 == 1) // TODO: avoid mat Nx1 until we find the right GLSL profile
|
||||
return false;
|
||||
|
||||
if (isMat && (argType == 'I' || argType == 'U' || argType == 'B') ||
|
||||
retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B'))
|
||||
if ((isMat && (argType == 'I' || argType == 'U' || argType == 'B')) ||
|
||||
(retOrder == 'M' && (retType == 'I' || retType == 'U' || retType == 'B')))
|
||||
return false;
|
||||
|
||||
if (name == "GetRenderTargetSamplePosition" ||
|
||||
@@ -284,7 +300,8 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
// orderKey can be:
|
||||
// S = scalar, V = vector, M = matrix, - = void
|
||||
// typekey can be:
|
||||
// D = double, F = float, U = uint, I = int, B = bool, S = sampler, - = void
|
||||
// D = double, F = float, U = uint, I = int, B = bool,
|
||||
// S = sampler, T = texture, i = itexture, u = utexture, - = void
|
||||
// An empty order or type key repeats the first one. E.g: SVM,, means 3 args each of SVM.
|
||||
// '>' as first letter of order creates an output parameter
|
||||
// '<' as first letter of order creates an input parameter
|
||||
@@ -429,33 +446,39 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
{ "step", nullptr, nullptr, "SVM,", "F,", EShLangAll },
|
||||
{ "tan", nullptr, nullptr, "SVM", "F", EShLangAll },
|
||||
{ "tanh", nullptr, nullptr, "SVM", "F", EShLangAll },
|
||||
{ "tex1D", "V4", "F", "S1,S", "S,F", EShLangFragmentMask },
|
||||
{ "tex1D", "V4", "F", "S1,S,V1,V1", "S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex1Dbias", "V4", "F", "S1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex1Dgrad", "V4", "F", "S1,V1,V1,V1","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex1Dlod", "V4", "F", "S1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex1Dproj", "V4", "F", "S1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2D", "V4", "F", "S2,V2", "S,F", EShLangFragmentMask },
|
||||
{ "tex2D", "V4", "F", "S2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex2Dbias", "V4", "F", "S2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2Dgrad", "V4", "F", "S2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex2Dlod", "V4", "F", "S2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2Dproj", "V4", "F", "S2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3D", "V4", "F", "S3,V3", "S,F", EShLangFragmentMask },
|
||||
{ "tex3D", "V4", "F", "S3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex3Dbias", "V4", "F", "S3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3Dgrad", "V4", "F", "S3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex3Dlod", "V4", "F", "S3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3Dproj", "V4", "F", "S3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBE", "V4", "F", "S4,V3", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBE", "V4", "F", "S4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "texCUBEbias", "V4", "F", "S4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBEgrad", "V4", "F", "S4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "texCUBElod", "V4", "F", "S4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBEproj", "V4", "F", "S4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex1D", "V4", "F", "V1,S", "S,F", EShLangFragmentMask },
|
||||
{ "tex1D", "V4", "F", "V1,S,V1,V1", "S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex1Dbias", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex1Dgrad", "V4", "F", "V1,V1,V1,V1","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex1Dlod", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex1Dproj", "V4", "F", "V1,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2D", "V4", "F", "V2,V2", "S,F", EShLangFragmentMask },
|
||||
{ "tex2D", "V4", "F", "V2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex2Dbias", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2Dgrad", "V4", "F", "V2,V2,V2,V2","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex2Dlod", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex2Dproj", "V4", "F", "V2,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3D", "V4", "F", "V3,V3", "S,F", EShLangFragmentMask },
|
||||
{ "tex3D", "V4", "F", "V3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex3Dbias", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3Dgrad", "V4", "F", "V3,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "tex3Dlod", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "tex3Dproj", "V4", "F", "V3,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBE", "V4", "F", "V4,V3", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBE", "V4", "F", "V4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "texCUBEbias", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBEgrad", "V4", "F", "V4,V3,V3,V3","S,F,F,F",EShLangFragmentMask },
|
||||
{ "texCUBElod", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "texCUBEproj", "V4", "F", "V4,V4", "S,F", EShLangFragmentMask },
|
||||
{ "transpose", "^M", nullptr, "M", "F", EShLangAll },
|
||||
{ "trunc", nullptr, nullptr, "SVM", "F", EShLangAll },
|
||||
|
||||
// Texture object methods. Return type can be overridden by shader declaration.
|
||||
{ "Sample", "V4", "F", "V,S,V", "T,S,F", EShLangFragmentMask },
|
||||
{ "Sample", "V4", "I", "V,S,V", "i,S,F", EShLangFragmentMask },
|
||||
{ "Sample", "V4", "U", "V,S,V", "u,S,F", EShLangFragmentMask },
|
||||
// TODO: forms with texel-space offset parameter
|
||||
|
||||
// Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
|
||||
{ nullptr, nullptr, nullptr, nullptr, nullptr, 0 },
|
||||
};
|
||||
@@ -501,6 +524,8 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
s.append(intrinsic.name); // intrinsic name
|
||||
s.append("("); // open paren
|
||||
|
||||
const bool isTexture = IsTextureType(*argType);
|
||||
|
||||
// Append argument types, if any.
|
||||
for (int arg = 0; ; ++arg) {
|
||||
const char* nthArgOrder(NthArg(argOrder, arg));
|
||||
@@ -509,6 +534,13 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
if (nthArgOrder == nullptr || nthArgType == nullptr)
|
||||
break;
|
||||
|
||||
// For textures, the 1D case isn't a 1-vector, but a scalar.
|
||||
if (isTexture && dim0 == 1 && arg > 0 && *nthArgOrder == 'V')
|
||||
nthArgOrder = "S";
|
||||
|
||||
// cube textures use vec3 coordinates
|
||||
const int argDim0 = isTexture && arg > 0 ? std::min(dim0, 3) : dim0;
|
||||
|
||||
s.append(arg > 0 ? ", ": ""); // comma separator if needed
|
||||
|
||||
if (*nthArgOrder == '>') { // output params
|
||||
@@ -523,7 +555,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
||||
if (*nthArgOrder == ',' || *nthArgOrder == '\0') nthArgOrder = argOrder;
|
||||
if (*nthArgType == ',' || *nthArgType == '\0') nthArgType = argType;
|
||||
|
||||
AppendTypeName(s, nthArgOrder, nthArgType, dim0, dim1); // Add arguments
|
||||
AppendTypeName(s, nthArgOrder, nthArgType, argDim0, dim1); // Add arguments
|
||||
}
|
||||
|
||||
s.append(");\n"); // close paren and trailing semicolon
|
||||
@@ -606,7 +638,7 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
|
||||
symbolTable.relateToOperator("ddy_fine", EOpDPdyFine);
|
||||
symbolTable.relateToOperator("degrees", EOpDegrees);
|
||||
symbolTable.relateToOperator("determinant", EOpDeterminant);
|
||||
symbolTable.relateToOperator("DeviceMemoryBarrier", EOpGroupMemoryBarrier); // == ScopeDevice+CrossWorkGroup
|
||||
symbolTable.relateToOperator("DeviceMemoryBarrier", EOpGroupMemoryBarrier);
|
||||
symbolTable.relateToOperator("DeviceMemoryBarrierWithGroupSync", EOpGroupMemoryBarrierWithGroupSync); // ...
|
||||
symbolTable.relateToOperator("distance", EOpDistance);
|
||||
symbolTable.relateToOperator("dot", EOpDot);
|
||||
@@ -710,6 +742,9 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
|
||||
symbolTable.relateToOperator("texCUBEproj", EOpTextureProj);
|
||||
symbolTable.relateToOperator("transpose", EOpTranspose);
|
||||
symbolTable.relateToOperator("trunc", EOpTrunc);
|
||||
|
||||
// Texture methods
|
||||
symbolTable.relateToOperator("Sample", EOpMethodSample);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//
|
||||
//Copyright (C) 2016 Google, Inc.
|
||||
//Copyright (C) 2016 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
@@ -249,6 +250,9 @@ void HlslScanContext::fillInKeywordMap()
|
||||
(*KeywordMap)["Texture2DArray"] = EHTokTexture2darray;
|
||||
(*KeywordMap)["Texture3D"] = EHTokTexture3d;
|
||||
(*KeywordMap)["TextureCube"] = EHTokTextureCube;
|
||||
(*KeywordMap)["TextureCubeArray"] = EHTokTextureCubearray;
|
||||
(*KeywordMap)["Texture2DMS"] = EHTokTexture2DMS;
|
||||
(*KeywordMap)["Texture2DMSArray"] = EHTokTexture2DMSarray;
|
||||
|
||||
(*KeywordMap)["struct"] = EHTokStruct;
|
||||
(*KeywordMap)["typedef"] = EHTokTypedef;
|
||||
@@ -556,6 +560,9 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
|
||||
case EHTokTexture2darray:
|
||||
case EHTokTexture3d:
|
||||
case EHTokTextureCube:
|
||||
case EHTokTextureCubearray:
|
||||
case EHTokTexture2DMS:
|
||||
case EHTokTexture2DMSarray:
|
||||
return keyword;
|
||||
|
||||
// variable, user type, ...
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//
|
||||
//Copyright (C) 2016 Google, Inc.
|
||||
//Copyright (C) 2016 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
@@ -200,6 +201,9 @@ enum EHlslTokenClass {
|
||||
EHTokTexture2darray,
|
||||
EHTokTexture3d,
|
||||
EHTokTextureCube,
|
||||
EHTokTextureCubearray,
|
||||
EHTokTexture2DMS,
|
||||
EHTokTexture2DMSarray,
|
||||
|
||||
// variable, user type, ...
|
||||
EHTokIdentifier,
|
||||
@@ -278,4 +282,4 @@ enum EHlslTokenClass {
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // EHLSLTOKENS_H_
|
||||
#endif // EHLSLTOKENS_H_
|
||||
|
||||
Reference in New Issue
Block a user