mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
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:
@@ -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);
|
||||
|
||||
@@ -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&);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user