SPV: Implement Vulkan version of GLSL (KHR_vulkan_glsl).
This commit is contained in:
parent
019f08fcd8
commit
6c292d3ba7
200 changed files with 7841 additions and 5577 deletions
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//Copyright (C) 2012-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
|
|
@ -47,10 +48,10 @@ extern int yyparse(glslang::TParseContext*);
|
|||
|
||||
namespace glslang {
|
||||
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, EShLanguage L, TInfoSink& is,
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, int vulkan, EShLanguage L, TInfoSink& is,
|
||||
bool fc, EShMessages m) :
|
||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L),
|
||||
version(v), profile(p), spv(spv), forwardCompatible(fc),
|
||||
version(v), profile(p), spv(spv), vulkan(vulkan), forwardCompatible(fc),
|
||||
contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0),
|
||||
postMainReturn(false),
|
||||
tokensBeforeEOF(false), limits(resources.limits), messages(m), currentScanner(nullptr),
|
||||
|
|
@ -97,11 +98,11 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
|
|||
|
||||
globalUniformDefaults.clear();
|
||||
globalUniformDefaults.layoutMatrix = ElmColumnMajor;
|
||||
globalUniformDefaults.layoutPacking = ElpShared;
|
||||
globalUniformDefaults.layoutPacking = vulkan > 0 ? ElpStd140 : ElpShared;
|
||||
|
||||
globalBufferDefaults.clear();
|
||||
globalBufferDefaults.layoutMatrix = ElmColumnMajor;
|
||||
globalBufferDefaults.layoutPacking = ElpShared;
|
||||
globalBufferDefaults.layoutPacking = vulkan > 0 ? ElpStd430 : ElpShared;
|
||||
|
||||
globalInputDefaults.clear();
|
||||
globalOutputDefaults.clear();
|
||||
|
|
@ -463,7 +464,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb
|
|||
if (! variable)
|
||||
variable = new TVariable(string, TType(EbtVoid));
|
||||
|
||||
if (variable->getType().getQualifier().storage == EvqConst)
|
||||
if (variable->getType().getQualifier().isFrontEndConstant())
|
||||
node = intermediate.addConstantUnion(variable->getConstArray(), variable->getType(), loc);
|
||||
else
|
||||
node = intermediate.addSymbol(*variable, loc);
|
||||
|
|
@ -610,6 +611,16 @@ void TParseContext::makeEditable(TSymbol*& symbol)
|
|||
intermediate.addSymbolLinkageNode(linkage, *symbol);
|
||||
}
|
||||
|
||||
TVariable* TParseContext::getEditableVariable(const char* name)
|
||||
{
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find(name, &builtIn);
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
|
||||
return symbol->getAsVariable();
|
||||
}
|
||||
|
||||
// Return true if this is a geometry shader input array or tessellation control output array.
|
||||
bool TParseContext::isIoResizeArray(const TType& type) const
|
||||
{
|
||||
|
|
@ -813,7 +824,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|||
}
|
||||
}
|
||||
|
||||
if (base->getType().getQualifier().storage == EvqConst)
|
||||
if (base->getType().getQualifier().isFrontEndConstant())
|
||||
result = intermediate.foldSwizzle(base, fields, loc);
|
||||
else {
|
||||
if (fields.num == 1) {
|
||||
|
|
@ -1682,6 +1693,8 @@ TOperator TParseContext::mapTypeToConstructorOp(const TType& type) const
|
|||
op = EOpConstructStruct;
|
||||
break;
|
||||
case EbtSampler:
|
||||
if (type.getSampler().combined)
|
||||
op = EOpConstructTextureSampler;
|
||||
break;
|
||||
case EbtFloat:
|
||||
if (type.isMatrix()) {
|
||||
|
|
@ -2154,6 +2167,8 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
|
||||
bool constructingMatrix = false;
|
||||
switch(op) {
|
||||
case EOpConstructTextureSampler:
|
||||
return constructorTextureSamplerError(loc, function);
|
||||
case EOpConstructMat2x2:
|
||||
case EOpConstructMat2x3:
|
||||
case EOpConstructMat2x4:
|
||||
|
|
@ -2309,6 +2324,66 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|||
return false;
|
||||
}
|
||||
|
||||
// Verify all the correct semantics for constructing a combined texture/sampler.
|
||||
// Return true if the semantics are incorrect.
|
||||
bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const TFunction& function)
|
||||
{
|
||||
TString constructorName = function.getType().getBasicTypeString(); // TODO: performance: should not be making copy; interface needs to change
|
||||
const char* token = constructorName.c_str();
|
||||
|
||||
// exactly two arguments needed
|
||||
if (function.getParamCount() != 2) {
|
||||
error(loc, "sampler-constructor requires two arguments", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// For now, not allowing arrayed constructors, the rest of this function
|
||||
// is set up to allow them, if this test is removed:
|
||||
if (function.getType().isArray()) {
|
||||
error(loc, "sampler-constructor cannot make an array of samplers", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// first argument
|
||||
// * the constructor's first argument must be a texture type
|
||||
// * the dimensionality (1D, 2D, 3D, Cube, Rect, Buffer, MS, and Array)
|
||||
// of the texture type must match that of the constructed sampler type
|
||||
// (that is, the suffixes of the type of the first argument and the
|
||||
// type of the constructor will be spelled the same way)
|
||||
if (function[0].type->getBasicType() != EbtSampler ||
|
||||
! function[0].type->getSampler().isTexture() ||
|
||||
function[0].type->isArray()) {
|
||||
error(loc, "sampler-constructor first argument must be a scalar textureXXX type", token, "");
|
||||
return true;
|
||||
}
|
||||
// simulate the first argument's impact on the result type, so it can be compared with the encapsulated operator!=()
|
||||
TSampler texture = function.getType().getSampler();
|
||||
texture.combined = false;
|
||||
texture.shadow = false;
|
||||
if (texture != function[0].type->getSampler()) {
|
||||
error(loc, "sampler-constructor first argument must match type and dimensionality of constructor type", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
// second argument
|
||||
// * the constructor's second argument must be a scalar of type
|
||||
// *sampler* or *samplerShadow*
|
||||
// * the presence or absence of depth comparison (Shadow) must match
|
||||
// between the constructed sampler type and the type of the second argument
|
||||
if ( function[1].type->getBasicType() != EbtSampler ||
|
||||
! function[1].type->getSampler().isPureSampler() ||
|
||||
function[1].type->isArray()) {
|
||||
error(loc, "sampler-constructor second argument must be a scalar type 'sampler'", token, "");
|
||||
return true;
|
||||
}
|
||||
if (function.getType().getSampler().shadow != function[1].type->getSampler().shadow) {
|
||||
error(loc, "sampler-constructor second argument presence of shadow must match constructor presence of shadow", token, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks to see if a void variable has been declared and raise an error message for such a case
|
||||
//
|
||||
// returns true in case of an error
|
||||
|
|
@ -2337,7 +2412,7 @@ void TParseContext::boolCheck(const TSourceLoc& loc, const TPublicType& pType)
|
|||
error(loc, "boolean expression expected", "", "");
|
||||
}
|
||||
|
||||
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier)
|
||||
void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const TString& identifier, TIntermTyped* /*initializer*/)
|
||||
{
|
||||
if (type.getQualifier().storage == EvqUniform)
|
||||
return;
|
||||
|
|
@ -2345,6 +2420,9 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const
|
|||
if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler))
|
||||
error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) {
|
||||
// non-uniform sampler
|
||||
// not yet: okay if it has an initializer
|
||||
// if (! initializer)
|
||||
error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -2360,6 +2438,19 @@ void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, co
|
|||
error(loc, "atomic_uints can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str());
|
||||
}
|
||||
|
||||
void TParseContext::transparentCheck(const TSourceLoc& loc, const TType& type, const TString& /*identifier*/)
|
||||
{
|
||||
// double standard due to gl_NumSamples
|
||||
if (parsingBuiltins)
|
||||
return;
|
||||
|
||||
// Vulkan doesn't allow transparent uniforms outside of blocks
|
||||
if (vulkan == 0 || type.getQualifier().storage != EvqUniform)
|
||||
return;
|
||||
if (type.containsNonOpaque())
|
||||
vulkanRemoved(loc, "non-opaque uniforms outside a block");
|
||||
}
|
||||
|
||||
//
|
||||
// Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level.
|
||||
//
|
||||
|
|
@ -2605,6 +2696,7 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
|
|||
MERGE_SINGLETON(restrict);
|
||||
MERGE_SINGLETON(readonly);
|
||||
MERGE_SINGLETON(writeonly);
|
||||
MERGE_SINGLETON(specConstant);
|
||||
|
||||
if (repeated)
|
||||
error(loc, "replicated qualifiers", "", "");
|
||||
|
|
@ -2707,22 +2799,35 @@ bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType bas
|
|||
//
|
||||
// Do size checking for an array type's size.
|
||||
//
|
||||
void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, int& size)
|
||||
void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair)
|
||||
{
|
||||
TIntermConstantUnion* constant = expr->getAsConstantUnion();
|
||||
if (constant == nullptr || (constant->getBasicType() != EbtInt && constant->getBasicType() != EbtUint)) {
|
||||
error(loc, "array size must be a constant integer expression", "", "");
|
||||
size = 1;
|
||||
bool isConst = false;
|
||||
sizePair.size = 1;
|
||||
sizePair.node = nullptr;
|
||||
|
||||
TIntermConstantUnion* constant = expr->getAsConstantUnion();
|
||||
if (constant) {
|
||||
// handle true (non-specialization) constant
|
||||
sizePair.size = constant->getConstArray()[0].getIConst();
|
||||
isConst = true;
|
||||
} else {
|
||||
// see if it's a specialization constant instead
|
||||
if (expr->getQualifier().isSpecConstant()) {
|
||||
isConst = true;
|
||||
sizePair.node = expr;
|
||||
TIntermSymbol* symbol = expr->getAsSymbolNode();
|
||||
if (symbol && symbol->getConstArray().size() > 0)
|
||||
sizePair.size = symbol->getConstArray()[0].getIConst();
|
||||
}
|
||||
}
|
||||
|
||||
if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
|
||||
error(loc, "array size must be a constant integer expression", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
size = constant->getConstArray()[0].getIConst();
|
||||
|
||||
if (size <= 0) {
|
||||
if (sizePair.size <= 0) {
|
||||
error(loc, "array size must be a positive integer", "", "");
|
||||
size = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -3390,6 +3495,12 @@ void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const
|
|||
error(loc, "can't use with samplers or structs containing samplers", op, "");
|
||||
}
|
||||
|
||||
void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op)
|
||||
{
|
||||
if (type.containsSpecializationSize())
|
||||
error(loc, "can't use with types containing arrays sized with a specialization constant", op, "");
|
||||
}
|
||||
|
||||
void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publicType)
|
||||
{
|
||||
const TTypeList& typeList = *publicType.userDef->getStruct();
|
||||
|
|
@ -3605,10 +3716,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
return;
|
||||
}
|
||||
if (id == TQualifier::getLayoutPackingString(ElpPacked)) {
|
||||
if (vulkan > 0)
|
||||
vulkanRemoved(loc, "packed");
|
||||
publicType.qualifier.layoutPacking = ElpPacked;
|
||||
return;
|
||||
}
|
||||
if (id == TQualifier::getLayoutPackingString(ElpShared)) {
|
||||
if (vulkan > 0)
|
||||
vulkanRemoved(loc, "shared");
|
||||
publicType.qualifier.layoutPacking = ElpShared;
|
||||
return;
|
||||
}
|
||||
|
|
@ -3636,6 +3751,11 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (id == "push_constant") {
|
||||
requireVulkan(loc, "push_constant");
|
||||
publicType.qualifier.layoutPushConstant = true;
|
||||
return;
|
||||
}
|
||||
if (language == EShLangGeometry || language == EShLangTessEvaluation) {
|
||||
if (id == TQualifier::getGeometryString(ElgTriangles)) {
|
||||
publicType.shaderQualifiers.geometry = ElgTriangles;
|
||||
|
|
@ -3874,6 +3994,27 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
}
|
||||
}
|
||||
|
||||
if (id == "input_attachment_index") {
|
||||
requireVulkan(loc, "input_attachment_index");
|
||||
if (value >= (int)TQualifier::layoutAttachmentEnd)
|
||||
error(loc, "attachment index is too large", id.c_str(), "");
|
||||
else
|
||||
publicType.qualifier.layoutAttachment = value;
|
||||
return;
|
||||
}
|
||||
if (id == "constant_id") {
|
||||
requireSpv(loc, "constant_id");
|
||||
if (value >= (int)TQualifier::layoutSpecConstantIdEnd) {
|
||||
error(loc, "specialization-constant id is too large", id.c_str(), "");
|
||||
} else {
|
||||
publicType.qualifier.layoutSpecConstantId = value;
|
||||
publicType.qualifier.specConstant = true;
|
||||
if (! intermediate.addUsedConstantId(value))
|
||||
error(loc, "specialization-constant id already used", id.c_str(), "");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (language) {
|
||||
case EShLangVertex:
|
||||
break;
|
||||
|
|
@ -3924,17 +4065,33 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
if (id == "local_size_x") {
|
||||
publicType.shaderQualifiers.localSize[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y") {
|
||||
publicType.shaderQualifiers.localSize[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z") {
|
||||
publicType.shaderQualifiers.localSize[2] = value;
|
||||
return;
|
||||
if (id.compare(0, 11, "local_size_") == 0) {
|
||||
if (id == "local_size_x") {
|
||||
publicType.shaderQualifiers.localSize[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y") {
|
||||
publicType.shaderQualifiers.localSize[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z") {
|
||||
publicType.shaderQualifiers.localSize[2] = value;
|
||||
return;
|
||||
}
|
||||
if (spv > 0) {
|
||||
if (id == "local_size_x_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[0] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_y_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[1] = value;
|
||||
return;
|
||||
}
|
||||
if (id == "local_size_z_id") {
|
||||
publicType.shaderQualifiers.localSizeSpecId[2] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -3999,6 +4156,13 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie
|
|||
dst.layoutXfbStride = src.layoutXfbStride;
|
||||
if (src.hasXfbOffset())
|
||||
dst.layoutXfbOffset = src.layoutXfbOffset;
|
||||
if (src.hasAttachment())
|
||||
dst.layoutAttachment = src.layoutAttachment;
|
||||
if (src.hasSpecConstantId())
|
||||
dst.layoutSpecConstantId = src.layoutSpecConstantId;
|
||||
|
||||
if (src.layoutPushConstant)
|
||||
dst.layoutPushConstant = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4041,6 +4205,8 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
|
|||
// "The align qualifier can only be used on blocks or block members..."
|
||||
if (qualifier.hasAlign())
|
||||
error(loc, "cannot specify on a variable declaration", "align", "");
|
||||
if (qualifier.layoutPushConstant)
|
||||
error(loc, "can only specify on a uniform block", "push_constant", "");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -4055,7 +4221,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
{
|
||||
const TQualifier& qualifier = type.getQualifier();
|
||||
|
||||
// first, intra layout qualifier-only error checking
|
||||
// first, intra-layout qualifier-only error checking
|
||||
layoutQualifierCheck(loc, qualifier);
|
||||
|
||||
// now, error checking combining type and qualifier
|
||||
|
|
@ -4087,7 +4253,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
case EvqBuffer:
|
||||
break;
|
||||
default:
|
||||
error(loc, "can only appy to uniform, buffer, in, or out storage qualifiers", "location", "");
|
||||
error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", "");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4181,6 +4347,38 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
}
|
||||
} else if (type.isImage() && ! qualifier.writeonly)
|
||||
error(loc, "image variables not declared 'writeonly' must have a format layout qualifier", "", "");
|
||||
|
||||
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
|
||||
error(loc, "can only be used with a block", "push_constant", "");
|
||||
|
||||
// input attachment
|
||||
if (type.isSubpass()) {
|
||||
if (! qualifier.hasAttachment())
|
||||
error(loc, "requires an input_attachment_index layout qualifier", "subpass", "");
|
||||
} else {
|
||||
if (qualifier.hasAttachment())
|
||||
error(loc, "can only be used with a subpass", "input_attachment_index", "");
|
||||
}
|
||||
|
||||
// specialization-constant id
|
||||
if (qualifier.hasSpecConstantId()) {
|
||||
if (type.getQualifier().storage != EvqConst)
|
||||
error(loc, "can only be applied to 'const'-qualified scalar", "constant_id", "");
|
||||
if (! type.isScalar())
|
||||
error(loc, "can only be applied to a scalar", "constant_id", "");
|
||||
switch (type.getBasicType())
|
||||
{
|
||||
case EbtInt:
|
||||
case EbtUint:
|
||||
case EbtBool:
|
||||
case EbtFloat:
|
||||
case EbtDouble:
|
||||
break;
|
||||
default:
|
||||
error(loc, "cannot be applied to this type", "constant_id", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do layout error checking that can be done within a layout qualifier proper, not needing to know
|
||||
|
|
@ -4275,6 +4473,10 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|||
error(loc, "offset/align can only be used on a uniform or buffer", "layout", "");
|
||||
}
|
||||
}
|
||||
if (qualifier.layoutPushConstant) {
|
||||
if (qualifier.storage != EvqUniform)
|
||||
error(loc, "can only be used with a uniform", "push_constant", "");
|
||||
}
|
||||
}
|
||||
|
||||
// For places that can't have shader-level layout qualifiers
|
||||
|
|
@ -4297,6 +4499,8 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua
|
|||
for (int i = 0; i < 3; ++i) {
|
||||
if (shaderQualifiers.localSize[i] > 1)
|
||||
error(loc, message, "local_size", "");
|
||||
if (shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet)
|
||||
error(loc, message, "local_size id", "");
|
||||
}
|
||||
if (shaderQualifiers.blendEquation)
|
||||
error(loc, message, "blend equation", "");
|
||||
|
|
@ -4490,8 +4694,9 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|||
else
|
||||
nonInitConstCheck(loc, identifier, type);
|
||||
|
||||
samplerCheck(loc, type, identifier);
|
||||
samplerCheck(loc, type, identifier, initializer);
|
||||
atomicUintCheck(loc, type, identifier);
|
||||
transparentCheck(loc, type, identifier);
|
||||
|
||||
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
|
||||
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
|
||||
|
|
@ -4690,7 +4895,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
}
|
||||
|
||||
if (qualifier == EvqConst || qualifier == EvqUniform) {
|
||||
// Compile-time tagging of the variable with it's constant value...
|
||||
// Compile-time tagging of the variable with its constant value...
|
||||
|
||||
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
|
||||
if (! initializer || ! initializer->getAsConstantUnion() || variable->getType() != initializer->getType()) {
|
||||
|
|
@ -4703,6 +4908,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
|
||||
} else {
|
||||
// normal assigning of a value to a variable...
|
||||
specializationCheck(loc, initializer->getType(), "initializer");
|
||||
TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
|
||||
TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
|
||||
if (! initNode)
|
||||
|
|
@ -4716,7 +4922,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
|
|||
|
||||
//
|
||||
// Reprocess any initializer-list { ... } parts of the initializer.
|
||||
// Need to heirarchically assign correct types and implicit
|
||||
// Need to hierarchically assign correct types and implicit
|
||||
// conversions. Will do this mimicking the same process used for
|
||||
// creating a constructor-style initializer, ensuring we get the
|
||||
// same form.
|
||||
|
|
@ -4811,6 +5017,11 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode*
|
|||
|
||||
TIntermAggregate* aggrNode = node->getAsAggregate();
|
||||
|
||||
// Combined texture-sampler constructors are completely semantic checked
|
||||
// in constructorTextureSamplerError()
|
||||
if (op == EOpConstructTextureSampler)
|
||||
return intermediate.setAggregateOperator(aggrNode, op, type, loc);
|
||||
|
||||
TTypeList::const_iterator memberTypes;
|
||||
if (op == EOpConstructStruct)
|
||||
memberTypes = type.getStruct()->begin();
|
||||
|
|
@ -4997,7 +5208,7 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType&
|
|||
void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
|
||||
{
|
||||
blockStageIoCheck(loc, currentBlockQualifier);
|
||||
blockQualifierCheck(loc, currentBlockQualifier);
|
||||
blockQualifierCheck(loc, currentBlockQualifier, instanceName != nullptr);
|
||||
if (arraySizes) {
|
||||
arrayUnsizedCheck(loc, currentBlockQualifier, arraySizes, false, false);
|
||||
arrayDimCheck(loc, arraySizes, 0);
|
||||
|
|
@ -5052,6 +5263,11 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
default: defaultQualification.clear(); break;
|
||||
}
|
||||
|
||||
// Special case for "push_constant uniform", which has a default of std430,
|
||||
// contrary to normal uniform defaults, and can't have a default tracked for it.
|
||||
if (currentBlockQualifier.layoutPushConstant && !currentBlockQualifier.hasPacking())
|
||||
currentBlockQualifier.layoutPacking = ElpStd430;
|
||||
|
||||
// fix and check for member layout qualifiers
|
||||
|
||||
mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
|
||||
|
|
@ -5197,7 +5413,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
case EvqUniform:
|
||||
profileRequires(loc, EEsProfile, 300, nullptr, "uniform block");
|
||||
profileRequires(loc, ENoProfile, 140, nullptr, "uniform block");
|
||||
if (currentBlockQualifier.layoutPacking == ElpStd430)
|
||||
if (currentBlockQualifier.layoutPacking == ElpStd430 && ! currentBlockQualifier.layoutPushConstant)
|
||||
error(loc, "requires the 'buffer' storage qualifier", "std430", "");
|
||||
break;
|
||||
case EvqBuffer:
|
||||
|
|
@ -5227,7 +5443,7 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
}
|
||||
|
||||
// Do all block-declaration checking regarding its qualifers.
|
||||
void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier)
|
||||
void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier, bool instanceName)
|
||||
{
|
||||
// The 4.5 specification says:
|
||||
//
|
||||
|
|
@ -5254,6 +5470,11 @@ void TParseContext::blockQualifierCheck(const TSourceLoc& loc, const TQualifier&
|
|||
error(loc, "cannot use sample qualifier on an interface block", "sample", "");
|
||||
if (qualifier.invariant)
|
||||
error(loc, "cannot use invariant qualifier on an interface block", "invariant", "");
|
||||
if (qualifier.layoutPushConstant) {
|
||||
intermediate.addPushConstantCount();
|
||||
if (! instanceName)
|
||||
error(loc, "requires an instance name", "push_constant", "");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -5541,16 +5762,22 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", "");
|
||||
|
||||
// Fix the existing constant gl_WorkGroupSize with this new information.
|
||||
bool builtIn;
|
||||
TSymbol* symbol = symbolTable.find("gl_WorkGroupSize", &builtIn);
|
||||
if (builtIn)
|
||||
makeEditable(symbol);
|
||||
TVariable* workGroupSize = symbol->getAsVariable();
|
||||
TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
|
||||
workGroupSize->getWritableConstArray()[i].setUConst(intermediate.getLocalSize(i));
|
||||
}
|
||||
} else
|
||||
error(loc, "can only apply to 'in'", "local_size", "");
|
||||
}
|
||||
if (publicType.shaderQualifiers.localSizeSpecId[i] != TQualifier::layoutNotSet) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn) {
|
||||
if (! intermediate.setLocalSizeSpecId(i, publicType.shaderQualifiers.localSizeSpecId[i]))
|
||||
error(loc, "cannot change previously set size", "local_size", "");
|
||||
} else
|
||||
error(loc, "can only apply to 'in'", "local_size id", "");
|
||||
// Set the workgroup built-in variable as a specialization constant
|
||||
TVariable* workGroupSize = getEditableVariable("gl_WorkGroupSize");
|
||||
workGroupSize->getWritableType().getQualifier().specConstant = true;
|
||||
}
|
||||
}
|
||||
if (publicType.shaderQualifiers.earlyFragmentTests) {
|
||||
if (publicType.qualifier.storage == EvqVaryingIn)
|
||||
|
|
@ -5614,6 +5841,10 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
error(loc, "cannot declare a default, use a full declaration", "location/component/index", "");
|
||||
if (qualifier.hasXfbOffset())
|
||||
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
|
||||
if (qualifier.layoutPushConstant)
|
||||
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
|
||||
if (qualifier.hasSpecConstantId())
|
||||
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue