|
@@ -428,8 +428,18 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|
|
#ifndef GLSLANG_WEB
|
|
#ifndef GLSLANG_WEB
|
|
|
if (base->isReference() && ! base->isArray()) {
|
|
if (base->isReference() && ! base->isArray()) {
|
|
|
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing");
|
|
requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing");
|
|
|
- result = intermediate.addBinaryMath(EOpAdd, base, index, loc);
|
|
|
|
|
- result->setType(base->getType());
|
|
|
|
|
|
|
+ if (base->getType().getReferentType()->containsUnsizedArray()) {
|
|
|
|
|
+ error(loc, "cannot index reference to buffer containing an unsized array", "", "");
|
|
|
|
|
+ result = nullptr;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ result = intermediate.addBinaryMath(EOpAdd, base, index, loc);
|
|
|
|
|
+ if (result != nullptr)
|
|
|
|
|
+ result->setType(base->getType());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (result == nullptr) {
|
|
|
|
|
+ error(loc, "cannot index buffer reference", "", "");
|
|
|
|
|
+ result = intermediate.addConstantUnion(0.0, EbtFloat, loc);
|
|
|
|
|
+ }
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
|
|
if (base->getAsSymbolNode() && isIoResizeArray(base->getType()))
|
|
@@ -822,50 +832,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|
|
TIntermTyped* result = base;
|
|
TIntermTyped* result = base;
|
|
|
if ((base->isVector() || base->isScalar()) &&
|
|
if ((base->isVector() || base->isScalar()) &&
|
|
|
(base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) {
|
|
(base->isFloatingDomain() || base->isIntegerDomain() || base->getBasicType() == EbtBool)) {
|
|
|
- if (base->isScalar()) {
|
|
|
|
|
- const char* dotFeature = "scalar swizzle";
|
|
|
|
|
- requireProfile(loc, ~EEsProfile, dotFeature);
|
|
|
|
|
- profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- TSwizzleSelectors<TVectorSelector> selectors;
|
|
|
|
|
- parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
|
|
|
|
|
-
|
|
|
|
|
- if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
|
|
|
|
|
- requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
|
|
|
|
|
- if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt())
|
|
|
|
|
- requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16");
|
|
|
|
|
- if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt())
|
|
|
|
|
- requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
|
|
|
|
|
-
|
|
|
|
|
- if (base->isScalar()) {
|
|
|
|
|
- if (selectors.size() == 1)
|
|
|
|
|
- return result;
|
|
|
|
|
- else {
|
|
|
|
|
- TType type(base->getBasicType(), EvqTemporary, selectors.size());
|
|
|
|
|
- // Swizzle operations propagate specialization-constantness
|
|
|
|
|
- if (base->getQualifier().isSpecConstant())
|
|
|
|
|
- type.getQualifier().makeSpecConstant();
|
|
|
|
|
- return addConstructor(loc, base, type);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (base->getType().getQualifier().isFrontEndConstant())
|
|
|
|
|
- result = intermediate.foldSwizzle(base, selectors, loc);
|
|
|
|
|
- else {
|
|
|
|
|
- if (selectors.size() == 1) {
|
|
|
|
|
- TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc);
|
|
|
|
|
- result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
|
|
|
|
- result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision));
|
|
|
|
|
- } else {
|
|
|
|
|
- TIntermTyped* index = intermediate.addSwizzle(selectors, loc);
|
|
|
|
|
- result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
|
|
|
|
|
- result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size()));
|
|
|
|
|
- }
|
|
|
|
|
- // Swizzle operations propagate specialization-constantness
|
|
|
|
|
- if (base->getType().getQualifier().isSpecConstant())
|
|
|
|
|
- result->getWritableType().getQualifier().makeSpecConstant();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ result = handleDotSwizzle(loc, base, field);
|
|
|
} else if (base->isStruct() || base->isReference()) {
|
|
} else if (base->isStruct() || base->isReference()) {
|
|
|
const TTypeList* fields = base->isReference() ?
|
|
const TTypeList* fields = base->isReference() ?
|
|
|
base->getType().getReferentType()->getStruct() :
|
|
base->getType().getReferentType()->getStruct() :
|
|
@@ -906,6 +873,60 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+//
|
|
|
|
|
+// Handle seeing a base.swizzle, a subset of base.identifier in the grammar.
|
|
|
|
|
+//
|
|
|
|
|
+TIntermTyped* TParseContext::handleDotSwizzle(const TSourceLoc& loc, TIntermTyped* base, const TString& field)
|
|
|
|
|
+{
|
|
|
|
|
+ TIntermTyped* result = base;
|
|
|
|
|
+ if (base->isScalar()) {
|
|
|
|
|
+ const char* dotFeature = "scalar swizzle";
|
|
|
|
|
+ requireProfile(loc, ~EEsProfile, dotFeature);
|
|
|
|
|
+ profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, dotFeature);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ TSwizzleSelectors<TVectorSelector> selectors;
|
|
|
|
|
+ parseSwizzleSelector(loc, field, base->getVectorSize(), selectors);
|
|
|
|
|
+
|
|
|
|
|
+ if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitFloat())
|
|
|
|
|
+ requireFloat16Arithmetic(loc, ".", "can't swizzle types containing float16");
|
|
|
|
|
+ if (base->isVector() && selectors.size() != 1 && base->getType().contains16BitInt())
|
|
|
|
|
+ requireInt16Arithmetic(loc, ".", "can't swizzle types containing (u)int16");
|
|
|
|
|
+ if (base->isVector() && selectors.size() != 1 && base->getType().contains8BitInt())
|
|
|
|
|
+ requireInt8Arithmetic(loc, ".", "can't swizzle types containing (u)int8");
|
|
|
|
|
+
|
|
|
|
|
+ if (base->isScalar()) {
|
|
|
|
|
+ if (selectors.size() == 1)
|
|
|
|
|
+ return result;
|
|
|
|
|
+ else {
|
|
|
|
|
+ TType type(base->getBasicType(), EvqTemporary, selectors.size());
|
|
|
|
|
+ // Swizzle operations propagate specialization-constantness
|
|
|
|
|
+ if (base->getQualifier().isSpecConstant())
|
|
|
|
|
+ type.getQualifier().makeSpecConstant();
|
|
|
|
|
+ return addConstructor(loc, base, type);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (base->getType().getQualifier().isFrontEndConstant())
|
|
|
|
|
+ result = intermediate.foldSwizzle(base, selectors, loc);
|
|
|
|
|
+ else {
|
|
|
|
|
+ if (selectors.size() == 1) {
|
|
|
|
|
+ TIntermTyped* index = intermediate.addConstantUnion(selectors[0], loc);
|
|
|
|
|
+ result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
|
|
|
|
|
+ result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ TIntermTyped* index = intermediate.addSwizzle(selectors, loc);
|
|
|
|
|
+ result = intermediate.addIndex(EOpVectorSwizzle, base, index, loc);
|
|
|
|
|
+ result->setType(TType(base->getBasicType(), EvqTemporary, base->getType().getQualifier().precision, selectors.size()));
|
|
|
|
|
+ }
|
|
|
|
|
+ // Swizzle operations propagate specialization-constantness
|
|
|
|
|
+ if (base->getType().getQualifier().isSpecConstant())
|
|
|
|
|
+ result->getWritableType().getQualifier().makeSpecConstant();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
|
|
void TParseContext::blockMemberExtensionCheck(const TSourceLoc& loc, const TIntermTyped* base, int member, const TString& memberName)
|
|
|
{
|
|
{
|
|
|
// a block that needs extension checking is either 'base', or if arrayed,
|
|
// a block that needs extension checking is either 'base', or if arrayed,
|
|
@@ -2198,6 +2219,28 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan
|
|
|
memorySemanticsCheck(loc, fnCandidate, callNode);
|
|
memorySemanticsCheck(loc, fnCandidate, callNode);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
+
|
|
|
|
|
+ case EOpMix:
|
|
|
|
|
+ if (profile == EEsProfile && version < 310) {
|
|
|
|
|
+ // Look for specific signatures
|
|
|
|
|
+ if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat &&
|
|
|
|
|
+ (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat &&
|
|
|
|
|
+ (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) {
|
|
|
|
|
+ requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, "specific signature of builtin mix");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (profile != EEsProfile && version < 450) {
|
|
|
|
|
+ if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat &&
|
|
|
|
|
+ (*argp)[0]->getAsTyped()->getBasicType() != EbtDouble &&
|
|
|
|
|
+ (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat &&
|
|
|
|
|
+ (*argp)[1]->getAsTyped()->getBasicType() != EbtDouble &&
|
|
|
|
|
+ (*argp)[2]->getAsTyped()->getBasicType() == EbtBool) {
|
|
|
|
|
+ requireExtensions(loc, 1, &E_GL_EXT_shader_integer_mix, fnCandidate.getName().c_str());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
default:
|
|
@@ -3354,6 +3397,11 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
|
|
|
!qualifier.hasBufferReference())
|
|
!qualifier.hasBufferReference())
|
|
|
error(loc, "buffers can be declared only as blocks", "buffer", "");
|
|
error(loc, "buffers can be declared only as blocks", "buffer", "");
|
|
|
|
|
|
|
|
|
|
+ if (qualifier.storage != EvqVaryingIn && publicType.basicType == EbtDouble &&
|
|
|
|
|
+ extensionTurnedOn(E_GL_ARB_vertex_attrib_64bit) && language == EShLangVertex &&
|
|
|
|
|
+ version < 400) {
|
|
|
|
|
+ profileRequires(loc, ECoreProfile | ECompatibilityProfile, 410, E_GL_ARB_gpu_shader_fp64, "vertex-shader `double` type");
|
|
|
|
|
+ }
|
|
|
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
|
|
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
@@ -3404,7 +3452,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali
|
|
|
profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
|
|
profileRequires(loc, ENoProfile, 150, nullptr, "vertex input arrays");
|
|
|
}
|
|
}
|
|
|
if (publicType.basicType == EbtDouble)
|
|
if (publicType.basicType == EbtDouble)
|
|
|
- profileRequires(loc, ~EEsProfile, 410, nullptr, "vertex-shader `double` type input");
|
|
|
|
|
|
|
+ profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_vertex_attrib_64bit, "vertex-shader `double` type input");
|
|
|
if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)
|
|
if (qualifier.isAuxiliary() || qualifier.isInterpolation() || qualifier.isMemory() || qualifier.invariant)
|
|
|
error(loc, "vertex input cannot be further qualified", "", "");
|
|
error(loc, "vertex input cannot be further qualified", "", "");
|
|
|
break;
|
|
break;
|
|
@@ -5385,10 +5433,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
|
|
|
|
|
|
|
|
case EShLangFragment:
|
|
case EShLangFragment:
|
|
|
if (id == "index") {
|
|
if (id == "index") {
|
|
|
- requireProfile(loc, ECompatibilityProfile | ECoreProfile, "index layout qualifier on fragment output");
|
|
|
|
|
|
|
+ requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, "index layout qualifier on fragment output");
|
|
|
const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
|
|
const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location };
|
|
|
profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output");
|
|
profileRequires(loc, ECompatibilityProfile | ECoreProfile, 330, 2, exts, "index layout qualifier on fragment output");
|
|
|
-
|
|
|
|
|
|
|
+ profileRequires(loc, EEsProfile ,310, E_GL_EXT_blend_func_extended, "index layout qualifier on fragment output");
|
|
|
// "It is also a compile-time error if a fragment shader sets a layout index to less than 0 or greater than 1."
|
|
// "It is also a compile-time error if a fragment shader sets a layout index to less than 0 or greater than 1."
|
|
|
if (value < 0 || value > 1) {
|
|
if (value < 0 || value > 1) {
|
|
|
value = 0;
|
|
value = 0;
|
|
@@ -6135,7 +6183,10 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct
|
|
|
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float32) ||
|
|
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float32) ||
|
|
|
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float64);
|
|
extensionTurnedOn(E_GL_EXT_shader_explicit_arithmetic_types_float64);
|
|
|
|
|
|
|
|
- if (isEsProfile() || version < 120)
|
|
|
|
|
|
|
+ if (isEsProfile())
|
|
|
|
|
+ function = (extensionTurnedOn(E_GL_EXT_shader_implicit_conversions) && version >= 310) ?
|
|
|
|
|
+ findFunction120(loc, call, builtIn) : findFunctionExact(loc, call, builtIn);
|
|
|
|
|
+ else if (version < 120)
|
|
|
function = findFunctionExact(loc, call, builtIn);
|
|
function = findFunctionExact(loc, call, builtIn);
|
|
|
else if (version < 400)
|
|
else if (version < 400)
|
|
|
function = extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) ? findFunction400(loc, call, builtIn) : findFunction120(loc, call, builtIn);
|
|
function = extensionTurnedOn(E_GL_ARB_gpu_shader_fp64) ? findFunction400(loc, call, builtIn) : findFunction120(loc, call, builtIn);
|