Implement GL_EXT_null_initializer

Adds null initializer syntax (empty braces)
Allows null initialization of shared variables
This commit is contained in:
John Kessenich 2020-06-11 08:30:03 -06:00 committed by Alan Baker
parent 6abdde3ce5
commit c739e03748
17 changed files with 2694 additions and 2355 deletions

View file

@ -6815,6 +6815,11 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString&
//
TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable)
{
// A null initializer is an aggregate that hasn't had an op assigned yet
// (still EOpNull, no relation to nullInit), and has no children.
bool nullInit = initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull &&
initializer->getAsAggregate()->getSequence().size() == 0;
//
// Identifier must be of type constant, a global, or a temporary, and
// starting at version 120, desktop allows uniforms to have initializers.
@ -6822,9 +6827,36 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
TStorageQualifier qualifier = variable->getType().getQualifier().storage;
if (! (qualifier == EvqTemporary || qualifier == EvqGlobal || qualifier == EvqConst ||
(qualifier == EvqUniform && !isEsProfile() && version >= 120))) {
error(loc, " cannot initialize this type of qualifier ", variable->getType().getStorageQualifierString(), "");
if (qualifier == EvqShared) {
// GL_EXT_null_initializer allows this for shared, if it's a null initializer
if (nullInit) {
const char* feature = "initialization with shared qualifier";
profileRequires(loc, EEsProfile, 0, E_GL_EXT_null_initializer, feature);
profileRequires(loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, feature);
} else {
error(loc, "initializer can only be a null initializer ('{}')", "shared", "");
}
} else {
error(loc, " cannot initialize this type of qualifier ",
variable->getType().getStorageQualifierString(), "");
return nullptr;
}
}
if (nullInit) {
// only some types can be null initialized
if (variable->getType().containsUnsizedArray()) {
error(loc, "null initializers can't size unsized arrays", "{}", "");
return nullptr;
}
if (variable->getType().containsOpaque()) {
error(loc, "null initializers can't be used on opaque values", "{}", "");
return nullptr;
}
variable->getWritableType().getQualifier().setNullInit();
return nullptr;
}
arrayObjectCheck(loc, variable->getType(), "array initializer");
//
@ -6868,13 +6900,15 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
// Uniforms require a compile-time constant initializer
if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) {
error(loc, "uniform initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
error(loc, "uniform initializers must be constant", "=", "'%s'",
variable->getType().getCompleteString().c_str());
variable->getWritableType().getQualifier().makeTemporary();
return nullptr;
}
// Global consts require a constant initializer (specialization constant is okay)
if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
error(loc, "global const initializers must be constant", "=", "'%s'", variable->getType().getCompleteString().c_str());
error(loc, "global const initializers must be constant", "=", "'%s'",
variable->getType().getCompleteString().c_str());
variable->getWritableType().getQualifier().makeTemporary();
return nullptr;
}
@ -6894,7 +6928,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
// "In declarations of global variables with no storage qualifier or with a const
// qualifier any initializer must be a constant expression."
if (symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) {
const char* initFeature = "non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
const char* initFeature =
"non-constant global initializer (needs GL_EXT_shader_non_constant_global_initializers)";
if (isEsProfile()) {
if (relaxedErrors() && ! extensionTurnedOn(E_GL_EXT_shader_non_constant_global_initializers))
warn(loc, "not allowed in this version", initFeature, "");
@ -6908,7 +6943,8 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp
// Compile-time tagging of the variable with its constant value...
initializer = intermediate.addConversion(EOpAssign, variable->getType(), initializer);
if (! initializer || ! initializer->getType().getQualifier().isConstant() || variable->getType() != initializer->getType()) {
if (! initializer || ! initializer->getType().getQualifier().isConstant() ||
variable->getType() != initializer->getType()) {
error(loc, "non-matching or non-convertible constant type for const initializer",
variable->getType().getStorageQualifierString(), "");
variable->getWritableType().getQualifier().makeTemporary();