mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
Built-in symbol tables now lazily evaluated, and driven by per version, per profile input. Got all ES 100 and ES 300 built-in symbols correct.
This includes - doing prescan of shader to know version/profile before parsing it - putting precision qualifiers on built-in ES symbols - getting most built-in state correct for core/compatibility/missing profile - adding gl_VertexID and gl_InstanceID, among other ES 300 built-in symbols - adding the ES 300 gl_Max/Min constants - accepting shaders that contain nothing but whitespace without generating an error git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@20627 e7fa87d3-cd2b-0410-9028-fcbf551c1848
This commit is contained in:
parent
fb5f7eadfa
commit
bd0747d6f0
@ -1,5 +1,7 @@
|
||||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
@ -99,6 +101,12 @@ void GenerateResources(TBuiltInResource& resources)
|
||||
resources.maxTextureImageUnits = 32;
|
||||
resources.maxFragmentUniformComponents = 4096;
|
||||
resources.maxDrawBuffers = 32;
|
||||
resources.maxVertexUniformVectors = 128;
|
||||
resources.maxVaryingVectors = 8;
|
||||
resources.maxFragmentUniformVectors = 16;
|
||||
resources.maxVertexOutputVectors = 16;
|
||||
resources.minProgramTexelOffset = -8;
|
||||
resources.maxProgramTexelOffset = 7;
|
||||
}
|
||||
|
||||
int C_DECL main(int argc, char* argv[])
|
||||
|
12
Test/comment.frag
Normal file
12
Test/comment.frag
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
//
|
||||
/* anotehn t* ontuh * / tnoahnt /* oo */
|
||||
/* multi line...
|
||||
|
||||
ao */
|
||||
/* no escape \
|
||||
oanot */
|
||||
// escape nothing \o oeu
|
||||
// escape newline \
|
||||
still in a comment
|
||||
|
@ -1,4 +1,4 @@
|
||||
precision mediump float;
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
|
@ -19,3 +19,4 @@ cppComplexExpr.vert
|
||||
pointCoord.frag
|
||||
array.frag
|
||||
array100.frag
|
||||
comment.frag
|
||||
|
@ -86,6 +86,10 @@ enum TStorageQualifier {
|
||||
EvqInOut,
|
||||
EvqConstReadOnly,
|
||||
|
||||
// built-ins read by vertex shader
|
||||
EvqVertexId,
|
||||
EvqInstanceId,
|
||||
|
||||
// built-ins written by vertex shader
|
||||
EvqPosition,
|
||||
EvqPointSize,
|
||||
@ -119,6 +123,8 @@ __inline const char* getStorageQualifierString(TStorageQualifier q)
|
||||
case EvqIn: return "in"; break;
|
||||
case EvqOut: return "out"; break;
|
||||
case EvqInOut: return "inout"; break;
|
||||
case EvqVertexId: return "gl_VertexId"; break;
|
||||
case EvqInstanceId: return "gl_InstanceId"; break;
|
||||
case EvqPosition: return "gl_Position"; break;
|
||||
case EvqPointSize: return "gl_PointSize"; break;
|
||||
case EvqClipVertex: return "gl_ClipVertex"; break;
|
||||
|
@ -257,7 +257,7 @@ struct TThreadGlobalPools
|
||||
TPoolAllocator* globalPoolAllocator;
|
||||
};
|
||||
|
||||
void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator);
|
||||
void SetGlobalPoolAllocatorPtr(TPoolAllocator& poolAllocator);
|
||||
|
||||
//
|
||||
// This STL compatible allocator is intended to be used as the allocator
|
||||
|
@ -1,5 +1,7 @@
|
||||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
@ -48,5 +50,11 @@ struct TBuiltInResource {
|
||||
int maxTextureImageUnits;
|
||||
int maxFragmentUniformComponents;
|
||||
int maxDrawBuffers;
|
||||
int maxVertexUniformVectors;
|
||||
int maxVaryingVectors;
|
||||
int maxFragmentUniformVectors;
|
||||
int maxVertexOutputVectors;
|
||||
int minProgramTexelOffset;
|
||||
int maxProgramTexelOffset;
|
||||
};
|
||||
#endif // _RESOURCE_LIMITS_INCLUDED_
|
||||
|
@ -155,6 +155,15 @@ public:
|
||||
qualifier.storage = q;
|
||||
qualifier.precision = EpqNone;
|
||||
}
|
||||
TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
|
||||
type(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
|
||||
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0),
|
||||
fieldName(0), mangled(0), typeName(0)
|
||||
{
|
||||
qualifier.storage = q;
|
||||
qualifier.precision = p;
|
||||
assert(p >= 0 && p <= EpqHigh);
|
||||
}
|
||||
explicit TType(const TPublicType &p) :
|
||||
type(p.type), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes),
|
||||
structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0)
|
||||
|
@ -43,7 +43,9 @@
|
||||
#include "../Include/intermediate.h"
|
||||
#include "Initialize.h"
|
||||
|
||||
void TBuiltIns::initialize()
|
||||
const int FirstProfileVersion = 150;
|
||||
|
||||
void TBuiltIns::initialize(int version, EProfile profile)
|
||||
{
|
||||
//
|
||||
// Initialize all the built-in strings for parsing.
|
||||
@ -499,12 +501,23 @@ void TBuiltIns::initialize()
|
||||
|
||||
TString& s = StandardUniforms;
|
||||
|
||||
|
||||
//
|
||||
// OpenGL'uniform' state. Page numbers are in reference to version
|
||||
// 1.4 of the OpenGL specification.
|
||||
// Depth range in window coordinates, p. 33
|
||||
//
|
||||
s.append(TString("struct gl_DepthRangeParameters {"));
|
||||
if (profile == EEsProfile) {
|
||||
s.append(TString(" highp float near;")); // n
|
||||
s.append(TString(" highp float far;")); // f
|
||||
s.append(TString(" highp float diff;")); // f - n
|
||||
} else {
|
||||
s.append(TString(" float near;")); // n
|
||||
s.append(TString(" float far;")); // f
|
||||
s.append(TString(" float diff;")); // f - n
|
||||
}
|
||||
s.append(TString("};"));
|
||||
s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;"));
|
||||
|
||||
if (profile != EEsProfile && (version < FirstProfileVersion || profile == ECompatibilityProfile)) {
|
||||
//
|
||||
// Matrix state. p. 31, 32, 37, 39, 40.
|
||||
//
|
||||
@ -535,17 +548,6 @@ void TBuiltIns::initialize()
|
||||
//
|
||||
s.append(TString("uniform float gl_NormalScale;"));
|
||||
|
||||
//
|
||||
// Depth range in window coordinates, p. 33
|
||||
//
|
||||
s.append(TString("struct gl_DepthRangeParameters {"));
|
||||
s.append(TString(" float near;")); // n
|
||||
s.append(TString(" float far;")); // f
|
||||
s.append(TString(" float diff;")); // f - n
|
||||
s.append(TString("};"));
|
||||
s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;"));
|
||||
|
||||
|
||||
//
|
||||
// Point Size, p. 66, 67.
|
||||
//
|
||||
@ -619,9 +621,6 @@ void TBuiltIns::initialize()
|
||||
s.append(TString(" vec4 specular;")); // Scm * Scli
|
||||
s.append(TString("};"));
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Fog p. 161
|
||||
//
|
||||
@ -634,18 +633,20 @@ void TBuiltIns::initialize()
|
||||
s.append(TString("};"));
|
||||
|
||||
s.append(TString("uniform gl_FogParameters gl_Fog;"));
|
||||
}
|
||||
|
||||
s.append(TString("\n"));
|
||||
}
|
||||
{
|
||||
//============================================================================
|
||||
//
|
||||
// Vertex attributes, p. 19.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
if (profile != EEsProfile) {
|
||||
TString& s = StandardVertexAttributes;
|
||||
|
||||
if (version < 130) {
|
||||
s.append(TString("attribute vec4 gl_Color;"));
|
||||
s.append(TString("attribute vec4 gl_SecondaryColor;"));
|
||||
s.append(TString("attribute vec3 gl_Normal;"));
|
||||
@ -659,24 +660,48 @@ void TBuiltIns::initialize()
|
||||
s.append(TString("attribute vec4 gl_MultiTexCoord6;"));
|
||||
s.append(TString("attribute vec4 gl_MultiTexCoord7;"));
|
||||
s.append(TString("attribute float gl_FogCoord;"));
|
||||
} else if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
s.append(TString("in vec4 gl_Color;"));
|
||||
s.append(TString("in vec4 gl_SecondaryColor;"));
|
||||
s.append(TString("in vec3 gl_Normal;"));
|
||||
s.append(TString("in vec4 gl_Vertex;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord0;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord1;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord2;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord3;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord4;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord5;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord6;"));
|
||||
s.append(TString("in vec4 gl_MultiTexCoord7;"));
|
||||
s.append(TString("in float gl_FogCoord;"));
|
||||
}
|
||||
|
||||
s.append(TString("\n"));
|
||||
}
|
||||
{
|
||||
//============================================================================
|
||||
//
|
||||
// Define the output varying interface from the vertex shader.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
if (profile != EEsProfile) {
|
||||
TString& s = StandardVertexVaryings;
|
||||
|
||||
if (version < 130) {
|
||||
s.append(TString("varying vec4 gl_FrontColor;"));
|
||||
s.append(TString("varying vec4 gl_BackColor;"));
|
||||
s.append(TString("varying vec4 gl_FrontSecondaryColor;"));
|
||||
s.append(TString("varying vec4 gl_BackSecondaryColor;"));
|
||||
s.append(TString("varying vec4 gl_TexCoord[];"));
|
||||
s.append(TString("varying float gl_FogFragCoord;"));
|
||||
} else if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
s.append(TString("out vec4 gl_FrontColor;"));
|
||||
s.append(TString("out vec4 gl_BackColor;"));
|
||||
s.append(TString("out vec4 gl_FrontSecondaryColor;"));
|
||||
s.append(TString("out vec4 gl_BackSecondaryColor;"));
|
||||
s.append(TString("out vec4 gl_TexCoord[];"));
|
||||
s.append(TString("out float gl_FogFragCoord;"));
|
||||
}
|
||||
|
||||
s.append(TString("\n"));
|
||||
}
|
||||
@ -687,15 +712,23 @@ void TBuiltIns::initialize()
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
if (profile != EEsProfile) {
|
||||
TString& s = StandardFragmentVaryings;
|
||||
|
||||
if (version < 130) {
|
||||
s.append(TString("varying vec4 gl_Color;"));
|
||||
s.append(TString("varying vec4 gl_SecondaryColor;"));
|
||||
s.append(TString("varying vec4 gl_TexCoord[];"));
|
||||
s.append(TString("varying float gl_FogFragCoord;"));
|
||||
} else if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
s.append(TString("in vec4 gl_Color;"));
|
||||
s.append(TString("in vec4 gl_SecondaryColor;"));
|
||||
s.append(TString("in vec4 gl_TexCoord[];"));
|
||||
s.append(TString("in float gl_FogFragCoord;"));
|
||||
}
|
||||
|
||||
s.append(TString("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
builtInStrings[EShLangFragment].push_back(BuiltInFunctions.c_str());
|
||||
builtInStrings[EShLangFragment].push_back(BuiltInFunctionsFragment);
|
||||
@ -710,7 +743,7 @@ void TBuiltIns::initialize()
|
||||
}
|
||||
|
||||
|
||||
void TBuiltIns::initialize(const TBuiltInResource &resources)
|
||||
void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, EShLanguage language)
|
||||
{
|
||||
//
|
||||
// Initialize the context-dependent (resource-dependent) built-in strings for parsing.
|
||||
@ -725,49 +758,87 @@ void TBuiltIns::initialize(const TBuiltInResource &resources)
|
||||
//============================================================================
|
||||
|
||||
TString& s = StandardUniforms;
|
||||
const int maxSize = 80;
|
||||
char builtInConstant[maxSize];
|
||||
|
||||
//
|
||||
// Implementation dependent constants. The example values below
|
||||
// are the minimum values allowed for these maximums.
|
||||
//
|
||||
const int maxSize = 80;
|
||||
char builtInConstant[maxSize];
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxLights = %d;", resources.maxLights); // GL 1.0
|
||||
|
||||
if (profile == EEsProfile) {
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxClipPlanes = %d;", resources.maxClipPlanes); // GL 1.0
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxVertexUniformVectors = %d;", resources.maxVertexUniformVectors);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureUnits = %d;", resources.maxTextureUnits); // GL 1.2
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureCoords = %d;", resources.maxTextureCoords); // ARB_fragment_program
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs); // ARB_vertex_shader
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents); // ARB_vertex_shader
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxFragmentUniformVectors = %d;", resources.maxFragmentUniformVectors);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats); // ARB_vertex_shader
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits); // ARB_vertex_shader
|
||||
if (version == 100) {
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxVaryingVectors = %d;", resources.maxVaryingVectors);
|
||||
s.append(TString(builtInConstant));
|
||||
} else {
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxVertexOutputVectors = %d;", resources.maxVertexOutputVectors);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits); // ARB_vertex_shader
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits); // ARB_fragment_shader
|
||||
snprintf(builtInConstant, maxSize, "const mediump int gl_MaxProgramTexelOffset = %d;", resources.maxProgramTexelOffset);
|
||||
s.append(TString(builtInConstant));
|
||||
}
|
||||
} else {
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents); // ARB_fragment_shader
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers); // proposed ARB_draw_buffers
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxLights = %d;", resources.maxLights);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxClipPlanes = %d;", resources.maxClipPlanes);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureUnits = %d;", resources.maxTextureUnits);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxTextureCoords = %d;", resources.maxTextureCoords);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVertexUniformComponents = %d;", resources.maxVertexUniformComponents);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxVaryingFloats = %d;", resources.maxVaryingFloats);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
snprintf(builtInConstant, maxSize, "const int gl_MaxFragmentUniformComponents = %d;", resources.maxFragmentUniformComponents);
|
||||
s.append(TString(builtInConstant));
|
||||
|
||||
if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
//
|
||||
// OpenGL'uniform' state. Page numbers are in reference to version
|
||||
// 1.4 of the OpenGL specification.
|
||||
@ -816,6 +887,8 @@ void TBuiltIns::initialize(const TBuiltInResource &resources)
|
||||
s.append(TString("uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords];"));
|
||||
s.append(TString("uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords];"));
|
||||
s.append(TString("uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords];"));
|
||||
}
|
||||
}
|
||||
|
||||
s.append(TString("\n"));
|
||||
}
|
||||
@ -824,26 +897,55 @@ void TBuiltIns::initialize(const TBuiltInResource &resources)
|
||||
builtInStrings[EShLangVertex].push_back(StandardUniforms);
|
||||
}
|
||||
|
||||
void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable)
|
||||
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable)
|
||||
{
|
||||
TPrecisionQualifier pq;
|
||||
//
|
||||
// First, insert some special built-in variables that are not in
|
||||
// the built-in header files.
|
||||
// the built-in text strings.
|
||||
//
|
||||
switch(language) {
|
||||
case EShLangFragment:
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EvqFace, 1)));
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EvqFragCoord, 4)));
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EvqPointCoord, 2)));
|
||||
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EvqFragColor, 4)));
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepth"), TType(EbtFloat, EvqFragDepth, 1)));
|
||||
if (profile == EEsProfile)
|
||||
pq = version == 100 ? EpqMedium : EpqHigh;
|
||||
else
|
||||
pq = EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EvqFragCoord, pq, 4)));
|
||||
|
||||
if (profile == EEsProfile || version >= 120) {
|
||||
pq = profile == EEsProfile ? EpqMedium : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EvqPointCoord, pq, 2)));
|
||||
}
|
||||
|
||||
if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
pq = profile == EEsProfile ? EpqMedium : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EvqFragColor, pq, 4)));
|
||||
}
|
||||
|
||||
if (profile != EEsProfile || version > 100) {
|
||||
pq = profile == EEsProfile ? EpqHigh : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepth"), TType(EbtFloat, EvqFragDepth, pq, 1)));
|
||||
}
|
||||
break;
|
||||
|
||||
case EShLangVertex:
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EvqPosition, 4)));
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EvqPointSize, 1)));
|
||||
pq = profile == EEsProfile ? EpqHigh : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EvqPosition, pq, 4)));
|
||||
|
||||
pq = profile == EEsProfile ? (version > 100 ? EpqHigh : EpqMedium) : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EvqPointSize, pq, 1)));
|
||||
|
||||
if (profile != EEsProfile)
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_ClipVertex"), TType(EbtFloat, EvqClipVertex, 4)));
|
||||
|
||||
if (version >= 130) {
|
||||
pq = profile == EEsProfile ? EpqHigh : EpqNone;
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_VertexID"), TType(EbtInt, EvqVertexId, pq, 1)));
|
||||
if (version >= 140)
|
||||
symbolTable.insert(*new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EvqInstanceId, pq, 1)));
|
||||
}
|
||||
break;
|
||||
|
||||
case EShLangTessControl:
|
||||
@ -928,16 +1030,17 @@ void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable)
|
||||
}
|
||||
}
|
||||
|
||||
void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
|
||||
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources)
|
||||
{
|
||||
//
|
||||
// First, insert some special built-in variables that are not in
|
||||
// the built-in header files.
|
||||
// Set resource-specific built-ins not yet handled.
|
||||
//
|
||||
switch(language) {
|
||||
|
||||
case EShLangFragment: {
|
||||
// Set up gl_FragData. The array size.
|
||||
case EShLangFragment:
|
||||
// Set up gl_FragData based on current array size.
|
||||
if (version < FirstProfileVersion || profile == ECompatibilityProfile) {
|
||||
TPrecisionQualifier pq = profile == EEsProfile ? EpqMedium : EpqNone;
|
||||
TType fragData(EbtFloat, EvqFragColor, 4);
|
||||
TArraySizes arraySizes = NewPoolTArraySizes();
|
||||
arraySizes->push_back(resources.maxDrawBuffers);
|
||||
|
@ -1,5 +1,7 @@
|
||||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
@ -39,23 +41,22 @@
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Versions.h"
|
||||
|
||||
typedef TVector<TString> TBuiltInStrings;
|
||||
|
||||
class TBuiltIns {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
|
||||
void initialize();
|
||||
void initialize(const TBuiltInResource& resources);
|
||||
void initialize(int version, EProfile);
|
||||
void initialize(const TBuiltInResource& resources, int version, EProfile, EShLanguage);
|
||||
TBuiltInStrings* getBuiltInStrings() { return builtInStrings; }
|
||||
protected:
|
||||
TBuiltInStrings builtInStrings[EShLangCount];
|
||||
};
|
||||
|
||||
void IdentifyBuiltIns(EShLanguage, TSymbolTable&);
|
||||
void IdentifyBuiltIns(EShLanguage, TSymbolTable&, const TBuiltInResource &resources);
|
||||
bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink&, TSymbolTable*, EShLanguage language = EShLangCount);
|
||||
bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource *resources, TSymbolTable*);
|
||||
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage, TSymbolTable&);
|
||||
void IdentifyBuiltIns(int version, EProfile profile, EShLanguage, TSymbolTable&, const TBuiltInResource &resources);
|
||||
extern "C" int InitPreprocessor(void);
|
||||
extern "C" int FinalizePreprocessor(void);
|
||||
|
||||
|
@ -38,95 +38,43 @@
|
||||
#include "Include/InitializeParseContext.h"
|
||||
#include "osinclude.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, int v, EProfile p, EShLanguage L, TInfoSink& is) :
|
||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
||||
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
||||
switchNestingLevel(0), inTypeParen(false),
|
||||
version(v), profile(p), futureCompatibility(false),
|
||||
contextPragma(true, false)
|
||||
{
|
||||
for (int type = 0; type < EbtNumTypes; ++type)
|
||||
defaultPrecision[type] = EpqNone;
|
||||
|
||||
if (profile == EEsProfile) {
|
||||
switch (language) {
|
||||
case EShLangVertex:
|
||||
defaultPrecision[EbtInt] = EpqHigh;
|
||||
defaultPrecision[EbtFloat] = EpqHigh;
|
||||
defaultPrecision[EbtSampler2D] = EpqLow;
|
||||
defaultPrecision[EbtSamplerCube] = EpqLow;
|
||||
break;
|
||||
case EShLangFragment:
|
||||
defaultPrecision[EbtInt] = EpqMedium;
|
||||
defaultPrecision[EbtSampler2D] = EpqLow;
|
||||
defaultPrecision[EbtSamplerCube] = EpqLow;
|
||||
// TODO: give error when using float in frag shader without default precision
|
||||
break;
|
||||
default:
|
||||
error(1, "INTERNAL ERROR", "unexpected language", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Sub- vector and matrix fields
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is, int defaultVersion) :
|
||||
intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0),
|
||||
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
|
||||
switchNestingLevel(0), inTypeParen(false),
|
||||
futureCompatibility(false),
|
||||
contextPragma(true, false)
|
||||
{
|
||||
// Default precisions for version 110, to be overridden for
|
||||
// other versions/profiles/stage combinations
|
||||
for (int type = 0; type < EbtNumTypes; ++type)
|
||||
defaultPrecision[type] = EpqNone;
|
||||
|
||||
setVersion(defaultVersion);
|
||||
setProfile(ENoProfile);
|
||||
}
|
||||
|
||||
void TParseContext::setVersion(int newVersion)
|
||||
{
|
||||
version = newVersion;
|
||||
if (version == 100 || version == 300) {
|
||||
if (language == EShLangVertex) {
|
||||
defaultPrecision[EbtInt] = EpqHigh;
|
||||
defaultPrecision[EbtFloat] = EpqHigh;
|
||||
defaultPrecision[EbtSampler2D] = EpqLow;
|
||||
defaultPrecision[EbtSamplerCube] = EpqLow;
|
||||
}
|
||||
|
||||
if (language == EShLangFragment) {
|
||||
defaultPrecision[EbtInt] = EpqMedium;
|
||||
defaultPrecision[EbtSampler2D] = EpqLow;
|
||||
defaultPrecision[EbtSamplerCube] = EpqLow;
|
||||
// TODO: give error when using float in frag shader without default precision
|
||||
}
|
||||
} else {
|
||||
for (int type = 0; type < EbtNumTypes; ++type)
|
||||
defaultPrecision[type] = EpqNone;
|
||||
}
|
||||
}
|
||||
|
||||
// Important assumption: SetVersion() is called before SetProfile(), and is always called
|
||||
// if there is a version, sending in a ENoProfile if there is no profile given.
|
||||
void TParseContext::setProfile(EProfile newProfile)
|
||||
{
|
||||
const int FirstProfileVersion = 150;
|
||||
|
||||
if (newProfile == ENoProfile) {
|
||||
if (version == 300) {
|
||||
error(1, "version 300 requires specifying the 'es' profile", "#version", "");
|
||||
profile = EEsProfile;
|
||||
} else if (version == 100)
|
||||
profile = EEsProfile;
|
||||
else if (version >= FirstProfileVersion)
|
||||
profile = ECoreProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
} else {
|
||||
// a profile was provided...
|
||||
if (version < 150) {
|
||||
error(1, "versions before 150 do not allow a profile token", "#version", "");
|
||||
if (version == 100)
|
||||
profile = EEsProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
} else if (version == 300) {
|
||||
if (newProfile != EEsProfile)
|
||||
error(1, "only version 300 supports the es profile", "#version", "");
|
||||
profile = EEsProfile;
|
||||
} else {
|
||||
if (newProfile == EEsProfile) {
|
||||
error(1, "only version 300 supports the es profile", "#version", "");
|
||||
if (version >= FirstProfileVersion)
|
||||
profile = ECoreProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
} else {
|
||||
// typical desktop case... e.g., "#version 410 core"
|
||||
profile = newProfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Look at a '.' field selector string and change it into offsets
|
||||
// for a vector.
|
||||
@ -380,6 +328,8 @@ bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* nod
|
||||
case EvqAttribute: message = "can't modify an attribute"; break;
|
||||
case EvqUniform: message = "can't modify a uniform"; break;
|
||||
case EvqVaryingIn: message = "can't modify a varying"; break;
|
||||
case EvqInstanceId: message = "can't modify gl_InstanceID"; break;
|
||||
case EvqVertexId: message = "can't modify gl_VertexID"; break;
|
||||
case EvqFace: message = "can't modify gl_FrontFace"; break;
|
||||
case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
|
||||
case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
|
||||
@ -767,9 +717,10 @@ bool TParseContext::insertBuiltInArrayAtGlobalLevel()
|
||||
{
|
||||
TString *name = NewPoolTString("gl_TexCoord");
|
||||
TSymbol* symbol = symbolTable.find(*name);
|
||||
if (!symbol) {
|
||||
error(0, "INTERNAL ERROR finding symbol", name->c_str(), "");
|
||||
return true;
|
||||
if (! symbol) {
|
||||
// assume it was not added due to version/profile
|
||||
|
||||
return false;
|
||||
}
|
||||
TVariable* variable = symbol->getAsVariable();
|
||||
|
||||
|
@ -67,9 +67,9 @@ struct TPragma {
|
||||
// they can be passed to the parser without needing a global.
|
||||
//
|
||||
struct TParseContext {
|
||||
TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is, int defaultVersion);
|
||||
TParseContext(TSymbolTable&, TIntermediate&, int version, EProfile, EShLanguage, TInfoSink&);
|
||||
TIntermediate& intermediate; // to hold and build a parse tree
|
||||
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
|
||||
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
|
||||
TInfoSink& infoSink;
|
||||
EShLanguage language; // vertex or fragment language
|
||||
TIntermNode* treeRoot; // root of parse tree being created
|
||||
@ -92,9 +92,6 @@ struct TParseContext {
|
||||
TString HashErrMsg;
|
||||
bool AfterEOF;
|
||||
|
||||
void setVersion(int);
|
||||
void setProfile(EProfile);
|
||||
|
||||
void initializeExtensionBehavior();
|
||||
|
||||
void C_DECL error(TSourceLoc, const char *szReason, const char *szToken,
|
||||
|
@ -53,7 +53,6 @@ void InitializeGlobalPools()
|
||||
threadData->globalPoolAllocator = globalPoolAllocator;
|
||||
|
||||
OS_SetTLSValue(PoolIndex, threadData);
|
||||
globalPoolAllocator->push();
|
||||
}
|
||||
|
||||
void FreeGlobalPools()
|
||||
@ -90,11 +89,11 @@ TPoolAllocator& GetGlobalPoolAllocator()
|
||||
return *threadData->globalPoolAllocator;
|
||||
}
|
||||
|
||||
void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator)
|
||||
void SetGlobalPoolAllocatorPtr(TPoolAllocator& poolAllocator)
|
||||
{
|
||||
TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
|
||||
|
||||
threadData->globalPoolAllocator = poolAllocator;
|
||||
threadData->globalPoolAllocator = &poolAllocator;
|
||||
}
|
||||
|
||||
//
|
||||
@ -143,6 +142,8 @@ TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignm
|
||||
if (headerSkip < sizeof(tHeader)) {
|
||||
headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
|
||||
}
|
||||
|
||||
push();
|
||||
}
|
||||
|
||||
TPoolAllocator::~TPoolAllocator()
|
||||
|
@ -1,5 +1,7 @@
|
||||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
@ -35,7 +37,10 @@
|
||||
//
|
||||
// Implement the top-level of interface to the compiler/linker,
|
||||
// as defined in ShaderLang.h
|
||||
// This is the platform independent interface between an OGL driver
|
||||
// and the shading language compiler/linker.
|
||||
//
|
||||
|
||||
#include "SymbolTable.h"
|
||||
#include "ParseHelper.h"
|
||||
|
||||
@ -45,61 +50,355 @@
|
||||
#define SH_EXPORTING
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "Initialize.h"
|
||||
|
||||
namespace { // anonymous namespace for file-local functions and symbols
|
||||
|
||||
int MapVersionToIndex(int version)
|
||||
{
|
||||
switch(version) {
|
||||
case 100: return 0;
|
||||
case 110: return 1;
|
||||
case 120: return 2;
|
||||
case 130: return 3;
|
||||
case 140: return 4;
|
||||
case 150: return 5;
|
||||
case 300: return 6;
|
||||
case 330: return 7;
|
||||
case 400: return 8;
|
||||
case 410: return 9;
|
||||
case 420: return 10;
|
||||
case 430: return 11;
|
||||
default: // |
|
||||
return 0; // |
|
||||
} // |
|
||||
} // V
|
||||
const int VersionCount = 12;
|
||||
|
||||
//
|
||||
// A symbol table for each language. Each has a different
|
||||
// set of built-ins, and we want to preserve that from
|
||||
// A symbol table per version per profile per language. This will be sparsely
|
||||
// populated, so they will only only be generated as needed.
|
||||
//
|
||||
// Each has a different set of built-ins, and we want to preserve that from
|
||||
// compile to compile.
|
||||
//
|
||||
TSymbolTable SymbolTables[EShLangCount];
|
||||
|
||||
// TODO: thread safety: ensure the built-in symbol table levels are reado only.
|
||||
TSymbolTable* SharedSymbolTables[VersionCount][EProfileCount][EShLangCount] = {};
|
||||
|
||||
TPoolAllocator* PerProcessGPA = 0;
|
||||
//
|
||||
// This is the platform independent interface between an OGL driver
|
||||
// and the shading language compiler/linker.
|
||||
//
|
||||
|
||||
bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, int version, EProfile profile, EShLanguage language, TInfoSink& infoSink,
|
||||
const TBuiltInResource* resources, TSymbolTable* symbolTables)
|
||||
{
|
||||
TIntermediate intermediate(infoSink);
|
||||
TSymbolTable* symbolTable;
|
||||
|
||||
if (resources)
|
||||
symbolTable = symbolTables;
|
||||
else
|
||||
symbolTable = &symbolTables[language];
|
||||
|
||||
TParseContext parseContext(*symbolTable, intermediate, version, profile, language, infoSink);
|
||||
|
||||
GlobalParseContext = &parseContext;
|
||||
|
||||
assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel());
|
||||
|
||||
//
|
||||
// Parse the built-ins. This should only happen once per
|
||||
// language symbol table when no 'resources' are passed in.
|
||||
//
|
||||
// Push the symbol table to give it an initial scope. This
|
||||
// push should not have a corresponding pop, so that built-ins
|
||||
// are preserved, and the test for an empty table fails.
|
||||
//
|
||||
|
||||
symbolTable->push();
|
||||
|
||||
|
||||
//Initialize the Preprocessor
|
||||
int ret = InitPreprocessor();
|
||||
if (ret) {
|
||||
infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor");
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetFlex();
|
||||
|
||||
for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin();
|
||||
i != BuiltInStrings[parseContext.language].end(); ++i) {
|
||||
const char* builtInShaders[1];
|
||||
int builtInLengths[1];
|
||||
|
||||
builtInShaders[0] = (*i).c_str();
|
||||
builtInLengths[0] = (int) (*i).size();
|
||||
|
||||
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0) {
|
||||
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
FinalizePreprocessor();
|
||||
|
||||
if (resources) {
|
||||
IdentifyBuiltIns(version, profile, parseContext.language, *symbolTable, *resources);
|
||||
} else {
|
||||
IdentifyBuiltIns(version, profile, parseContext.language, *symbolTable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GenerateBuiltInSymbolTable(TInfoSink& infoSink, TSymbolTable* symbolTables, int version, EProfile profile)
|
||||
{
|
||||
TBuiltIns builtIns;
|
||||
|
||||
builtIns.initialize(version, profile);
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), version, profile, EShLangVertex, infoSink, 0, symbolTables);
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), version, profile, EShLangFragment, infoSink, 0, symbolTables);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddContextSpecificSymbols(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, int version, EProfile profile, EShLanguage language)
|
||||
{
|
||||
TBuiltIns builtIns;
|
||||
|
||||
builtIns.initialize(*resources, version, profile, language);
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), version, profile, language, infoSink, resources, symbolTables);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Driver must call this first, once, before doing any other
|
||||
// compiler/linker operations.
|
||||
//
|
||||
int ShInitialize()
|
||||
|
||||
void SetupBuiltinSymbolTable(int version, EProfile profile)
|
||||
{
|
||||
TInfoSink infoSink;
|
||||
bool ret = true;
|
||||
|
||||
if (!InitProcess())
|
||||
return 0;
|
||||
// This function is for lazy setup. See if already done.
|
||||
int versionIndex = MapVersionToIndex(version);
|
||||
if (SharedSymbolTables[versionIndex][profile][EShLangVertex])
|
||||
return;
|
||||
|
||||
// This method should be called once per process. If its called by multiple threads, then
|
||||
// we need to have thread synchronization code around the initialization of per process
|
||||
// global pool allocator
|
||||
if (!PerProcessGPA) {
|
||||
TPoolAllocator& savedGPA = GetGlobalPoolAllocator();
|
||||
TPoolAllocator *builtInPoolAllocator = new TPoolAllocator(true);
|
||||
builtInPoolAllocator->push();
|
||||
TPoolAllocator* gPoolAllocator = &GlobalPoolAllocator;
|
||||
SetGlobalPoolAllocatorPtr(builtInPoolAllocator);
|
||||
SetGlobalPoolAllocatorPtr(*builtInPoolAllocator);
|
||||
|
||||
TSymbolTable symTables[EShLangCount];
|
||||
GenerateBuiltInSymbolTable(0, infoSink, symTables);
|
||||
GenerateBuiltInSymbolTable(infoSink, symTables, version, profile);
|
||||
|
||||
PerProcessGPA = new TPoolAllocator(true);
|
||||
PerProcessGPA->push();
|
||||
SetGlobalPoolAllocatorPtr(PerProcessGPA);
|
||||
SetGlobalPoolAllocatorPtr(*PerProcessGPA);
|
||||
|
||||
SymbolTables[EShLangVertex].copyTable(symTables[EShLangVertex]);
|
||||
SymbolTables[EShLangFragment].copyTable(symTables[EShLangFragment]);
|
||||
|
||||
SetGlobalPoolAllocatorPtr(gPoolAllocator);
|
||||
SharedSymbolTables[versionIndex][profile][EShLangVertex] = new TSymbolTable;
|
||||
SharedSymbolTables[versionIndex][profile][EShLangVertex]->copyTable(symTables[EShLangVertex]);
|
||||
SharedSymbolTables[versionIndex][profile][EShLangFragment] = new TSymbolTable;
|
||||
SharedSymbolTables[versionIndex][profile][EShLangFragment]->copyTable(symTables[EShLangFragment]);
|
||||
|
||||
symTables[EShLangVertex].pop(0);
|
||||
symTables[EShLangFragment].pop(0);
|
||||
|
||||
builtInPoolAllocator->popAll();
|
||||
delete builtInPoolAllocator;
|
||||
|
||||
SetGlobalPoolAllocatorPtr(savedGPA);
|
||||
}
|
||||
|
||||
// returns true if something whas consumed
|
||||
bool ConsumeWhitespaceComment(const char*& s)
|
||||
{
|
||||
const char* startPoint = s;
|
||||
|
||||
// first, skip white space
|
||||
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') {
|
||||
++s;
|
||||
}
|
||||
|
||||
return ret ? 1 : 0;
|
||||
// then, check for a comment
|
||||
if (*s == '/') {
|
||||
if (*(s+1) == '/') {
|
||||
s += 2;
|
||||
do {
|
||||
while (*s && *s != '\\' && *s != '\n')
|
||||
++s;
|
||||
|
||||
if (*s == '\n' || *s == 0) {
|
||||
if (*s == '\n') {
|
||||
++s;
|
||||
if (*s == '\r')
|
||||
++s;
|
||||
} // else it's 0, end of string
|
||||
|
||||
// we reached the end of the comment
|
||||
break;
|
||||
} else {
|
||||
// it's a '\', so we need to keep going, after skipping what's escaped
|
||||
++s;
|
||||
if (*s == '\n') {
|
||||
++s;
|
||||
if (*s == '\r')
|
||||
++s;
|
||||
} else {
|
||||
// skip the escaped character
|
||||
if (*s)
|
||||
++s;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
} else if (*(s+1) == '*') {
|
||||
s += 2;
|
||||
do {
|
||||
while (*s && *s != '*')
|
||||
++s;
|
||||
if (*s == '*') {
|
||||
++s;
|
||||
if (*s == '/') {
|
||||
++s;
|
||||
break;
|
||||
} // else not end of comment, keep going
|
||||
} else // end of string
|
||||
break;
|
||||
} while (true);
|
||||
} // else it's not a comment
|
||||
} // else it's not a comment
|
||||
|
||||
return startPoint != s;
|
||||
}
|
||||
|
||||
void ScanVersion(const char* const shaderStrings[], int numStrings, int& version, EProfile& profile)
|
||||
{
|
||||
// This function doesn't have to get all the semantics correct,
|
||||
// just find the #version if there is a correct one present.
|
||||
// The CPP will have the responsibility of getting all the semantics right.
|
||||
|
||||
version = 0; // means not found
|
||||
profile = ENoProfile;
|
||||
|
||||
const char* s = &shaderStrings[0][0];
|
||||
|
||||
// TODO: ES error check: #version must be on first line
|
||||
|
||||
while (ConsumeWhitespaceComment(s))
|
||||
;
|
||||
|
||||
// #
|
||||
if (*s != '#')
|
||||
return;
|
||||
++s;
|
||||
|
||||
// whitespace
|
||||
while (*s == ' ' || *s == '\t') {
|
||||
++s;
|
||||
}
|
||||
|
||||
// version
|
||||
if (strncmp(s, "version", 7) != 0)
|
||||
return;
|
||||
|
||||
// whitespace
|
||||
s += 7;
|
||||
while (*s == ' ' || *s == '\t') {
|
||||
++s;
|
||||
}
|
||||
|
||||
// version number
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
version = 10 * version + (*s - '0');
|
||||
++s;
|
||||
}
|
||||
if (version == 0)
|
||||
return;
|
||||
|
||||
// whitespace
|
||||
while (*s == ' ' || *s == '\t') {
|
||||
++s;
|
||||
}
|
||||
|
||||
// profile
|
||||
const char* end = s;
|
||||
while (*end != ' ' && *end != '\t' && *end != '\n') {
|
||||
if (*end == 0)
|
||||
return;
|
||||
++end;
|
||||
}
|
||||
int profileLength = end - s;
|
||||
if (profileLength == 2 && strncmp(s, "es", profileLength) == 0)
|
||||
profile = EEsProfile;
|
||||
else if (profileLength == 4 && strncmp(s, "core", profileLength) == 0)
|
||||
profile = ECoreProfile;
|
||||
else if (profileLength == 13 && strncmp(s, "compatibility", profileLength) == 0)
|
||||
profile = ECompatibilityProfile;
|
||||
}
|
||||
|
||||
bool DeduceProfile(TInfoSink& infoSink, int version, EProfile& profile)
|
||||
{
|
||||
const int FirstProfileVersion = 150;
|
||||
|
||||
if (profile == ENoProfile) {
|
||||
if (version == 300) {
|
||||
infoSink.info.message(EPrefixError, "#version: version 300 requires specifying the 'es' profile");
|
||||
profile = EEsProfile;
|
||||
|
||||
return false;
|
||||
} else if (version == 100)
|
||||
profile = EEsProfile;
|
||||
else if (version >= FirstProfileVersion)
|
||||
profile = ECoreProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
} else {
|
||||
// a profile was provided...
|
||||
if (version < 150) {
|
||||
infoSink.info.message(EPrefixError, "#version: versions before 150 do not allow a profile token");
|
||||
if (version == 100)
|
||||
profile = EEsProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
|
||||
return false;
|
||||
} else if (version == 300) {
|
||||
if (profile != EEsProfile) {
|
||||
infoSink.info.message(EPrefixError, "#version: version 300 supports only the es profile");
|
||||
|
||||
return false;
|
||||
}
|
||||
profile = EEsProfile;
|
||||
} else {
|
||||
if (profile == EEsProfile) {
|
||||
infoSink.info.message(EPrefixError, "#version: only version 300 supports the es profile");
|
||||
if (version >= FirstProfileVersion)
|
||||
profile = ECoreProfile;
|
||||
else
|
||||
profile = ENoProfile;
|
||||
|
||||
return false;
|
||||
}
|
||||
// else: typical desktop case... e.g., "#version 410 core"
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}; // end anonymous namespace for local functions
|
||||
|
||||
int ShInitialize()
|
||||
{
|
||||
if (! InitProcess())
|
||||
return 0;
|
||||
|
||||
// TODO: Thread safety:
|
||||
// This method should be called once per process. If it's called by multiple threads, then
|
||||
// we need to have thread synchronization code around the initialization of per process
|
||||
// global pool allocator
|
||||
if (! PerProcessGPA) {
|
||||
PerProcessGPA = new TPoolAllocator(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
@ -157,6 +456,11 @@ void ShDestruct(ShHandle handle)
|
||||
//
|
||||
int __fastcall ShFinalize()
|
||||
{
|
||||
for (int version = 0; version < VersionCount; ++version)
|
||||
for (int p = 0; p < EProfileCount; ++p)
|
||||
for (int lang = 0; lang < EShLangCount; ++lang)
|
||||
delete SharedSymbolTables[version][p][lang];
|
||||
|
||||
if (PerProcessGPA) {
|
||||
PerProcessGPA->popAll();
|
||||
delete PerProcessGPA;
|
||||
@ -164,82 +468,6 @@ int __fastcall ShFinalize()
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, EShLanguage language)
|
||||
{
|
||||
TBuiltIns builtIns;
|
||||
|
||||
if (resources) {
|
||||
builtIns.initialize(*resources);
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), language, infoSink, resources, symbolTables);
|
||||
} else {
|
||||
builtIns.initialize();
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangVertex, infoSink, resources, symbolTables);
|
||||
InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangFragment, infoSink, resources, symbolTables);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource* resources, TSymbolTable* symbolTables)
|
||||
{
|
||||
TIntermediate intermediate(infoSink);
|
||||
TSymbolTable* symbolTable;
|
||||
|
||||
if (resources)
|
||||
symbolTable = symbolTables;
|
||||
else
|
||||
symbolTable = &symbolTables[language];
|
||||
|
||||
TParseContext parseContext(*symbolTable, intermediate, language, infoSink, 110);
|
||||
|
||||
GlobalParseContext = &parseContext;
|
||||
|
||||
assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel());
|
||||
|
||||
//
|
||||
// Parse the built-ins. This should only happen once per
|
||||
// language symbol table when no 'resources' are passed in.
|
||||
//
|
||||
// Push the symbol table to give it an initial scope. This
|
||||
// push should not have a corresponding pop, so that built-ins
|
||||
// are preserved, and the test for an empty table fails.
|
||||
//
|
||||
|
||||
symbolTable->push();
|
||||
|
||||
|
||||
//Initialize the Preprocessor
|
||||
int ret = InitPreprocessor();
|
||||
if (ret) {
|
||||
infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor");
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetFlex();
|
||||
|
||||
for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin();
|
||||
i != BuiltInStrings[parseContext.language].end(); ++i) {
|
||||
const char* builtInShaders[1];
|
||||
int builtInLengths[1];
|
||||
|
||||
builtInShaders[0] = (*i).c_str();
|
||||
builtInLengths[0] = (int) (*i).size();
|
||||
|
||||
if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0) {
|
||||
infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
FinalizePreprocessor();
|
||||
|
||||
if (resources) {
|
||||
IdentifyBuiltIns(parseContext.language, *symbolTable, *resources);
|
||||
} else {
|
||||
IdentifyBuiltIns(parseContext.language, *symbolTable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Do an actual compile on the given strings. The result is left
|
||||
// in the given compile object.
|
||||
@ -262,7 +490,6 @@ int ShCompile(
|
||||
|
||||
if (handle == 0)
|
||||
return 0;
|
||||
|
||||
TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
|
||||
TCompiler* compiler = base->getAsCompiler();
|
||||
if (compiler == 0)
|
||||
@ -275,14 +502,29 @@ int ShCompile(
|
||||
if (numStrings == 0)
|
||||
return 1;
|
||||
|
||||
int version;
|
||||
EProfile profile;
|
||||
ScanVersion(shaderStrings, numStrings, version, profile);
|
||||
if (version == 0)
|
||||
version = defaultVersion;
|
||||
bool goodProfile = DeduceProfile(compiler->infoSink, version, profile);
|
||||
|
||||
TIntermediate intermediate(compiler->infoSink);
|
||||
TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]);
|
||||
|
||||
SetupBuiltinSymbolTable(version, profile);
|
||||
TSymbolTable symbolTable(*SharedSymbolTables[MapVersionToIndex(version)]
|
||||
[profile]
|
||||
[compiler->getLanguage()]);
|
||||
|
||||
// Add built-in symbols that are potentially context dependent;
|
||||
// they get popped again further down.
|
||||
GenerateBuiltInSymbolTable(resources, compiler->infoSink, &symbolTable, compiler->getLanguage());
|
||||
AddContextSpecificSymbols(resources, compiler->infoSink, &symbolTable, version, profile, compiler->getLanguage());
|
||||
|
||||
TParseContext parseContext(symbolTable, intermediate, version, profile, compiler->getLanguage(), compiler->infoSink);
|
||||
|
||||
if (! goodProfile)
|
||||
parseContext.error(1, "incorrect", "#version", "");
|
||||
|
||||
TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink, defaultVersion);
|
||||
parseContext.initializeExtensionBehavior();
|
||||
|
||||
GlobalParseContext = &parseContext;
|
||||
@ -298,7 +540,7 @@ int ShCompile(
|
||||
bool success = true;
|
||||
|
||||
symbolTable.push();
|
||||
if (!symbolTable.atGlobalLevel())
|
||||
if (! symbolTable.atGlobalLevel())
|
||||
parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
|
||||
|
||||
if (parseContext.insertBuiltInArrayAtGlobalLevel())
|
||||
@ -326,7 +568,7 @@ int ShCompile(
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
} else if (!success) {
|
||||
} else if (! success) {
|
||||
parseContext.infoSink.info.prefix(EPrefixError);
|
||||
parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
|
||||
success = false;
|
||||
@ -579,4 +821,3 @@ int ShGetUniformLocation(const ShHandle handle, const char* name)
|
||||
|
||||
return uniformMap->getLocation(name);
|
||||
}
|
||||
|
||||
|
@ -479,14 +479,14 @@ int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseCon
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (!argv[i]) {
|
||||
if (! argv[i]) {
|
||||
parseContextLocal.error(0, "Null shader source string", "", "");
|
||||
parseContextLocal.recover();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strLen) {
|
||||
if (! strLen) {
|
||||
argv0len = (int) strlen(argv[0]);
|
||||
strLen = &argv0len;
|
||||
}
|
||||
@ -499,7 +499,16 @@ int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseCon
|
||||
cpp->notAVersionToken = 0;
|
||||
yylineno = 1;
|
||||
|
||||
if (*cpp->PaStrLen >= 0) {
|
||||
// TODO: CPP: a shader containing nothing but white space and comments is valid, even though it has no parse tokens
|
||||
int len = 0;
|
||||
while (argv[0][len] == ' ' ||
|
||||
argv[0][len] == '\t' ||
|
||||
argv[0][len] == '\n' ||
|
||||
argv[0][len] == '\r')
|
||||
if (++len >= strLen[0])
|
||||
return 0;
|
||||
|
||||
if (*cpp->PaStrLen > 0) {
|
||||
int ret;
|
||||
#ifdef _WIN32
|
||||
ret = yyparse(parseContextLocal);
|
||||
@ -510,8 +519,7 @@ int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseCon
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -838,14 +846,18 @@ void ResetTString(void)
|
||||
|
||||
void SetVersion(int version)
|
||||
{
|
||||
TParseContext& pc = *((TParseContext *)cpp->pC);
|
||||
pc.setVersion(version);
|
||||
// called by the CPP, but this functionality is currently
|
||||
// taken over by ScanVersion() before parsing starts
|
||||
|
||||
// CPP should still report errors in semantics
|
||||
}
|
||||
|
||||
void SetProfile(EProfile profile)
|
||||
{
|
||||
TParseContext& pc = *((TParseContext *)cpp->pC);
|
||||
pc.setProfile(profile);
|
||||
// called by the CPP, but this functionality is currently
|
||||
// taken over by ScanVersion() before parsing starts
|
||||
|
||||
// CPP should still report errors in semantics
|
||||
}
|
||||
|
||||
TBehavior GetBehavior(const char* behavior)
|
||||
|
@ -78,6 +78,8 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// cpp.c
|
||||
//
|
||||
|
||||
// TODO: CPP handle escaped newlines in a // style comment, correctly done in ConsumeWhitespaceComment()
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <stdarg.h>
|
||||
|
Loading…
Reference in New Issue
Block a user