Implement Array, Cubemap, and Volume texture types (issue #1111).

- Add love.graphics.newArrayImage, newCubeImage, and newVolumeImage.
- Add love.graphics.newCanvas(w, h, layers) and newCanvas(w, h, layers, settings). Add ‘type’ field to the settings table of newCanvas.

- Add new love.graphics.setCanvas variants: setCanvas(canvas, slice), and setCanvas(canvastable) where canvastable is in the format: {{canvas1, layer=2}, {canvas2, face=5}}

- Add Texture:getTextureType, getDepth, getLayerCount, getMipmapCount, and getFormat.

- Remove Image:getData and Image:refresh.
- Add Image:replacePixels(imagedata [, slice] [, mipmap]).

- Update Canvas:newImageData to accept a slice argument.

- Add love.image.newCubeFaces(imagedata).

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-02-20 14:58:13 -04:00
parent d70fe5cb89
commit 73fd45558b
91 changed files with 3160 additions and 2003 deletions
@@ -207,6 +207,8 @@ enum TBuiltInVariable {
EbvViewportMaskNV,
EbvSecondaryPositionNV,
EbvSecondaryViewportMaskNV,
EbvPositionPerViewNV,
EbvViewportMaskPerViewNV,
#endif
// HLSL built-ins that live only temporarily, until they get remapped
// to one of the above.
@@ -325,6 +327,8 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v)
case EbvViewportMaskNV: return "ViewportMaskNV";
case EbvSecondaryPositionNV: return "SecondaryPositionNV";
case EbvSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
case EbvPositionPerViewNV: return "PositionPerViewNV";
case EbvViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
#endif
default: return "unknown built-in variable";
}
@@ -81,12 +81,19 @@ public:
type = EbtBool;
}
void setSConst(const TString* s)
{
sConst = s;
type = EbtString;
}
int getIConst() const { return iConst; }
unsigned int getUConst() const { return uConst; }
long long getI64Const() const { return i64Const; }
unsigned long long getU64Const() const { return u64Const; }
double getDConst() const { return dConst; }
bool getBConst() const { return bConst; }
const TString* getSConst() const { return sConst; }
bool operator==(const int i) const
{
@@ -532,6 +539,7 @@ private:
unsigned long long u64Const; // used for u64vec, scalar uint64s
bool bConst; // used for bvec, scalar bools
double dConst; // used for vec, dvec, mat, dmat, scalar floats and doubles
const TString* sConst; // string constant
};
TBasicType type;
@@ -255,7 +255,7 @@ extern TPoolAllocator& GetThreadPoolAllocator();
struct TThreadMemoryPools
{
TPoolAllocator* threadPoolAllocator;
TPoolAllocator* threadPoolAllocator;
};
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
+104 -51
View File
@@ -401,8 +401,23 @@ public:
// drop qualifiers that don't belong in a temporary variable
void makeTemporary()
{
storage = EvqTemporary;
builtIn = EbvNone;
storage = EvqTemporary;
builtIn = EbvNone;
clearInterstage();
clearMemory();
specConstant = false;
clearLayout();
}
void clearInterstage()
{
clearInterpolation();
patch = false;
sample = false;
}
void clearInterpolation()
{
centroid = false;
smooth = false;
flat = false;
@@ -410,15 +425,15 @@ public:
#ifdef AMD_EXTENSIONS
explicitInterp = false;
#endif
patch = false;
sample = false;
}
void clearMemory()
{
coherent = false;
volatil = false;
restrict = false;
readonly = false;
writeonly = false;
specConstant = false;
clearLayout();
}
// Drop just the storage qualification, which perhaps should
@@ -575,42 +590,47 @@ public:
}
// Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield
void clearLayout()
void clearLayout() // all layout
{
layoutMatrix = ElmNone;
layoutPacking = ElpNone;
layoutOffset = layoutNotSet;
layoutAlign = layoutNotSet;
layoutLocation = layoutLocationEnd;
layoutComponent = layoutComponentEnd;
layoutSet = layoutSetEnd;
layoutBinding = layoutBindingEnd;
layoutIndex = layoutIndexEnd;
layoutStream = layoutStreamEnd;
layoutXfbBuffer = layoutXfbBufferEnd;
layoutXfbStride = layoutXfbStrideEnd;
layoutXfbOffset = layoutXfbOffsetEnd;
layoutAttachment = layoutAttachmentEnd;
layoutSpecConstantId = layoutSpecConstantIdEnd;
layoutFormat = ElfNone;
clearUniformLayout();
layoutPushConstant = false;
#ifdef NV_EXTENSIONS
layoutPassthrough = false;
layoutViewportRelative = false;
// -2048 as the default vaule indicating layoutSecondaryViewportRelative is not set
// -2048 as the default value indicating layoutSecondaryViewportRelative is not set
layoutSecondaryViewportRelativeOffset = -2048;
#endif
clearInterstageLayout();
layoutSpecConstantId = layoutSpecConstantIdEnd;
layoutFormat = ElfNone;
}
void clearInterstageLayout()
{
layoutLocation = layoutLocationEnd;
layoutComponent = layoutComponentEnd;
layoutIndex = layoutIndexEnd;
clearStreamLayout();
clearXfbLayout();
}
void clearStreamLayout()
{
layoutStream = layoutStreamEnd;
}
void clearXfbLayout()
{
layoutXfbBuffer = layoutXfbBufferEnd;
layoutXfbStride = layoutXfbStrideEnd;
layoutXfbOffset = layoutXfbOffsetEnd;
}
bool hasLayout() const
{
return hasUniformLayout() ||
hasAnyLocation() ||
hasBinding() ||
hasStream() ||
hasXfb() ||
hasFormat() ||
@@ -670,8 +690,21 @@ public:
hasPacking() ||
hasOffset() ||
hasBinding() ||
hasSet() ||
hasAlign();
}
void clearUniformLayout() // only uniform specific
{
layoutMatrix = ElmNone;
layoutPacking = ElpNone;
layoutOffset = layoutNotSet;
layoutAlign = layoutNotSet;
layoutSet = layoutSetEnd;
layoutBinding = layoutBindingEnd;
layoutAttachment = layoutAttachmentEnd;
}
bool hasMatrix() const
{
return layoutMatrix != ElmNone;
@@ -1202,30 +1235,11 @@ public:
typeName = copyOf.typeName;
}
// Make complete copy of the whole type graph rooted at 'copyOf'.
void deepCopy(const TType& copyOf)
{
shallowCopy(copyOf);
if (copyOf.arraySizes) {
arraySizes = new TArraySizes;
*arraySizes = *copyOf.arraySizes;
}
if (copyOf.structure) {
structure = new TTypeList;
for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
TTypeLoc typeLoc;
typeLoc.loc = (*copyOf.structure)[i].loc;
typeLoc.type = new TType();
typeLoc.type->deepCopy(*(*copyOf.structure)[i].type);
structure->push_back(typeLoc);
}
}
if (copyOf.fieldName)
fieldName = NewPoolTString(copyOf.fieldName->c_str());
if (copyOf.typeName)
typeName = NewPoolTString(copyOf.typeName->c_str());
TMap<TTypeList*,TTypeList*> copied; // to enable copying a type graph as a graph, not a tree
deepCopy(copyOf, copied);
}
// Recursively make temporary
@@ -1346,6 +1360,8 @@ public:
case EbvViewportMaskNV:
case EbvSecondaryPositionNV:
case EbvSecondaryViewportMaskNV:
case EbvPositionPerViewNV:
case EbvViewportMaskPerViewNV:
#endif
return true;
default:
@@ -1720,6 +1736,7 @@ public:
const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
const TTypeList* getStruct() const { return structure; }
void setStruct(TTypeList* s) { structure = s; }
TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads
int computeNumComponents() const
@@ -1830,6 +1847,42 @@ protected:
TType(const TType& type);
TType& operator=(const TType& type);
// Recursively copy a type graph, while preserving the graph-like
// quality. That is, don't make more than one copy of a structure that
// gets reused multiple times in the type graph.
void deepCopy(const TType& copyOf, TMap<TTypeList*,TTypeList*>& copiedMap)
{
shallowCopy(copyOf);
if (copyOf.arraySizes) {
arraySizes = new TArraySizes;
*arraySizes = *copyOf.arraySizes;
}
if (copyOf.structure) {
auto prevCopy = copiedMap.find(copyOf.structure);
if (prevCopy != copiedMap.end())
structure = prevCopy->second;
else {
structure = new TTypeList;
copiedMap[copyOf.structure] = structure;
for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
TTypeLoc typeLoc;
typeLoc.loc = (*copyOf.structure)[i].loc;
typeLoc.type = new TType();
typeLoc.type->deepCopy(*(*copyOf.structure)[i].type, copiedMap);
structure->push_back(typeLoc);
}
}
}
if (copyOf.fieldName)
fieldName = NewPoolTString(copyOf.fieldName->c_str());
if (copyOf.typeName)
typeName = NewPoolTString(copyOf.typeName->c_str());
}
void buildMangledName(TString&);
TBasicType basicType : 8;
@@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1773"
#define GLSLANG_DATE "19-Jan-2017"
#define GLSLANG_REVISION "Overload400-PrecQual.1843"
#define GLSLANG_DATE "18-Feb-2017"
@@ -1292,6 +1292,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 textureCube(samplerCube, vec3);"
"vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array
"\n");
}
}
@@ -1317,6 +1319,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 shadow2DRect(sampler2DRectShadow, vec3);" // GL_ARB_texture_rectangle, caught by keyword check
"vec4 shadow2DRectProj(sampler2DRectShadow, vec4);" // GL_ARB_texture_rectangle, caught by keyword check
"vec4 texture1DArray(sampler1DArray, vec2);" // GL_EXT_texture_array
"vec4 shadow1DArray(sampler1DArrayShadow, vec3);" // GL_EXT_texture_array
"vec4 shadow2DArray(sampler2DArrayShadow, vec4);" // GL_EXT_texture_array
"\n");
}
}
@@ -2646,6 +2652,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 texture3DProjLod(sampler3D, vec4, float);" // GL_ARB_shader_texture_lod // OES_texture_3D, but caught by keyword check
"vec4 textureCubeLod(samplerCube, vec3, float);" // GL_ARB_shader_texture_lod
"vec4 texture2DArrayLod(sampler2DArray, vec3, float);" // GL_EXT_texture_array
"\n");
}
}
@@ -2681,6 +2689,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 shadow2DRectGradARB( sampler2DRectShadow, vec3, vec2, vec2);" // GL_ARB_shader_texture_lod
"vec4 shadow2DRectProjGradARB(sampler2DRectShadow, vec4, vec2, vec2);" // GL_ARB_shader_texture_lod
"vec4 texture1DArrayLod(sampler1DArray, vec2, float);" // GL_EXT_texture_array
"vec4 shadow1DArrayLod(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array
"vec4 shadow2DArrayLod(sampler2DArrayShadow, vec4, float);" // GL_EXT_texture_array
"\n");
}
}
@@ -2752,6 +2764,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 texture3D(sampler3D, vec3, float);" // OES_texture_3D
"vec4 texture3DProj(sampler3D, vec4, float);" // OES_texture_3D
"vec4 textureCube(samplerCube, vec3, float);"
"vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array
"\n");
}
@@ -2764,7 +2777,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"vec4 shadow2D(sampler2DShadow, vec3, float);"
"vec4 shadow1DProj(sampler1DShadow, vec4, float);"
"vec4 shadow2DProj(sampler2DShadow, vec4, float);"
"vec4 texture1DArray(sampler1DArray, vec2, float);" // GL_EXT_texture_array
"vec4 shadow1DArray(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array
"vec4 shadow2DArray(sampler2DArrayShadow, vec4, float);" // GL_EXT_texture_array
"\n");
}
if (spvVersion.spv == 0 && profile == EEsProfile) {
@@ -3249,6 +3264,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"out int gl_ViewportMask[];"
"out int gl_SecondaryViewportMaskNV[];"
"out vec4 gl_SecondaryPositionNV;"
"out vec4 gl_PositionPerViewNV[];"
"out int gl_ViewportMaskPerViewNV[];"
);
#endif
@@ -3313,6 +3330,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
"float gl_CullDistance[];"
#ifdef NV_EXTENSIONS
"vec4 gl_SecondaryPositionNV;"
"vec4 gl_PositionPerViewNV[];"
#endif
);
stageBuiltins[EShLangGeometry].append(
@@ -3362,9 +3380,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
#ifdef NV_EXTENSIONS
if (version >= 450)
stageBuiltins[EShLangGeometry].append(
"out int gl_ViewportMask[];"
"out int gl_SecondaryViewportMaskNV[];"
"out vec4 gl_SecondaryPositionNV;"
"out int gl_ViewportMask[];"
"out int gl_SecondaryViewportMaskNV[];"
"out vec4 gl_SecondaryPositionNV;"
"out vec4 gl_PositionPerViewNV[];"
"out int gl_ViewportMaskPerViewNV[];"
);
#endif
@@ -3424,11 +3444,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
stageBuiltins[EShLangTessControl].append(
"float gl_CullDistance[];"
#ifdef NV_EXTENSIONS
"int gl_ViewportIndex;"
"int gl_Layer;"
"int gl_ViewportMask[];"
"int gl_ViewportIndex;"
"int gl_Layer;"
"int gl_ViewportMask[];"
"vec4 gl_SecondaryPositionNV;"
"int gl_SecondaryViewportMaskNV[];"
"int gl_SecondaryViewportMaskNV[];"
"vec4 gl_PositionPerViewNV[];"
"int gl_ViewportMaskPerViewNV[];"
#endif
);
stageBuiltins[EShLangTessControl].append(
@@ -3503,11 +3525,13 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV
#ifdef NV_EXTENSIONS
if (version >= 450)
stageBuiltins[EShLangTessEvaluation].append(
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"out int gl_ViewportMask[];"
"out int gl_ViewportIndex;"
"out int gl_Layer;"
"out int gl_ViewportMask[];"
"out vec4 gl_SecondaryPositionNV;"
"out int gl_SecondaryViewportMaskNV[];"
"out int gl_SecondaryViewportMaskNV[];"
"out vec4 gl_PositionPerViewNV[];"
"out int gl_ViewportMaskPerViewNV[];"
);
#endif
@@ -4203,7 +4227,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, TString& typeName, int ve
// Add to the per-language set of built-ins
if (bias)
if (bias || lodClamp)
stageBuiltins[EShLangFragment].append(s);
else
commonBuiltins.append(s);
@@ -4446,6 +4470,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
"highp float gl_PointSize;"
#ifdef NV_EXTENSIONS
"highp vec4 gl_SecondaryPositionNV;"
"highp vec4 gl_PositionPerViewNV[];"
#endif
"} gl_in[gl_MaxPatchVertices];"
"\n");
@@ -4635,6 +4660,7 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
"float gl_CullDistance[];"
#ifdef NV_EXTENSIONS
"vec4 gl_SecondaryPositionNV;"
"vec4 gl_PositionPerViewNV[];"
#endif
);
s.append(
@@ -5033,19 +5059,26 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setVariableExtensions("gl_ViewportMask", 1, &E_GL_NV_viewport_array2);
symbolTable.setVariableExtensions("gl_SecondaryPositionNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_SecondaryViewportMaskNV", 1, &E_GL_NV_stereo_view_rendering);
symbolTable.setVariableExtensions("gl_PositionPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes);
symbolTable.setVariableExtensions("gl_ViewportMaskPerViewNV", 1, &E_GL_NVX_multiview_per_view_attributes);
BuiltInVariable("gl_ViewportMask", EbvViewportMaskNV, symbolTable);
BuiltInVariable("gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
BuiltInVariable("gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
BuiltInVariable("gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
if (language != EShLangVertex)
if (language != EShLangVertex) {
BuiltInVariable("gl_in", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_in", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
}
BuiltInVariable("gl_out", "gl_Layer", EbvLayer, symbolTable);
BuiltInVariable("gl_out", "gl_ViewportIndex", EbvViewportIndex, symbolTable);
BuiltInVariable("gl_out", "gl_ViewportMask", EbvViewportMaskNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryPositionNV", EbvSecondaryPositionNV, symbolTable);
BuiltInVariable("gl_out", "gl_SecondaryViewportMaskNV", EbvSecondaryViewportMaskNV, symbolTable);
BuiltInVariable("gl_out", "gl_PositionPerViewNV", EbvPositionPerViewNV, symbolTable);
BuiltInVariable("gl_out", "gl_ViewportMaskPerViewNV", EbvViewportMaskPerViewNV, symbolTable);
#endif
BuiltInVariable("gl_PatchVerticesIn", EbvPatchVertices, symbolTable);
@@ -5197,6 +5230,27 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.setFunctionExtensions("shadow2DRectProjGradARB", 1, &E_GL_ARB_shader_texture_lod);
}
// E_GL_EXT_texture_array
if (spvVersion.spv == 0) {
symbolTable.setFunctionExtensions("texture2DArray", 1, &E_GL_EXT_texture_array);
}
if (profile != EEsProfile && spvVersion.spv == 0) {
int nLodExtensions = 2;
const char *lodExtensions[] = {E_GL_EXT_texture_array, E_GL_ARB_shader_texture_lod};
if (version >= 130)
nLodExtensions = 1;
symbolTable.setFunctionExtensions("texture1DArray", 1, &E_GL_EXT_texture_array);
symbolTable.setFunctionExtensions("shadow1DArray", 1, &E_GL_EXT_texture_array);
symbolTable.setFunctionExtensions("shadow2DArray", 1, &E_GL_EXT_texture_array);
symbolTable.setFunctionExtensions("texture1DArrayLod", nLodExtensions, lodExtensions);
symbolTable.setFunctionExtensions("texture2DArrayLod", nLodExtensions, lodExtensions);
symbolTable.setFunctionExtensions("shadow1DArrayLod", nLodExtensions, lodExtensions);
symbolTable.setFunctionExtensions("shadow2DArrayLod", nLodExtensions, lodExtensions);
}
// E_GL_ARB_shader_image_load_store
if (profile != EEsProfile && version < 420)
symbolTable.setFunctionExtensions("memoryBarrier", 1, &E_GL_ARB_shader_image_load_store);
@@ -5555,6 +5609,15 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion
symbolTable.relateToOperator("texture2DProjLod", EOpTextureProjLod);
symbolTable.relateToOperator("texture2DProjLodEXT", EOpTextureProjLod);
symbolTable.relateToOperator("texture1DArray", EOpTexture);
symbolTable.relateToOperator("texture2DArray", EOpTexture);
symbolTable.relateToOperator("shadow1DArray", EOpTexture);
symbolTable.relateToOperator("shadow2DArray", EOpTexture);
symbolTable.relateToOperator("texture1DArrayLod", EOpTextureLod);
symbolTable.relateToOperator("texture2DArrayLod", EOpTextureLod);
symbolTable.relateToOperator("shadow1DArrayLod", EOpTextureLod);
symbolTable.relateToOperator("shadow2DArrayLod", EOpTextureLod);
symbolTable.relateToOperator("texture3D", EOpTexture);
symbolTable.relateToOperator("texture3DGradARB", EOpTextureGrad);
symbolTable.relateToOperator("texture3DProj", EOpTextureProj);
@@ -155,14 +155,10 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
return folded;
}
// If either is a specialization constant, while the other is
// a constant (or specialization constant), the result is still
// a specialization constant, if the operation is an allowed
// specialization-constant operation.
if (( left->getType().getQualifier().isSpecConstant() && right->getType().getQualifier().isConstant()) ||
(right->getType().getQualifier().isSpecConstant() && left->getType().getQualifier().isConstant()))
if (isSpecializationOperation(*node))
node->getWritableType().getQualifier().makeSpecConstant();
// If can propagate spec-constantness and if the operation is an allowed
// specialization-constant operation, make a spec-constant.
if (specConstantPropagates(*left, *right) && isSpecializationOperation(*node))
node->getWritableType().getQualifier().makeSpecConstant();
return node;
}
@@ -1232,7 +1228,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
//
// Returns the selection node created.
//
TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
{
//
// Don't prune the false path for compile-time constants; it's needed
@@ -1277,10 +1273,19 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
// a true path, and a false path. The two paths are specified
// as separate parameters.
//
// Specialization constant operations include
// - The ternary operator ( ? : )
//
// Returns the selection node created, or nullptr if one could not be.
//
TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc)
{
// If it's void, go to the if-then-else selection()
if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
TIntermNodePair pair = { trueBlock, falseBlock };
return addSelection(cond, pair, loc);
}
//
// Get compatible types.
//
@@ -1314,10 +1319,16 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
// Make a selection node.
//
TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
node->getQualifier().makeTemporary();
node->setLoc(loc);
node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
if ((cond->getQualifier().isConstant() && specConstantPropagates(*trueBlock, *falseBlock)) ||
(cond->getQualifier().isSpecConstant() && trueBlock->getQualifier().isConstant() &&
falseBlock->getQualifier().isConstant()))
node->getQualifier().makeSpecConstant();
else
node->getQualifier().makeTemporary();
return node;
}
@@ -1392,6 +1403,14 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT
return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
}
TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const
{
TConstUnionArray unionArray(1);
unionArray[0].setSConst(s);
return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal);
}
// Put vector swizzle selectors onto the given sequence
void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
{
@@ -2639,4 +2658,13 @@ void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
*pragmaTable = pTable;
}
// If either node is a specialization constant, while the other is
// a constant (or specialization constant), the result is still
// a specialization constant.
bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TIntermTyped& node2)
{
return (node1.getType().getQualifier().isSpecConstant() && node2.getType().getQualifier().isConstant()) ||
(node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant());
}
} // end namespace glslang
@@ -223,20 +223,11 @@ void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op,
error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str());
}
// Add a linkage symbol node for 'symbol', which
// must have its type fully edited, as this will snapshot the type.
// It is okay if symbol becomes invalid before finish().
void TParseContextBase::trackLinkage(TSymbol& symbol)
{
if (!parsingBuiltins)
intermediate.addSymbolLinkageNode(linkage, symbol);
}
// Add 'symbol' to the list of deferred linkage symbols, which
// are later processed in finish(), at which point the symbol
// must still be valid.
// It is okay if the symbol's type will be subsequently edited.
void TParseContextBase::trackLinkageDeferred(TSymbol& symbol)
void TParseContextBase::trackLinkage(TSymbol& symbol)
{
if (!parsingBuiltins)
linkageSymbols.push_back(&symbol);
@@ -253,7 +244,7 @@ void TParseContextBase::makeEditable(TSymbol*& symbol)
// Save it (deferred, so it can be edited first) in the AST for linker use.
if (symbol)
trackLinkageDeferred(*symbol);
trackLinkage(*symbol);
}
// Return a writable version of the variable 'name'.
@@ -539,7 +530,7 @@ void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TStrin
// Make the passed-in variable information become a member of the
// global uniform block. If this doesn't exist yet, make it.
//
void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName)
void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberType, TString& memberName, TTypeList* typeList)
{
// make the global block, if not yet made
if (globalUniformBlock == nullptr) {
@@ -557,6 +548,8 @@ void TParseContextBase::growGlobalUniformBlock(TSourceLoc& loc, TType& memberTyp
TType* type = new TType;
type->shallowCopy(memberType);
type->setFieldName(memberName);
if (typeList)
type->setStruct(typeList);
TTypeLoc typeLoc = {type, loc};
globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc);
}
@@ -577,7 +570,7 @@ bool TParseContextBase::insertGlobalUniformBlock()
// This is the first request; we need a normal symbol table insert
inserted = symbolTable.insert(*globalUniformBlock);
if (inserted)
trackLinkageDeferred(*globalUniformBlock);
trackLinkage(*globalUniformBlock);
} else if (firstNewMember <= numMembers) {
// This is a follow-on request; we need to amend the first insert
inserted = symbolTable.amend(*globalUniformBlock, firstNewMember);
@@ -593,12 +586,14 @@ bool TParseContextBase::insertGlobalUniformBlock()
void TParseContextBase::finish()
{
if (!parsingBuiltins) {
// Transfer the linkage symbols to AST nodes
for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
intermediate.addSymbolLinkageNode(linkage, **i);
intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
}
if (parsingBuiltins)
return;
// Transfer the linkage symbols to AST nodes
TIntermAggregate* linkage = new TIntermAggregate;
for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i)
intermediate.addSymbolLinkageNode(linkage, **i);
intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable);
}
} // end namespace glslang
@@ -3009,7 +3009,7 @@ void TParseContext::declareArray(const TSourceLoc& loc, TString& identifier, con
symbol = new TVariable(&identifier, type);
symbolTable.insert(*symbol);
if (symbolTable.atGlobalLevel())
trackLinkageDeferred(*symbol);
trackLinkage(*symbol);
if (! symbolTable.atBuiltInLevel()) {
if (isIoResizeArray(type)) {
@@ -3431,9 +3431,9 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
oldType.getQualifier().layoutViewportRelative = newType.getQualifier().layoutViewportRelative;
oldType.getQualifier().layoutSecondaryViewportRelativeOffset = newType.getQualifier().layoutSecondaryViewportRelativeOffset;
}
#endif
if (oldType.isImplicitlySizedArray() && newType.isExplicitlySizedArray())
oldType.changeOuterArraySize(newType.getOuterArraySize());
#endif
// go to next member
++member;
@@ -3476,7 +3476,7 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT
fixIoArraySize(loc, block->getWritableType());
// Save it in the AST for linker use.
trackLinkageDeferred(*block);
trackLinkage(*block);
}
void TParseContext::paramCheckFix(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type)
@@ -3958,9 +3958,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
publicType.shaderQualifiers.layoutOverrideCoverage = true;
return;
}
#endif
}
#ifdef NV_EXTENSIONS
if (language == EShLangVertex ||
language == EShLangTessControl ||
language == EShLangTessEvaluation ||
@@ -3971,6 +3969,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
return;
}
}
#else
}
#endif
error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), "");
}
@@ -4008,16 +4008,20 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi
// - uniform offsets
// - atomic_uint offsets
const char* feature = "offset";
requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters };
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature);
profileRequires(loc, EEsProfile, 310, nullptr, feature);
if (spvVersion.spv == 0) {
requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, feature);
const char* exts[2] = { E_GL_ARB_enhanced_layouts, E_GL_ARB_shader_atomic_counters };
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, 2, exts, feature);
profileRequires(loc, EEsProfile, 310, nullptr, feature);
}
publicType.qualifier.layoutOffset = value;
return;
} else if (id == "align") {
const char* feature = "uniform buffer-member align";
requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
if (spvVersion.spv == 0) {
requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, feature);
}
// "The specified alignment must be a power of 2, or a compile-time error results."
if (! IsPow2(value))
error(loc, "must be a power of 2", "align", "");
@@ -4495,8 +4499,11 @@ 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", "", "");
} else if (type.isImage() && ! qualifier.writeonly) {
const char *explanation = "image variables declared 'writeonly' without a format layout qualifier";
requireProfile(loc, ECoreProfile | ECompatibilityProfile, explanation);
profileRequires(loc, ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shader_image_load_formatted, explanation);
}
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "push_constant", "");
@@ -5056,7 +5063,7 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, TString& identi
// add variable to symbol table
if (symbolTable.insert(*variable)) {
if (symbolTable.atGlobalLevel())
trackLinkageDeferred(*variable);
trackLinkage(*variable);
return variable;
}
@@ -5546,8 +5553,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
if (memberType.isArray())
arrayUnsizedCheck(memberLoc, currentBlockQualifier, &memberType.getArraySizes(), false, member == typeList.size() - 1);
if (memberQualifier.hasOffset()) {
requireProfile(memberLoc, ~EEsProfile, "offset on block member");
profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member");
if (spvVersion.spv == 0) {
requireProfile(memberLoc, ~EEsProfile, "offset on block member");
profileRequires(memberLoc, ~EEsProfile, 440, E_GL_ARB_enhanced_layouts, "offset on block member");
}
}
if (memberType.containsOpaque())
@@ -5718,7 +5727,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
fixIoArraySize(loc, variable.getWritableType());
// Save it in the AST for linker use.
trackLinkageDeferred(variable);
trackLinkage(variable);
}
// Do all block-declaration checking regarding the combination of in/out/uniform/buffer
@@ -79,9 +79,7 @@ public:
symbolTable(symbolTable),
parsingBuiltins(parsingBuiltins), scanContext(nullptr), ppContext(nullptr),
globalUniformBlock(nullptr)
{
linkage = new TIntermAggregate;
}
{ }
virtual ~TParseContextBase() { }
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
@@ -141,7 +139,7 @@ public:
// TODO: This could perhaps get its own object, but the current design doesn't work
// yet when new uniform variables are declared between function definitions, so
// this is pending getting a fully functional design.
virtual void growGlobalUniformBlock(TSourceLoc&, TType&, TString& memberName);
virtual void growGlobalUniformBlock(TSourceLoc&, TType&, TString& memberName, TTypeList* typeList = nullptr);
virtual bool insertGlobalUniformBlock();
virtual bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
@@ -183,13 +181,9 @@ protected:
const char* szExtraInfoFormat, TPrefixType prefix,
va_list args);
virtual void trackLinkage(TSymbol& symbol);
virtual void trackLinkageDeferred(TSymbol& symbol);
virtual void makeEditable(TSymbol*&);
virtual TVariable* getEditableVariable(const char* name);
virtual void finish();
private:
TIntermAggregate* linkage;
};
//
@@ -105,8 +105,8 @@ void SetThreadPoolAllocator(TPoolAllocator& poolAllocator)
TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
pageSize(growthIncrement),
alignment(allocationAlignment),
freeList(0),
inUseList(0),
freeList(nullptr),
inUseList(nullptr),
numCalls(0)
{
//
@@ -1006,7 +1006,6 @@ int TScanContext::tokenizeIdentifier()
case ISAMPLER1D:
case ISAMPLER1DARRAY:
case SAMPLER1DARRAYSHADOW:
case USAMPLER1D:
case USAMPLER1DARRAY:
afterType = true;
@@ -1017,8 +1016,6 @@ int TScanContext::tokenizeIdentifier()
case UVEC3:
case UVEC4:
case SAMPLERCUBESHADOW:
case SAMPLER2DARRAY:
case SAMPLER2DARRAYSHADOW:
case ISAMPLER2D:
case ISAMPLER3D:
case ISAMPLERCUBE:
@@ -1085,6 +1082,37 @@ int TScanContext::tokenizeIdentifier()
reservedWord();
return keyword;
case SAMPLER1DARRAY:
case SAMPLER1DARRAYSHADOW:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel())
return keyword;
else if (parseContext.profile == EEsProfile) {
if (parseContext.version >= 300)
reservedWord();
else
return identifierOrType();
} else if (parseContext.version < 130 && !parseContext.extensionTurnedOn(E_GL_EXT_texture_array)) {
if (parseContext.forwardCompatible)
parseContext.warn(loc, "using future keyword", tokenText, "");
return identifierOrType();
}
return keyword;
case SAMPLER2DARRAY:
case SAMPLER2DARRAYSHADOW:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel())
return keyword;
else if (parseContext.version < 130 && ((parseContext.profile == EEsProfile && keyword != SAMPLER2DARRAY) || !parseContext.extensionTurnedOn(E_GL_EXT_texture_array))) {
if (parseContext.forwardCompatible)
parseContext.warn(loc, "using future keyword", tokenText, "");
return identifierOrType();
}
return keyword;
case SAMPLER2DRECT:
case SAMPLER2DRECTSHADOW:
afterType = true;
@@ -1098,15 +1126,6 @@ int TScanContext::tokenizeIdentifier()
}
return keyword;
case SAMPLER1DARRAY:
afterType = true;
if (parseContext.profile == EEsProfile && parseContext.version == 300)
reservedWord();
else if ((parseContext.profile == EEsProfile && parseContext.version < 300) ||
(parseContext.profile != EEsProfile && parseContext.version < 130))
return identifierOrType();
return keyword;
case SAMPLEREXTERNALOES:
afterType = true;
if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_OES_EGL_image_external))
@@ -1632,6 +1632,7 @@ TProgram::TProgram() : pool(0), reflection(0), ioMapper(nullptr), linked(false)
TProgram::~TProgram()
{
delete ioMapper;
delete infoSink;
delete reflection;
@@ -1707,6 +1708,15 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages)
intermediate[stage] = new TIntermediate(stage,
firstIntermediate->getVersion(),
firstIntermediate->getProfile());
// The new TIntermediate must use the same origin as the original TIntermediates.
// Otherwise linking will fail due to different coordinate systems.
if (firstIntermediate->getOriginUpperLeft()) {
intermediate[stage]->setOriginUpperLeft();
}
intermediate[stage]->setSpv(firstIntermediate->getSpv());
newedIntermediate[stage] = true;
}
@@ -87,6 +87,12 @@ public:
virtual const TString& getName() const { return *name; }
virtual void changeName(const TString* newName) { name = newName; }
virtual void addPrefix(const char* prefix)
{
TString newName(prefix);
newName.append(*name);
changeName(NewPoolTString(newName.c_str()));
}
virtual const TString& getMangledName() const { return getName(); }
virtual TFunction* getAsFunction() { return 0; }
virtual const TFunction* getAsFunction() const { return 0; }
@@ -192,6 +198,7 @@ struct TParameter {
TString *name;
TType* type;
TIntermTyped* defaultValue;
TBuiltInVariable declaredBuiltIn;
void copyParam(const TParameter& param)
{
if (param.name)
@@ -200,6 +207,7 @@ struct TParameter {
name = 0;
type = param.type->clone();
defaultValue = param.defaultValue;
declaredBuiltIn = param.declaredBuiltIn;
}
};
@@ -216,7 +224,11 @@ public:
TSymbol(name),
mangledName(*name + '('),
op(tOp),
defined(false), prototyped(false), defaultParamCount(0) { returnType.shallowCopy(retType); }
defined(false), prototyped(false), defaultParamCount(0)
{
returnType.shallowCopy(retType);
declaredBuiltIn = retType.getQualifier().builtIn;
}
virtual TFunction* clone() const;
virtual ~TFunction();
@@ -226,15 +238,22 @@ public:
virtual void addParameter(TParameter& p)
{
assert(writable);
p.declaredBuiltIn = p.type->getQualifier().builtIn;
parameters.push_back(p);
p.type->appendMangledName(mangledName);
if (p.defaultValue != nullptr)
defaultParamCount++;
}
virtual void addPrefix(const char* prefix) override
{
TSymbol::addPrefix(prefix);
mangledName.insert(0, prefix);
}
virtual const TString& getMangledName() const { return mangledName; }
virtual const TType& getType() const { return returnType; }
virtual TBuiltInVariable getDeclaredBuiltInType() const { return declaredBuiltIn; }
virtual TType& getWritableType() { return returnType; }
virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
virtual TOperator getBuiltInOp() const { return op; }
@@ -262,6 +281,8 @@ protected:
typedef TVector<TParameter> TParamList;
TParamList parameters;
TType returnType;
TBuiltInVariable declaredBuiltIn;
TString mangledName;
TOperator op;
bool defined;
@@ -156,6 +156,7 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_OES_EGL_image_external] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable;
extensionBehavior[E_GL_EXT_texture_array] = EBhDisable;
extensionBehavior[E_GL_ARB_texture_rectangle] = EBhDisable;
extensionBehavior[E_GL_3DL_array_objects] = EBhDisable;
extensionBehavior[E_GL_ARB_shading_language_420pack] = EBhDisable;
@@ -182,6 +183,7 @@ void TParseVersions::initializeExtensionBehavior()
// extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_image_load_formatted] = EBhDisable;
// #line and #include
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
@@ -201,6 +203,7 @@ void TParseVersions::initializeExtensionBehavior()
extensionBehavior[E_GL_ARB_shader_viewport_layer_array] = EBhDisable;
extensionBehavior[E_GL_NV_viewport_array2] = EBhDisable;
extensionBehavior[E_GL_NV_stereo_view_rendering] = EBhDisable;
extensionBehavior[E_GL_NVX_multiview_per_view_attributes] = EBhDisable;
#endif
// AEP
@@ -240,6 +243,7 @@ void TParseVersions::getPreamble(std::string& preamble)
preamble =
"#define GL_ES 1\n"
"#define GL_FRAGMENT_PRECISION_HIGH 1\n"
"#define GL_EXT_texture_array 1\n"
"#define GL_OES_texture_3D 1\n"
"#define GL_OES_standard_derivatives 1\n"
"#define GL_EXT_frag_depth 1\n"
@@ -278,6 +282,7 @@ void TParseVersions::getPreamble(std::string& preamble)
} else {
preamble =
"#define GL_FRAGMENT_PRECISION_HIGH 1\n"
"#define GL_EXT_texture_array 1\n"
"#define GL_ARB_texture_rectangle 1\n"
"#define GL_ARB_shading_language_420pack 1\n"
"#define GL_ARB_texture_gather 1\n"
@@ -302,6 +307,7 @@ void TParseVersions::getPreamble(std::string& preamble)
"#define GL_ARB_sparse_texture_clamp 1\n"
// "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
"#define GL_EXT_shader_image_load_formatted 1\n"
#ifdef AMD_EXTENSIONS
"#define GL_AMD_shader_ballot 1\n"
@@ -104,6 +104,7 @@ const char* const E_GL_EXT_frag_depth = "GL_EXT_frag_depth";
const char* const E_GL_OES_EGL_image_external = "GL_OES_EGL_image_external";
const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod";
const char* const E_GL_EXT_texture_array = "GL_EXT_texture_array";
const char* const E_GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle";
const char* const E_GL_3DL_array_objects = "GL_3DL_array_objects";
const char* const E_GL_ARB_shading_language_420pack = "GL_ARB_shading_language_420pack";
@@ -130,6 +131,7 @@ const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture
// const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members
const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_shader_non_constant_global_initializers";
const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_load_formatted";
// #line and #include
const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive";
@@ -149,6 +151,7 @@ const char* const E_SPV_NV_geometry_shader_passthrough = "GL_NV_geometr
const char* const E_GL_ARB_shader_viewport_layer_array = "GL_ARB_shader_viewport_layer_array";
const char* const E_GL_NV_viewport_array2 = "GL_NV_viewport_array2";
const char* const E_GL_NV_stereo_view_rendering = "GL_NV_stereo_view_rendering";
const char* const E_GL_NVX_multiview_per_view_attributes = "GL_NVX_multiview_per_view_attributes";
// Arrays of extensions for the above viewportEXTs duplications
@@ -209,6 +209,9 @@ struct TResolverAdaptor
TIoMapResolver& resolver;
TInfoSink& infoSink;
bool& error;
private:
TResolverAdaptor& operator=(TResolverAdaptor&);
};
/*
@@ -252,7 +252,7 @@ public:
TIntermAggregate* makeAggregate(const TSourceLoc&);
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
bool areAllChildConst(TIntermAggregate* aggrNode);
TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
@@ -263,6 +263,7 @@ public:
TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
@@ -440,6 +441,7 @@ protected:
bool promoteAggregate(TIntermAggregate&);
void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&);
void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&);
bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&);
const EShLanguage language; // stage, known at construction time
EShSource source; // source language, known a bit later
@@ -148,10 +148,10 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
// record the definition of the macro
TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
while (token != '\n' && token != EndOfInput) {
RecordToken(mac.body, token, ppToken);
mac.body.putToken(token, ppToken);
token = scanToken(ppToken);
if (token != '\n' && ppToken->space)
RecordToken(mac.body, ' ', ppToken);
mac.body.putToken(' ', ppToken);
}
// check for duplicate definition
@@ -166,15 +166,15 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
else {
if (existing->args != mac.args)
parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", atomStrings.getString(defAtom));
RewindTokenStream(existing->body);
RewindTokenStream(mac.body);
existing->body.reset();
mac.body.reset();
int newToken;
do {
int oldToken;
TPpToken oldPpToken;
TPpToken newPpToken;
oldToken = ReadToken(existing->body, &oldPpToken);
newToken = ReadToken(mac.body, &newPpToken);
oldToken = existing->body.getToken(parseContext, &oldPpToken);
newToken = mac.body.getToken(parseContext, &newPpToken);
if (oldToken != newToken || oldPpToken != newPpToken) {
parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", atomStrings.getString(defAtom));
break;
@@ -979,28 +979,16 @@ int TPpContext::scanHeaderName(TPpToken* ppToken, char delimit)
// Returns nullptr if no expanded argument is created.
TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
{
// pre-check, to see if anything in the argument needs to be expanded,
// to see if we can kick out early
int token;
RewindTokenStream(arg);
do {
token = ReadToken(arg, ppToken);
if (token == PpAtomIdentifier && lookupMacroDef(atomStrings.getAtom(ppToken->name)) != nullptr)
break;
} while (token != EndOfInput);
// if nothing needs to be expanded, kick out early
if (token == EndOfInput)
return nullptr;
// expand the argument
TokenStream* expandedArg = new TokenStream;
pushInput(new tMarkerInput(this));
pushTokenStreamInput(arg);
int token;
while ((token = scanToken(ppToken)) != tMarkerInput::marker && token != EndOfInput) {
token = tokenPaste(token, *ppToken);
if (token == PpAtomIdentifier && MacroExpand(ppToken, false, newLineOkay) != 0)
continue;
RecordToken(*expandedArg, token, ppToken);
expandedArg->putToken(token, ppToken);
}
if (token == EndOfInput) {
@@ -1023,7 +1011,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
{
int token;
do {
token = pp->ReadToken(mac->body, ppToken);
token = mac->body.getToken(pp->parseContext, ppToken);
} while (token == ' '); // handle white space in macro
// Hash operators basically turn off a round of macro substitution
@@ -1054,7 +1042,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
}
// see if are preceding a ##
if (peekMacPasting()) {
if (mac->body.peekUntokenizedPasting()) {
prepaste = true;
pasting = true;
}
@@ -1081,31 +1069,6 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
return token;
}
// See if the next non-white-space token in the macro is ##
bool TPpContext::tMacroInput::peekMacPasting()
{
// don't return early, have to restore this
size_t savePos = mac->body.current;
// skip white-space
int ltoken;
do {
ltoken = pp->lReadByte(mac->body);
} while (ltoken == ' ');
// check for ##
bool pasting = false;
if (ltoken == '#') {
ltoken = pp->lReadByte(mac->body);
if (ltoken == '#')
pasting = true;
}
mac->body.current = savePos;
return pasting;
}
// return a textual zero, for scanning a macro that was never defined
int TPpContext::tZeroInput::scan(TPpToken* ppToken)
{
@@ -1230,7 +1193,7 @@ int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOka
depth++;
if (token == ')')
depth--;
RecordToken(*in->args[arg], token, ppToken);
in->args[arg]->putToken(token, ppToken);
tokenRecorded = true;
}
if (token == ')') {
@@ -1263,14 +1226,14 @@ int TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, bool newLineOka
}
// We need both expanded and non-expanded forms of the argument, for whether or
// not token pasting is in play.
// not token pasting will be applied later when the argument is consumed next to ##.
for (size_t i = 0; i < in->mac->args.size(); i++)
in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
}
pushInput(in);
macro->busy = 1;
RewindTokenStream(macro->body);
macro->body.reset();
return 1;
}
@@ -220,8 +220,26 @@ public:
inputStack.pop_back();
}
struct TokenStream {
//
// From PpTokens.cpp
//
class TokenStream {
public:
TokenStream() : current(0) { }
void putToken(int token, TPpToken* ppToken);
int getToken(TParseContextBase&, TPpToken*);
bool atEnd() { return current >= data.size(); }
bool peekTokenizedPasting(bool lastTokenPastes);
bool peekUntokenizedPasting();
void reset() { current = 0; }
protected:
void putSubtoken(int);
int getSubtoken();
void ungetSubtoken();
TVector<unsigned char> data;
size_t current;
};
@@ -306,14 +324,13 @@ protected:
virtual int getch() override { assert(0); return EndOfInput; }
virtual void ungetch() override { assert(0); }
bool peekPasting() override { return prepaste; }
bool endOfReplacementList() override { return mac->body.current >= mac->body.data.size(); }
bool endOfReplacementList() override { return mac->body.atEnd(); }
MacroSymbol *mac;
TVector<TokenStream*> args;
TVector<TokenStream*> expandedArgs;
protected:
bool peekMacPasting();
bool prepaste; // true if we are just before ##
bool postpaste; // true if we are right after ##
};
@@ -375,22 +392,16 @@ protected:
//
// From PpTokens.cpp
//
void lAddByte(TokenStream&, unsigned char fVal);
int lReadByte(TokenStream&);
void lUnreadByte(TokenStream&);
void RecordToken(TokenStream&, int token, TPpToken* ppToken);
void RewindTokenStream(TokenStream&);
int ReadToken(TokenStream&, TPpToken*);
void pushTokenStreamInput(TokenStream&, bool pasting = false);
void UngetToken(int token, TPpToken*);
class tTokenInput : public tInput {
public:
tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : tInput(pp), tokens(t), lastTokenPastes(prepasting) { }
virtual int scan(TPpToken *) override;
virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); }
virtual int getch() override { assert(0); return EndOfInput; }
virtual void ungetch() override { assert(0); }
virtual bool peekPasting() override;
virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); }
protected:
TokenStream* tokens;
bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
@@ -232,6 +232,8 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken)
switch (ch) {
default:
// Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
if (ch > PpAtomMaxSingle)
ch = PpAtomBadToken;
return ch;
case 'A': case 'B': case 'C': case 'D': case 'E':
@@ -95,48 +95,45 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace glslang {
void TPpContext::lAddByte(TokenStream& fTok, unsigned char fVal)
// push onto back of stream
void TPpContext::TokenStream::putSubtoken(int subtoken)
{
fTok.data.push_back(fVal);
assert((subtoken & ~0xff) == 0);
data.push_back(static_cast<unsigned char>(subtoken));
}
/*
* Get the next byte from a stream.
*/
int TPpContext::lReadByte(TokenStream& pTok)
// get the next token in stream
int TPpContext::TokenStream::getSubtoken()
{
if (pTok.current < pTok.data.size())
return pTok.data[pTok.current++];
if (current < data.size())
return data[current++];
else
return EndOfInput;
}
void TPpContext::lUnreadByte(TokenStream& pTok)
// back up one position in the stream
void TPpContext::TokenStream::ungetSubtoken()
{
if (pTok.current > 0)
--pTok.current;
if (current > 0)
--current;
}
/*
* Add a token to the end of a list for later playback.
*/
void TPpContext::RecordToken(TokenStream& pTok, int token, TPpToken* ppToken)
// Add a complete token (including backing string) to the end of a list
// for later playback.
void TPpContext::TokenStream::putToken(int token, TPpToken* ppToken)
{
const char* s;
char* str = NULL;
if (token > PpAtomMaxSingle)
lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80));
else
lAddByte(pTok, (unsigned char)(token & 0x7f));
putSubtoken(token);
switch (token) {
case PpAtomIdentifier:
case PpAtomConstString:
s = ppToken->name;
while (*s)
lAddByte(pTok, (unsigned char) *s++);
lAddByte(pTok, 0);
putSubtoken(*s++);
putSubtoken(0);
break;
case PpAtomConstInt:
case PpAtomConstUint:
@@ -149,46 +146,35 @@ void TPpContext::RecordToken(TokenStream& pTok, int token, TPpToken* ppToken)
#endif
str = ppToken->name;
while (*str) {
lAddByte(pTok, (unsigned char) *str);
putSubtoken(*str);
str++;
}
lAddByte(pTok, 0);
putSubtoken(0);
break;
default:
break;
}
}
/*
* Reset a token stream in preparation for reading.
*/
void TPpContext::RewindTokenStream(TokenStream& pTok)
// Read the next token from a token stream.
// (Not the source stream, but a stream used to hold a tokenized macro).
int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken *ppToken)
{
pTok.current = 0;
}
/*
* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro).
*/
int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
{
int ltoken, len;
int len;
int ch;
ltoken = lReadByte(pTok);
int subtoken = getSubtoken();
ppToken->loc = parseContext.getCurrentLoc();
if (ltoken > 127)
ltoken += 128;
switch (ltoken) {
switch (subtoken) {
case '#':
// Check for ##, unless the current # is the last character
if (pTok.current < pTok.data.size()) {
if (lReadByte(pTok) == '#') {
if (current < data.size()) {
if (getSubtoken() == '#') {
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
ltoken = PpAtomPaste;
subtoken = PpAtomPaste;
} else
lUnreadByte(pTok);
ungetSubtoken();
}
break;
case PpAtomConstString:
@@ -203,12 +189,12 @@ int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
case PpAtomConstInt64:
case PpAtomConstUint64:
len = 0;
ch = lReadByte(pTok);
ch = getSubtoken();
while (ch != 0 && ch != EndOfInput) {
if (len < MaxTokenLength) {
ppToken->name[len] = (char)ch;
len++;
ch = lReadByte(pTok);
ch = getSubtoken();
} else {
parseContext.error(ppToken->loc, "token too long", "", "");
break;
@@ -216,7 +202,7 @@ int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
}
ppToken->name[len] = 0;
switch (ltoken) {
switch (subtoken) {
case PpAtomIdentifier:
break;
case PpAtomConstString:
@@ -267,43 +253,80 @@ int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
}
}
return ltoken;
return subtoken;
}
int TPpContext::tTokenInput::scan(TPpToken* ppToken)
// We are pasting if
// 1. we are preceding a pasting operator within this stream
// or
// 2. the entire macro is preceding a pasting operator (lastTokenPastes)
// and we are also on the last token
bool TPpContext::TokenStream::peekTokenizedPasting(bool lastTokenPastes)
{
return pp->ReadToken(*tokens, ppToken);
}
// 1. preceding ##?
size_t savePos = current;
int subtoken;
// skip white space
do {
subtoken = getSubtoken();
} while (subtoken == ' ');
current = savePos;
if (subtoken == PpAtomPaste)
return true;
// 2. last token and we've been told after this there will be a ##
// We are pasting if the entire macro is preceding a pasting operator
// (lastTokenPastes) and we are also on the last token.
bool TPpContext::tTokenInput::peekPasting()
{
if (! lastTokenPastes)
return false;
// Getting here means the last token will be pasted.
// Getting here means the last token will be pasted, after this
// Are we at the last non-whitespace token?
size_t savePos = tokens->current;
savePos = current;
bool moreTokens = false;
do {
int byte = pp->lReadByte(*tokens);
if (byte == EndOfInput)
subtoken = getSubtoken();
if (subtoken == EndOfInput)
break;
if (byte != ' ') {
if (subtoken != ' ') {
moreTokens = true;
break;
}
} while (true);
tokens->current = savePos;
current = savePos;
return !moreTokens;
}
// See if the next non-white-space tokens are two consecutive #
bool TPpContext::TokenStream::peekUntokenizedPasting()
{
// don't return early, have to restore this
size_t savePos = current;
// skip white-space
int subtoken;
do {
subtoken = getSubtoken();
} while (subtoken == ' ');
// check for ##
bool pasting = false;
if (subtoken == '#') {
subtoken = getSubtoken();
if (subtoken == '#')
pasting = true;
}
current = savePos;
return pasting;
}
void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting)
{
pushInput(new tTokenInput(this, &ts, prepasting));
RewindTokenStream(ts);
ts.reset();
}
int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken)
@@ -82,7 +82,11 @@ namespace glslang {
// Multi-character tokens
enum EFixedAtoms {
PpAtomMaxSingle = 256, // single character tokens get their own char value as their token, skip them
// single character tokens get their own char value as their token; start here for multi-character tokens
PpAtomMaxSingle = 127,
// replace bad character tokens with this, to avoid accidental aliasing with the below
PpAtomBadToken,
// Operators
@@ -540,6 +540,7 @@ protected:
bool linked;
private:
TProgram(TProgram&);
TProgram& operator=(TProgram&);
};