summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler')
-rw-r--r--src/3rdparty/angle/src/compiler/BaseTypes.h152
-rw-r--r--src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp406
-rw-r--r--src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h93
-rw-r--r--src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp34
-rw-r--r--src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp31
-rw-r--r--src/3rdparty/angle/src/compiler/Common.h89
-rw-r--r--src/3rdparty/angle/src/compiler/Compiler.cpp350
-rw-r--r--src/3rdparty/angle/src/compiler/ConstantUnion.h256
-rw-r--r--src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp119
-rw-r--r--src/3rdparty/angle/src/compiler/DetectDiscontinuity.h50
-rw-r--r--src/3rdparty/angle/src/compiler/DetectRecursion.cpp125
-rw-r--r--src/3rdparty/angle/src/compiler/DetectRecursion.h60
-rw-r--r--src/3rdparty/angle/src/compiler/Diagnostics.cpp63
-rw-r--r--src/3rdparty/angle/src/compiler/Diagnostics.h44
-rw-r--r--src/3rdparty/angle/src/compiler/DirectiveHandler.cpp161
-rw-r--r--src/3rdparty/angle/src/compiler/DirectiveHandler.h46
-rw-r--r--src/3rdparty/angle/src/compiler/ExtensionBehavior.h37
-rw-r--r--src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp215
-rw-r--r--src/3rdparty/angle/src/compiler/ForLoopUnroll.h48
-rw-r--r--src/3rdparty/angle/src/compiler/InfoSink.cpp59
-rw-r--r--src/3rdparty/angle/src/compiler/InfoSink.h115
-rw-r--r--src/3rdparty/angle/src/compiler/Initialize.cpp657
-rw-r--r--src/3rdparty/angle/src/compiler/Initialize.h35
-rw-r--r--src/3rdparty/angle/src/compiler/InitializeDll.cpp115
-rw-r--r--src/3rdparty/angle/src/compiler/InitializeDll.h16
-rw-r--r--src/3rdparty/angle/src/compiler/InitializeGlobals.h15
-rw-r--r--src/3rdparty/angle/src/compiler/InitializeParseContext.cpp96
-rw-r--r--src/3rdparty/angle/src/compiler/InitializeParseContext.h26
-rw-r--r--src/3rdparty/angle/src/compiler/IntermTraverse.cpp293
-rw-r--r--src/3rdparty/angle/src/compiler/Intermediate.cpp1447
-rw-r--r--src/3rdparty/angle/src/compiler/MMap.h56
-rw-r--r--src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp122
-rw-r--r--src/3rdparty/angle/src/compiler/MapLongVariableNames.h59
-rw-r--r--src/3rdparty/angle/src/compiler/OutputESSL.cpp22
-rw-r--r--src/3rdparty/angle/src/compiler/OutputESSL.h21
-rw-r--r--src/3rdparty/angle/src/compiler/OutputGLSL.cpp17
-rw-r--r--src/3rdparty/angle/src/compiler/OutputGLSL.h21
-rw-r--r--src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp720
-rw-r--r--src/3rdparty/angle/src/compiler/OutputGLSLBase.h53
-rw-r--r--src/3rdparty/angle/src/compiler/OutputHLSL.cpp2664
-rw-r--r--src/3rdparty/angle/src/compiler/OutputHLSL.h152
-rw-r--r--src/3rdparty/angle/src/compiler/ParseHelper.cpp1528
-rw-r--r--src/3rdparty/angle/src/compiler/ParseHelper.h140
-rw-r--r--src/3rdparty/angle/src/compiler/PoolAlloc.cpp310
-rw-r--r--src/3rdparty/angle/src/compiler/PoolAlloc.h306
-rw-r--r--src/3rdparty/angle/src/compiler/Pragma.h19
-rw-r--r--src/3rdparty/angle/src/compiler/QualifierAlive.cpp58
-rw-r--r--src/3rdparty/angle/src/compiler/QualifierAlive.h7
-rw-r--r--src/3rdparty/angle/src/compiler/RemoveTree.cpp77
-rw-r--r--src/3rdparty/angle/src/compiler/RemoveTree.h7
-rw-r--r--src/3rdparty/angle/src/compiler/RenameFunction.h36
-rw-r--r--src/3rdparty/angle/src/compiler/SearchSymbol.cpp38
-rw-r--r--src/3rdparty/angle/src/compiler/SearchSymbol.h33
-rw-r--r--src/3rdparty/angle/src/compiler/ShHandle.h142
-rw-r--r--src/3rdparty/angle/src/compiler/ShaderLang.cpp285
-rw-r--r--src/3rdparty/angle/src/compiler/SymbolTable.cpp279
-rw-r--r--src/3rdparty/angle/src/compiler/SymbolTable.h359
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorESSL.cpp40
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorESSL.h23
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp41
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorGLSL.h20
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp23
-rw-r--r--src/3rdparty/angle/src/compiler/TranslatorHLSL.h20
-rw-r--r--src/3rdparty/angle/src/compiler/Types.h318
-rw-r--r--src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp172
-rw-r--r--src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h39
-rw-r--r--src/3rdparty/angle/src/compiler/ValidateLimitations.cpp512
-rw-r--r--src/3rdparty/angle/src/compiler/ValidateLimitations.h59
-rw-r--r--src/3rdparty/angle/src/compiler/VariableInfo.cpp232
-rw-r--r--src/3rdparty/angle/src/compiler/VariableInfo.h46
-rw-r--r--src/3rdparty/angle/src/compiler/VariablePacker.cpp297
-rw-r--r--src/3rdparty/angle/src/compiler/VariablePacker.h41
-rw-r--r--src/3rdparty/angle/src/compiler/VersionGLSL.cpp140
-rw-r--r--src/3rdparty/angle/src/compiler/VersionGLSL.h56
-rw-r--r--src/3rdparty/angle/src/compiler/debug.cpp37
-rw-r--r--src/3rdparty/angle/src/compiler/debug.h53
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp97
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h212
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp227
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h181
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp65
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h30
-rw-r--r--src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp69
-rw-r--r--src/3rdparty/angle/src/compiler/glslang.h16
-rw-r--r--src/3rdparty/angle/src/compiler/glslang.l511
-rw-r--r--src/3rdparty/angle/src/compiler/glslang.y2142
-rw-r--r--src/3rdparty/angle/src/compiler/intermOut.cpp419
-rw-r--r--src/3rdparty/angle/src/compiler/intermediate.h557
-rw-r--r--src/3rdparty/angle/src/compiler/localintermediate.h58
-rw-r--r--src/3rdparty/angle/src/compiler/osinclude.h72
-rw-r--r--src/3rdparty/angle/src/compiler/ossource_nspr.cpp43
-rw-r--r--src/3rdparty/angle/src/compiler/ossource_posix.cpp64
-rw-r--r--src/3rdparty/angle/src/compiler/ossource_win.cpp57
-rw-r--r--src/3rdparty/angle/src/compiler/parseConst.cpp238
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/atom.c737
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/atom.h63
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/compile.h100
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/cpp.c1118
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/cpp.h86
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c152
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/length_limits.h21
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/memory.c158
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/memory.h58
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp127
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h87
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp16
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h43
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp932
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h82
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h34
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y279
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp55
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Input.h48
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp16
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h25
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp23
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h44
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp370
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h75
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp142
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h49
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h38
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp83
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Token.h106
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h58
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l340
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h61
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h18
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/parser.h93
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/preprocess.h50
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/scanner.c698
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/scanner.h81
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/slglobals.h82
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/symbols.c288
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/symbols.h111
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/tokens.c467
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/tokens.h90
-rw-r--r--src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp127
-rw-r--r--src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h40
-rw-r--r--src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp17
-rw-r--r--src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h33
-rw-r--r--src/3rdparty/angle/src/compiler/util.cpp33
-rw-r--r--src/3rdparty/angle/src/compiler/util.h21
143 files changed, 27886 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/BaseTypes.h b/src/3rdparty/angle/src/compiler/BaseTypes.h
new file mode 100644
index 0000000000..5f83185304
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/BaseTypes.h
@@ -0,0 +1,152 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+//
+// Precision qualifiers
+//
+enum TPrecision
+{
+ // These need to be kept sorted
+ EbpUndefined,
+ EbpLow,
+ EbpMedium,
+ EbpHigh,
+};
+
+inline const char* getPrecisionString(TPrecision p)
+{
+ switch(p)
+ {
+ case EbpHigh: return "highp"; break;
+ case EbpMedium: return "mediump"; break;
+ case EbpLow: return "lowp"; break;
+ default: return "mediump"; break; // Safest fallback
+ }
+}
+
+//
+// Basic type. Arrays, vectors, etc., are orthogonal to this.
+//
+enum TBasicType
+{
+ EbtVoid,
+ EbtFloat,
+ EbtInt,
+ EbtBool,
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D,
+ EbtSamplerCube,
+ EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
+ EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
+ EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
+ EbtStruct,
+ EbtAddress, // should be deprecated??
+ EbtInvariant, // used as a type when qualifying a previously declared variable as being invariant
+};
+
+inline const char* getBasicString(TBasicType t)
+{
+ switch (t)
+ {
+ case EbtVoid: return "void"; break;
+ case EbtFloat: return "float"; break;
+ case EbtInt: return "int"; break;
+ case EbtBool: return "bool"; break;
+ case EbtSampler2D: return "sampler2D"; break;
+ case EbtSamplerCube: return "samplerCube"; break;
+ case EbtSamplerExternalOES: return "samplerExternalOES"; break;
+ case EbtSampler2DRect: return "sampler2DRect"; break;
+ case EbtStruct: return "structure"; break;
+ default: return "unknown type";
+ }
+}
+
+inline bool IsSampler(TBasicType type)
+{
+ return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
+}
+
+//
+// Qualifiers and built-ins. These are mainly used to see what can be read
+// or written, and by the machine dependent translator to know which registers
+// to allocate variables in. Since built-ins tend to go to different registers
+// than varying or uniform, it makes sense they are peers, not sub-classes.
+//
+enum TQualifier
+{
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqInvariantVaryingIn, // readonly, fragment shaders only
+ EvqInvariantVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+
+ // pack/unpack input and output
+ EvqInput,
+ EvqOutput,
+
+ // parameters
+ EvqIn,
+ EvqOut,
+ EvqInOut,
+ EvqConstReadOnly,
+
+ // built-ins written by vertex shader
+ EvqPosition,
+ EvqPointSize,
+
+ // built-ins read by fragment shader
+ EvqFragCoord,
+ EvqFrontFacing,
+ EvqPointCoord,
+
+ // built-ins written by fragment shader
+ EvqFragColor,
+ EvqFragData,
+
+ // end of list
+ EvqLast,
+};
+
+//
+// This is just for debug print out, carried along with the definitions above.
+//
+inline const char* getQualifierString(TQualifier q)
+{
+ switch(q)
+ {
+ case EvqTemporary: return "Temporary"; break;
+ case EvqGlobal: return "Global"; break;
+ case EvqConst: return "const"; break;
+ case EvqConstReadOnly: return "const"; break;
+ case EvqAttribute: return "attribute"; break;
+ case EvqVaryingIn: return "varying"; break;
+ case EvqVaryingOut: return "varying"; break;
+ case EvqInvariantVaryingIn: return "invariant varying"; break;
+ case EvqInvariantVaryingOut:return "invariant varying"; break;
+ case EvqUniform: return "uniform"; break;
+ case EvqIn: return "in"; break;
+ case EvqOut: return "out"; break;
+ case EvqInOut: return "inout"; break;
+ case EvqInput: return "input"; break;
+ case EvqOutput: return "output"; break;
+ case EvqPosition: return "Position"; break;
+ case EvqPointSize: return "PointSize"; break;
+ case EvqFragCoord: return "FragCoord"; break;
+ case EvqFrontFacing: return "FrontFacing"; break;
+ case EvqFragColor: return "FragColor"; break;
+ case EvqFragData: return "FragData"; break;
+ default: return "unknown qualifier";
+ }
+}
+
+#endif // _BASICTYPES_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp
new file mode 100644
index 0000000000..1c4b25f13f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,406 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/BuiltInFunctionEmulator.h"
+
+#include "compiler/SymbolTable.h"
+
+namespace {
+
+// we use macros here instead of function definitions to work around more GLSL
+// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
+// problematic because if the argument has side-effects they will be repeatedly
+// evaluated. This is unlikely to show up in real shaders, but is something to
+// consider.
+const char* kFunctionEmulationVertexSource[] = {
+ "#error no emulation for cos(float)",
+ "#error no emulation for cos(vec2)",
+ "#error no emulation for cos(vec3)",
+ "#error no emulation for cos(vec4)",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const char* kFunctionEmulationFragmentSource[] = {
+ "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
+ "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
+ "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
+ "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const bool kFunctionEmulationVertexMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+const bool kFunctionEmulationFragmentMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ true, // TFunctionCos1
+ true, // TFunctionCos2
+ true, // TFunctionCos3
+ true, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+class BuiltInFunctionEmulationMarker : public TIntermTraverser {
+public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
+ : mEmulator(emulator)
+ {
+ }
+
+ virtual bool visitUnary(Visit visit, TIntermUnary* node)
+ {
+ if (visit == PreVisit) {
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), node->getOperand()->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ if (visit == PreVisit) {
+ // Here we handle all the built-in functions instead of the ones we
+ // currently identified as problematic.
+ switch (node->getOp()) {
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpMod:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpMul:
+ break;
+ default:
+ return true;
+ };
+ const TIntermSequence& sequence = node->getSequence();
+ // Right now we only handle built-in functions with two parameters.
+ if (sequence.size() != 2)
+ return true;
+ TIntermTyped* param1 = sequence[0]->getAsTyped();
+ TIntermTyped* param2 = sequence[1]->getAsTyped();
+ if (!param1 || !param2)
+ return true;
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), param1->getType(), param2->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+private:
+ BuiltInFunctionEmulator& mEmulator;
+};
+
+} // anonymous namepsace
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
+{
+ if (shaderType == SH_FRAGMENT_SHADER) {
+ mFunctionMask = kFunctionEmulationFragmentMask;
+ mFunctionSource = kFunctionEmulationFragmentSource;
+ } else {
+ mFunctionMask = kFunctionEmulationVertexMask;
+ mFunctionSource = kFunctionEmulationVertexSource;
+ }
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param1, param2);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ BuiltInFunctionEmulator::TBuiltInFunction function) {
+ if (function == TFunctionUnknown || mFunctionMask[function] == false)
+ return false;
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ if (mFunctions[i] == function)
+ return true;
+ }
+ mFunctions.push_back(function);
+ return true;
+}
+
+void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
+ TInfoSinkBase& out, bool withPrecision) const
+{
+ if (mFunctions.size() == 0)
+ return;
+ out << "// BEGIN: Generated code for built-in function emulation\n\n";
+ if (withPrecision) {
+ out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
+ << "#define webgl_emu_precision highp\n"
+ << "#else\n"
+ << "#define webgl_emu_precision mediump\n"
+ << "#endif\n\n";
+ } else {
+ out << "#define webgl_emu_precision\n\n";
+ }
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ out << mFunctionSource[mFunctions[i]] << "\n\n";
+ }
+ out << "// END: Generated code for built-in function emulation\n\n";
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param)
+{
+ if (param.getNominalSize() > 4)
+ return TFunctionUnknown;
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpCos:
+ function = TFunctionCos1;
+ break;
+ case EOpLength:
+ function = TFunctionLength1;
+ break;
+ case EOpNormalize:
+ function = TFunctionNormalize1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param.isVector())
+ function += param.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ // Right now for all the emulated functions with two parameters, the two
+ // parameters have the same type.
+ if (param1.isVector() != param2.isVector() ||
+ param1.getNominalSize() != param2.getNominalSize() ||
+ param1.getNominalSize() > 4)
+ return TFunctionUnknown;
+
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpDistance:
+ function = TFunctionDistance1_1;
+ break;
+ case EOpDot:
+ function = TFunctionDot1_1;
+ break;
+ case EOpReflect:
+ function = TFunctionReflect1_1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param1.isVector())
+ function += param1.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
+ TIntermNode* root)
+{
+ ASSERT(root);
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::Cleanup()
+{
+ mFunctions.clear();
+}
+
+//static
+TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
+ const TString& name)
+{
+ ASSERT(name[name.length() - 1] == '(');
+ return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
+}
+
diff --git a/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h
new file mode 100644
index 0000000000..0d904f41d0
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/BuiltInFunctionEmulator.h
@@ -0,0 +1,93 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+//
+// This class decides which built-in functions need to be replaced with the
+// emulated ones.
+// It's only a workaround for OpenGL driver bugs, and isn't needed in general.
+//
+class BuiltInFunctionEmulator {
+public:
+ BuiltInFunctionEmulator(ShShaderType shaderType);
+ // Records that a function is called by the shader and might needs to be
+ // emulated. If the function's group is not in mFunctionGroupFilter, this
+ // becomes an no-op.
+ // Returns true if the function call needs to be replaced with an emulated
+ // one.
+ bool SetFunctionCalled(TOperator op, const TType& param);
+ bool SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2);
+
+ // Output function emulation definition. This should be before any other
+ // shader source.
+ void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const;
+
+ void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
+
+ void Cleanup();
+
+ // "name(" becomes "webgl_name_emu(".
+ static TString GetEmulatedFunctionName(const TString& name);
+
+private:
+ //
+ // Built-in functions.
+ //
+ enum TBuiltInFunction {
+ TFunctionCos1 = 0, // float cos(float);
+ TFunctionCos2, // vec2 cos(vec2);
+ TFunctionCos3, // vec3 cos(vec3);
+ TFunctionCos4, // vec4 cos(vec4);
+
+ TFunctionDistance1_1, // float distance(float, float);
+ TFunctionDistance2_2, // vec2 distance(vec2, vec2);
+ TFunctionDistance3_3, // vec3 distance(vec3, vec3);
+ TFunctionDistance4_4, // vec4 distance(vec4, vec4);
+
+ TFunctionDot1_1, // float dot(float, float);
+ TFunctionDot2_2, // vec2 dot(vec2, vec2);
+ TFunctionDot3_3, // vec3 dot(vec3, vec3);
+ TFunctionDot4_4, // vec4 dot(vec4, vec4);
+
+ TFunctionLength1, // float length(float);
+ TFunctionLength2, // float length(vec2);
+ TFunctionLength3, // float length(vec3);
+ TFunctionLength4, // float length(vec4);
+
+ TFunctionNormalize1, // float normalize(float);
+ TFunctionNormalize2, // vec2 normalize(vec2);
+ TFunctionNormalize3, // vec3 normalize(vec3);
+ TFunctionNormalize4, // vec4 normalize(vec4);
+
+ TFunctionReflect1_1, // float reflect(float, float);
+ TFunctionReflect2_2, // vec2 reflect(vec2, vec2);
+ TFunctionReflect3_3, // vec3 reflect(vec3, vec3);
+ TFunctionReflect4_4, // vec4 reflect(vec4, vec4);
+
+ TFunctionUnknown
+ };
+
+ TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
+ TBuiltInFunction IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2);
+
+ bool SetFunctionCalled(TBuiltInFunction function);
+
+ std::vector<TBuiltInFunction> mFunctions;
+
+ const bool* mFunctionMask; // a boolean flag for each function.
+ const char** mFunctionSource;
+};
+
+#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
diff --git a/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp b/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp
new file mode 100644
index 0000000000..226bf8f0fc
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/CodeGenGLSL.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorGLSL.h"
+#include "compiler/TranslatorESSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_GLSL_OUTPUT:
+ return new TranslatorGLSL(type, spec);
+ case SH_ESSL_OUTPUT:
+ return new TranslatorESSL(type, spec);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp b/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp
new file mode 100644
index 0000000000..f46ff66d40
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/CodeGenHLSL.cpp
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_HLSL_OUTPUT:
+ return new TranslatorHLSL(type, spec);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/src/3rdparty/angle/src/compiler/Common.h b/src/3rdparty/angle/src/compiler/Common.h
new file mode 100644
index 0000000000..27a5598290
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Common.h
@@ -0,0 +1,89 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "compiler/PoolAlloc.h"
+
+// We need two pieces of information to report errors/warnings - string and
+// line number. We encode these into a single int so that it can be easily
+// incremented/decremented by lexer. The right SOURCE_LOC_LINE_SIZE bits store
+// line number while the rest store the string number. Since the shaders are
+// usually small, we should not run out of memory. SOURCE_LOC_LINE_SIZE
+// can be increased to alleviate this issue.
+typedef int TSourceLoc;
+const unsigned int SOURCE_LOC_LINE_SIZE = 16; // in bits.
+const unsigned int SOURCE_LOC_LINE_MASK = (1 << SOURCE_LOC_LINE_SIZE) - 1;
+
+inline TSourceLoc EncodeSourceLoc(int string, int line) {
+ return (string << SOURCE_LOC_LINE_SIZE) | (line & SOURCE_LOC_LINE_MASK);
+}
+
+inline void DecodeSourceLoc(TSourceLoc loc, int* string, int* line) {
+ if (string) *string = loc >> SOURCE_LOC_LINE_SIZE;
+ if (line) *line = loc & SOURCE_LOC_LINE_MASK;
+}
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE(A) \
+ void* operator new(size_t s) { return (A).allocate(s); } \
+ void* operator new(size_t, void *_Where) { return (_Where); } \
+ void operator delete(void*) { } \
+ void operator delete(void *, void *) { } \
+ void* operator new[](size_t s) { return (A).allocate(s); } \
+ void* operator new[](size_t, void *_Where) { return (_Where); } \
+ void operator delete[](void*) { } \
+ void operator delete[](void *, void *) { }
+
+//
+// Pool version of string.
+//
+typedef pool_allocator<char> TStringAllocator;
+typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
+inline TString* NewPoolTString(const char* s)
+{
+ void* memory = GlobalPoolAllocator.allocate(sizeof(TString));
+ return new(memory) TString(s);
+}
+
+//
+// Persistent string memory. Should only be used for strings that survive
+// across compiles.
+//
+#define TPersistString std::string
+#define TPersistStringStream std::ostringstream
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+ typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T> >() {}
+ TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
+ TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {}
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
+public:
+ typedef pool_allocator<std::pair<const K, D> > tAllocator;
+
+ TMap() : std::map<K, D, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {}
+};
+
+#endif // _COMMON_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/Compiler.cpp b/src/3rdparty/angle/src/compiler/Compiler.cpp
new file mode 100644
index 0000000000..9e7f75c33a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Compiler.cpp
@@ -0,0 +1,350 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/BuiltInFunctionEmulator.h"
+#include "compiler/DetectRecursion.h"
+#include "compiler/ForLoopUnroll.h"
+#include "compiler/Initialize.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/MapLongVariableNames.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/RenameFunction.h"
+#include "compiler/ShHandle.h"
+#include "compiler/ValidateLimitations.h"
+#include "compiler/VariablePacker.h"
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/depgraph/DependencyGraphOutput.h"
+#include "compiler/timing/RestrictFragmentShaderTiming.h"
+#include "compiler/timing/RestrictVertexShaderTiming.h"
+
+bool isWebGLBasedSpec(ShShaderSpec spec)
+{
+ return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
+}
+
+namespace {
+bool InitializeSymbolTable(
+ const TBuiltInStrings& builtInStrings,
+ ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
+ TInfoSink& infoSink, TSymbolTable& symbolTable)
+{
+ TIntermediate intermediate(infoSink);
+ TExtensionBehavior extBehavior;
+ InitExtensionBehavior(resources, extBehavior);
+ // The builtins deliberately don't specify precisions for the function
+ // arguments and return types. For that reason we don't try to check them.
+ TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
+
+ GlobalParseContext = &parseContext;
+
+ assert(symbolTable.isEmpty());
+ //
+ // Parse the built-ins. This should only happen once per
+ // language symbol table.
+ //
+ // 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();
+
+ for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
+ {
+ const char* builtInShaders = i->c_str();
+ int builtInLengths = static_cast<int>(i->size());
+ if (builtInLengths <= 0)
+ continue;
+
+ if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
+ {
+ infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
+ return false;
+ }
+ }
+
+ IdentifyBuiltIns(type, spec, resources, symbolTable);
+
+ return true;
+}
+
+class TScopedPoolAllocator {
+public:
+ TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
+ : mAllocator(allocator), mPushPopAllocator(pushPop) {
+ if (mPushPopAllocator) mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator() {
+ SetGlobalPoolAllocator(NULL);
+ if (mPushPopAllocator) mAllocator->pop();
+ }
+
+private:
+ TPoolAllocator* mAllocator;
+ bool mPushPopAllocator;
+};
+} // namespace
+
+TShHandleBase::TShHandleBase() {
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase() {
+ SetGlobalPoolAllocator(NULL);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
+ : shaderType(type),
+ shaderSpec(spec),
+ builtInFunctionEmulator(type)
+{
+ longNameMap = LongNameMap::GetInstance();
+}
+
+TCompiler::~TCompiler()
+{
+ ASSERT(longNameMap);
+ longNameMap->Release();
+}
+
+bool TCompiler::Init(const ShBuiltInResources& resources)
+{
+ maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
+ resources.MaxVertexUniformVectors :
+ resources.MaxFragmentUniformVectors;
+ TScopedPoolAllocator scopedAlloc(&allocator, false);
+
+ // Generate built-in symbol table.
+ if (!InitBuiltInSymbolTable(resources))
+ return false;
+ InitExtensionBehavior(resources, extensionBehavior);
+
+ return true;
+}
+
+bool TCompiler::compile(const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions)
+{
+ TScopedPoolAllocator scopedAlloc(&allocator, true);
+ clearResults();
+
+ if (numStrings == 0)
+ return true;
+
+ // If compiling for WebGL, validate loop and indexing as well.
+ if (isWebGLBasedSpec(shaderSpec))
+ compileOptions |= SH_VALIDATE_LOOP_INDEXING;
+
+ // First string is path of source file if flag is set. The actual source follows.
+ const char* sourcePath = NULL;
+ int firstSource = 0;
+ if (compileOptions & SH_SOURCE_PATH)
+ {
+ sourcePath = shaderStrings[0];
+ ++firstSource;
+ }
+
+ TIntermediate intermediate(infoSink);
+ TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
+ shaderType, shaderSpec, compileOptions, true,
+ sourcePath, infoSink);
+ GlobalParseContext = &parseContext;
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ symbolTable.push();
+ if (!symbolTable.atGlobalLevel())
+ infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
+
+ // Parse shader.
+ bool success =
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
+ (parseContext.treeRoot != NULL);
+ if (success) {
+ TIntermNode* root = parseContext.treeRoot;
+ success = intermediate.postProcess(root);
+
+ if (success)
+ success = detectRecursion(root);
+
+ if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
+ success = validateLimitations(root);
+
+ if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
+ success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
+
+ if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
+ rewriteCSSShader(root);
+
+ // Unroll for-loop markup needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
+ ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
+
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
+ builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+
+ // Call mapLongVariableNames() before collectAttribsUniforms() so in
+ // collectAttribsUniforms() we already have the mapped symbol names and
+ // we could composite mapped and original variable names.
+ if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
+ mapLongVariableNames(root);
+
+ if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
+ collectAttribsUniforms(root);
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
+ success = enforcePackingRestrictions();
+ if (!success) {
+ infoSink.info.message(EPrefixError, "too many uniforms");
+ }
+ }
+ }
+
+ if (success && (compileOptions & SH_INTERMEDIATE_TREE))
+ intermediate.outputTree(root);
+
+ if (success && (compileOptions & SH_OBJECT_CODE))
+ translate(root);
+ }
+
+ // Cleanup memory.
+ intermediate.remove(parseContext.treeRoot);
+ // Ensure symbol table is returned to the built-in level,
+ // throwing away all but the built-ins.
+ while (!symbolTable.atBuiltInLevel())
+ symbolTable.pop();
+
+ return success;
+}
+
+bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
+{
+ TBuiltIns builtIns;
+
+ builtIns.initialize(shaderType, shaderSpec, resources);
+ return InitializeSymbolTable(builtIns.getBuiltInStrings(),
+ shaderType, shaderSpec, resources, infoSink, symbolTable);
+}
+
+void TCompiler::clearResults()
+{
+ infoSink.info.erase();
+ infoSink.obj.erase();
+ infoSink.debug.erase();
+
+ attribs.clear();
+ uniforms.clear();
+
+ builtInFunctionEmulator.Cleanup();
+}
+
+bool TCompiler::detectRecursion(TIntermNode* root)
+{
+ DetectRecursion detect;
+ root->traverse(&detect);
+ switch (detect.detectRecursion()) {
+ case DetectRecursion::kErrorNone:
+ return true;
+ case DetectRecursion::kErrorMissingMain:
+ infoSink.info.message(EPrefixError, "Missing main()");
+ return false;
+ case DetectRecursion::kErrorRecursion:
+ infoSink.info.message(EPrefixError, "Function recursion detected");
+ return false;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+void TCompiler::rewriteCSSShader(TIntermNode* root)
+{
+ RenameFunction renamer("main(", "css_main(");
+ root->traverse(&renamer);
+}
+
+bool TCompiler::validateLimitations(TIntermNode* root) {
+ ValidateLimitations validate(shaderType, infoSink.info);
+ root->traverse(&validate);
+ return validate.numErrors() == 0;
+}
+
+bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
+{
+ if (shaderSpec != SH_WEBGL_SPEC) {
+ infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
+ return false;
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER) {
+ TDependencyGraph graph(root);
+
+ // Output any errors first.
+ bool success = enforceFragmentShaderTimingRestrictions(graph);
+
+ // Then, output the dependency graph.
+ if (outputGraph) {
+ TDependencyGraphOutput output(infoSink.info);
+ output.outputAllSpanningTrees(graph);
+ }
+
+ return success;
+ }
+ else {
+ return enforceVertexShaderTimingRestrictions(root);
+ }
+}
+
+bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
+{
+ RestrictFragmentShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(graph);
+ return restrictor.numErrors() == 0;
+}
+
+bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
+{
+ RestrictVertexShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(root);
+ return restrictor.numErrors() == 0;
+}
+
+void TCompiler::collectAttribsUniforms(TIntermNode* root)
+{
+ CollectAttribsUniforms collect(attribs, uniforms);
+ root->traverse(&collect);
+}
+
+bool TCompiler::enforcePackingRestrictions()
+{
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
+}
+
+void TCompiler::mapLongVariableNames(TIntermNode* root)
+{
+ ASSERT(longNameMap);
+ MapLongVariableNames map(longNameMap);
+ root->traverse(&map);
+}
+
+int TCompiler::getMappedNameMaxLength() const
+{
+ return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
+}
+
+const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+{
+ return extensionBehavior;
+}
+
+const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+{
+ return builtInFunctionEmulator;
+}
diff --git a/src/3rdparty/angle/src/compiler/ConstantUnion.h b/src/3rdparty/angle/src/compiler/ConstantUnion.h
new file mode 100644
index 0000000000..fd9d94dc5a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ConstantUnion.h
@@ -0,0 +1,256 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+#include <assert.h>
+
+class ConstantUnion {
+public:
+ ConstantUnion()
+ {
+ iConst = 0;
+ }
+
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ void setIConst(int i) {iConst = i; type = EbtInt; }
+ void setFConst(float f) {fConst = f; type = EbtFloat; }
+ void setBConst(bool b) {bConst = b; type = EbtBool; }
+
+ int getIConst() { return iConst; }
+ float getFConst() { return fConst; }
+ bool getBConst() { return bConst; }
+ int getIConst() const { return iConst; }
+ float getFConst() const { return fConst; }
+ bool getBConst() const { return bConst; }
+
+ bool operator==(const int i) const
+ {
+ return i == iConst;
+ }
+
+ bool operator==(const float f) const
+ {
+ return f == fConst;
+ }
+
+ bool operator==(const bool b) const
+ {
+ return b == bConst;
+ }
+
+ bool operator==(const ConstantUnion& constant) const
+ {
+ if (constant.type != type)
+ return false;
+
+ switch (type) {
+ case EbtInt:
+ return constant.iConst == iConst;
+ case EbtFloat:
+ return constant.fConst == fConst;
+ case EbtBool:
+ return constant.bConst == bConst;
+ default:
+ return false;
+ }
+ }
+
+ bool operator!=(const int i) const
+ {
+ return !operator==(i);
+ }
+
+ bool operator!=(const float f) const
+ {
+ return !operator==(f);
+ }
+
+ bool operator!=(const bool b) const
+ {
+ return !operator==(b);
+ }
+
+ bool operator!=(const ConstantUnion& constant) const
+ {
+ return !operator==(constant);
+ }
+
+ bool operator>(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst > constant.iConst;
+ case EbtFloat:
+ return fConst > constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ bool operator<(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst < constant.iConst;
+ case EbtFloat:
+ return fConst < constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ ConstantUnion operator+(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator-(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator*(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator%(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator>>(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator<<(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator|(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator^(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator||(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ TBasicType getType() const { return type; }
+private:
+
+ union {
+ int iConst; // used for ivec, scalar ints
+ bool bConst; // used for bvec, scalar bools
+ float fConst; // used for vec, mat, scalar floats
+ } ;
+
+ TBasicType type;
+};
+
+#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp
new file mode 100644
index 0000000000..472232a75d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.cpp
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#include "compiler/DetectDiscontinuity.h"
+
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
+{
+ mLoopDiscontinuity = false;
+ node->traverse(this);
+ return mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mLoopDiscontinuity)
+ {
+ return false;
+ }
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ break;
+ case EOpBreak:
+ case EOpContinue:
+ mLoopDiscontinuity = true;
+ case EOpReturn:
+ break;
+ default: UNREACHABLE();
+ }
+
+ return !mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ return !mLoopDiscontinuity;
+}
+
+bool containsLoopDiscontinuity(TIntermNode *node)
+{
+ DetectLoopDiscontinuity detectLoopDiscontinuity;
+ return detectLoopDiscontinuity.traverse(node);
+}
+
+bool DetectGradientOperation::traverse(TIntermNode *node)
+{
+ mGradientOperation = false;
+ node->traverse(this);
+ return mGradientOperation;
+}
+
+bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpDFdx:
+ case EOpDFdy:
+ mGradientOperation = true;
+ default:
+ break;
+ }
+
+ return !mGradientOperation;
+}
+
+bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ if (node->getOp() == EOpFunctionCall)
+ {
+ if (!node->isUserDefined())
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (name == "texture2D" ||
+ name == "texture2DProj" ||
+ name == "textureCube")
+ {
+ mGradientOperation = true;
+ }
+ }
+ else
+ {
+ // When a user defined function is called, we have to
+ // conservatively assume it to contain gradient operations
+ mGradientOperation = true;
+ }
+ }
+
+ return !mGradientOperation;
+}
+
+bool containsGradientOperation(TIntermNode *node)
+{
+ DetectGradientOperation detectGradientOperation;
+ return detectGradientOperation.traverse(node);
+}
+}
diff --git a/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h
new file mode 100644
index 0000000000..8bda4c3dea
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DetectDiscontinuity.h
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#ifndef COMPILER_DETECTDISCONTINUITY_H_
+#define COMPILER_DETECTDISCONTINUITY_H_
+
+#include "compiler/intermediate.h"
+
+namespace sh
+{
+// Checks whether a loop can run for a variable number of iterations
+class DetectLoopDiscontinuity : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitBranch(Visit visit, TIntermBranch *node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ bool mLoopDiscontinuity;
+};
+
+bool containsLoopDiscontinuity(TIntermNode *node);
+
+// Checks for intrinsic functions which compute gradients
+class DetectGradientOperation : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitUnary(Visit visit, TIntermUnary *node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ bool mGradientOperation;
+};
+
+bool containsGradientOperation(TIntermNode *node);
+
+}
+
+#endif // COMPILER_DETECTDISCONTINUITY_H_
diff --git a/src/3rdparty/angle/src/compiler/DetectRecursion.cpp b/src/3rdparty/angle/src/compiler/DetectRecursion.cpp
new file mode 100644
index 0000000000..c09780dd92
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DetectRecursion.cpp
@@ -0,0 +1,125 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/DetectRecursion.h"
+
+DetectRecursion::FunctionNode::FunctionNode(const TString& fname)
+ : name(fname),
+ visit(PreVisit)
+{
+}
+
+const TString& DetectRecursion::FunctionNode::getName() const
+{
+ return name;
+}
+
+void DetectRecursion::FunctionNode::addCallee(
+ DetectRecursion::FunctionNode* callee)
+{
+ for (size_t i = 0; i < callees.size(); ++i) {
+ if (callees[i] == callee)
+ return;
+ }
+ callees.push_back(callee);
+}
+
+bool DetectRecursion::FunctionNode::detectRecursion()
+{
+ ASSERT(visit == PreVisit);
+ visit = InVisit;
+ for (size_t i = 0; i < callees.size(); ++i) {
+ switch (callees[i]->visit) {
+ case InVisit:
+ // cycle detected, i.e., recursion detected.
+ return true;
+ case PostVisit:
+ break;
+ case PreVisit: {
+ bool recursion = callees[i]->detectRecursion();
+ if (recursion)
+ return true;
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ visit = PostVisit;
+ return false;
+}
+
+DetectRecursion::DetectRecursion()
+ : currentFunction(NULL)
+{
+}
+
+DetectRecursion::~DetectRecursion()
+{
+ for (size_t i = 0; i < functions.size(); ++i)
+ delete functions[i];
+}
+
+bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ // Function declaration.
+ // Don't add FunctionNode here because node->getName() is the
+ // unmangled function name.
+ break;
+ case EOpFunction: {
+ // Function definition.
+ if (visit == PreVisit) {
+ currentFunction = findFunctionByName(node->getName());
+ if (currentFunction == NULL) {
+ currentFunction = new FunctionNode(node->getName());
+ functions.push_back(currentFunction);
+ }
+ }
+ break;
+ }
+ case EOpFunctionCall: {
+ // Function call.
+ if (visit == PreVisit) {
+ ASSERT(currentFunction != NULL);
+ FunctionNode* func = findFunctionByName(node->getName());
+ if (func == NULL) {
+ func = new FunctionNode(node->getName());
+ functions.push_back(func);
+ }
+ currentFunction->addCallee(func);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+DetectRecursion::ErrorCode DetectRecursion::detectRecursion()
+{
+ FunctionNode* main = findFunctionByName("main(");
+ if (main == NULL)
+ return kErrorMissingMain;
+ if (main->detectRecursion())
+ return kErrorRecursion;
+ return kErrorNone;
+}
+
+DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName(
+ const TString& name)
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ if (functions[i]->getName() == name)
+ return functions[i];
+ }
+ return NULL;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/DetectRecursion.h b/src/3rdparty/angle/src/compiler/DetectRecursion.h
new file mode 100644
index 0000000000..bbac79dc9c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DetectRecursion.h
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DETECT_RECURSION_H_
+#define COMPILER_DETECT_RECURSION_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/VariableInfo.h"
+
+// Traverses intermediate tree to detect function recursion.
+class DetectRecursion : public TIntermTraverser {
+public:
+ enum ErrorCode {
+ kErrorMissingMain,
+ kErrorRecursion,
+ kErrorNone
+ };
+
+ DetectRecursion();
+ ~DetectRecursion();
+
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+
+ ErrorCode detectRecursion();
+
+private:
+ class FunctionNode {
+ public:
+ FunctionNode(const TString& fname);
+
+ const TString& getName() const;
+
+ // If a function is already in the callee list, this becomes a no-op.
+ void addCallee(FunctionNode* callee);
+
+ // Return true if recursive function calls are detected.
+ bool detectRecursion();
+
+ private:
+ // mangled function name is unique.
+ TString name;
+
+ // functions that are directly called by this function.
+ TVector<FunctionNode*> callees;
+
+ Visit visit;
+ };
+
+ FunctionNode* findFunctionByName(const TString& name);
+
+ TVector<FunctionNode*> functions;
+ FunctionNode* currentFunction;
+};
+
+#endif // COMPILER_DETECT_RECURSION_H_
diff --git a/src/3rdparty/angle/src/compiler/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/Diagnostics.cpp
new file mode 100644
index 0000000000..8aa1cb6b24
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Diagnostics.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/Diagnostics.h"
+
+#include "compiler/debug.h"
+#include "compiler/InfoSink.h"
+#include "compiler/preprocessor/new/SourceLocation.h"
+
+TDiagnostics::TDiagnostics(TInfoSink& infoSink) :
+ mInfoSink(infoSink),
+ mNumErrors(0),
+ mNumWarnings(0)
+{
+}
+
+TDiagnostics::~TDiagnostics()
+{
+}
+
+void TDiagnostics::writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra)
+{
+ TPrefixType prefix = EPrefixNone;
+ switch (severity)
+ {
+ case ERROR:
+ ++mNumErrors;
+ prefix = EPrefixError;
+ break;
+ case WARNING:
+ ++mNumWarnings;
+ prefix = EPrefixWarning;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ TInfoSinkBase& sink = mInfoSink.info;
+ /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
+ sink.prefix(prefix);
+ sink.location(EncodeSourceLoc(loc.file, loc.line));
+ sink << "'" << token << "' : " << reason << " " << extra << "\n";
+}
+
+void TDiagnostics::writeDebug(const std::string& str)
+{
+ mInfoSink.debug << str;
+}
+
+void TDiagnostics::print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text)
+{
+ writeInfo(severity(id), loc, message(id), text, "");
+}
diff --git a/src/3rdparty/angle/src/compiler/Diagnostics.h b/src/3rdparty/angle/src/compiler/Diagnostics.h
new file mode 100644
index 0000000000..3670414b03
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Diagnostics.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIAGNOSTICS_H_
+#define COMPILER_DIAGNOSTICS_H_
+
+#include "compiler/preprocessor/new/Diagnostics.h"
+
+class TInfoSink;
+
+class TDiagnostics : public pp::Diagnostics
+{
+ public:
+ TDiagnostics(TInfoSink& infoSink);
+ virtual ~TDiagnostics();
+
+ TInfoSink& infoSink() { return mInfoSink; }
+
+ int numErrors() const { return mNumErrors; }
+ int numWarnings() const { return mNumWarnings; }
+
+ void writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra);
+
+ void writeDebug(const std::string& str);
+
+ protected:
+ virtual void print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text);
+
+ private:
+ TInfoSink& mInfoSink;
+ int mNumErrors;
+ int mNumWarnings;
+};
+
+#endif // COMPILER_DIAGNOSTICS_H_
diff --git a/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp
new file mode 100644
index 0000000000..d1f6ab3af5
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DirectiveHandler.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/DirectiveHandler.h"
+
+#include <sstream>
+
+#include "compiler/debug.h"
+#include "compiler/Diagnostics.h"
+
+static TBehavior getBehavior(const std::string& str)
+{
+ static const std::string kRequire("require");
+ static const std::string kEnable("enable");
+ static const std::string kDisable("disable");
+ static const std::string kWarn("warn");
+
+ if (str == kRequire) return EBhRequire;
+ else if (str == kEnable) return EBhEnable;
+ else if (str == kDisable) return EBhDisable;
+ else if (str == kWarn) return EBhWarn;
+ return EBhUndefined;
+}
+
+TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics)
+ : mExtensionBehavior(extBehavior),
+ mDiagnostics(diagnostics)
+{
+}
+
+TDirectiveHandler::~TDirectiveHandler()
+{
+}
+
+void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
+ const std::string& msg)
+{
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, msg, "", "");
+}
+
+void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value)
+{
+ static const std::string kSTDGL("STDGL");
+ static const std::string kOptimize("optimize");
+ static const std::string kDebug("debug");
+ static const std::string kOn("on");
+ static const std::string kOff("off");
+
+ bool invalidValue = false;
+ if (name == kSTDGL)
+ {
+ // The STDGL pragma is used to reserve pragmas for use by future
+ // revisions of GLSL. Ignore it.
+ return;
+ }
+ else if (name == kOptimize)
+ {
+ if (value == kOn) mPragma.optimize = true;
+ else if (value == kOff) mPragma.optimize = false;
+ else invalidValue = true;
+ }
+ else if (name == kDebug)
+ {
+ if (value == kOn) mPragma.debug = true;
+ else if (value == kOff) mPragma.debug = false;
+ else invalidValue = true;
+ }
+ else
+ {
+ mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name);
+ return;
+ }
+
+ if (invalidValue)
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "invalid pragma value", value,
+ "'on' or 'off' expected");
+}
+
+void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior)
+{
+ static const std::string kExtAll("all");
+
+ TBehavior behaviorVal = getBehavior(behavior);
+ if (behaviorVal == EBhUndefined)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "behavior", name, "invalid");
+ return;
+ }
+
+ if (name == kExtAll)
+ {
+ if (behaviorVal == EBhRequire)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "extension", name,
+ "cannot have 'require' behavior");
+ }
+ else if (behaviorVal == EBhEnable)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "extension", name,
+ "cannot have 'enable' behavior");
+ }
+ else
+ {
+ for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
+ iter != mExtensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ return;
+ }
+
+ TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
+ if (iter != mExtensionBehavior.end())
+ {
+ iter->second = behaviorVal;
+ return;
+ }
+
+ pp::Diagnostics::Severity severity = pp::Diagnostics::ERROR;
+ switch (behaviorVal) {
+ case EBhRequire:
+ severity = pp::Diagnostics::ERROR;
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ severity = pp::Diagnostics::WARNING;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ mDiagnostics.writeInfo(severity, loc,
+ "extension", name, "is not supported");
+}
+
+void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
+ int version)
+{
+ static const int kVersion = 100;
+
+ if (version != kVersion)
+ {
+ std::stringstream stream;
+ stream << version;
+ std::string str = stream.str();
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "version number", str, "not supported");
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/DirectiveHandler.h
new file mode 100644
index 0000000000..21d3dfc315
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/DirectiveHandler.h
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIRECTIVE_HANDLER_H_
+#define COMPILER_DIRECTIVE_HANDLER_H_
+
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/Pragma.h"
+#include "compiler/preprocessor/new/DirectiveHandler.h"
+
+class TDiagnostics;
+
+class TDirectiveHandler : public pp::DirectiveHandler
+{
+ public:
+ TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics);
+ virtual ~TDirectiveHandler();
+
+ const TPragma& pragma() const { return mPragma; }
+ const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; }
+
+ virtual void handleError(const pp::SourceLocation& loc,
+ const std::string& msg);
+
+ virtual void handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value);
+
+ virtual void handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior);
+
+ virtual void handleVersion(const pp::SourceLocation& loc,
+ int version);
+
+ private:
+ TPragma mPragma;
+ TExtensionBehavior& mExtensionBehavior;
+ TDiagnostics& mDiagnostics;
+};
+
+#endif // COMPILER_DIRECTIVE_HANDLER_H_
diff --git a/src/3rdparty/angle/src/compiler/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/ExtensionBehavior.h
new file mode 100644
index 0000000000..6040980837
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ExtensionBehavior.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
+#define _EXTENSION_BEHAVIOR_INCLUDED_
+
+#include <map>
+#include <string>
+
+typedef enum
+{
+ EBhRequire,
+ EBhEnable,
+ EBhWarn,
+ EBhDisable,
+ EBhUndefined,
+} TBehavior;
+
+inline const char* getBehaviorString(TBehavior b)
+{
+ switch(b)
+ {
+ case EBhRequire: return "require";
+ case EBhEnable: return "enable";
+ case EBhWarn: return "warn";
+ case EBhDisable: return "disable";
+ default: return NULL;
+ }
+}
+
+// Mapping between extension name and behavior.
+typedef std::map<std::string, TBehavior> TExtensionBehavior;
+
+#endif // _EXTENSION_TABLE_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp b/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp
new file mode 100644
index 0000000000..fdc3f44431
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ForLoopUnroll.cpp
@@ -0,0 +1,215 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ForLoopUnroll.h"
+
+namespace {
+
+class IntegerForLoopUnrollMarker : public TIntermTraverser {
+public:
+
+ virtual bool visitLoop(Visit, TIntermLoop* node)
+ {
+ // This is called after ValidateLimitations pass, so all the ASSERT
+ // should never fail.
+ // See ValidateLimitations::validateForLoopInit().
+ ASSERT(node);
+ ASSERT(node->getType() == ELoopFor);
+ ASSERT(node->getInit());
+ TIntermAggregate* decl = node->getInit()->getAsAggregate();
+ ASSERT(decl && decl->getOp() == EOpDeclaration);
+ TIntermSequence& declSeq = decl->getSequence();
+ ASSERT(declSeq.size() == 1);
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ ASSERT(declInit && declInit->getOp() == EOpInitialize);
+ ASSERT(declInit->getLeft());
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ ASSERT(symbol);
+ TBasicType type = symbol->getBasicType();
+ ASSERT(type == EbtInt || type == EbtFloat);
+ if (type == EbtInt)
+ node->setUnrollFlag(true);
+ return true;
+ }
+
+};
+
+} // anonymous namepsace
+
+void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
+{
+ ASSERT(node->getType() == ELoopFor);
+ ASSERT(node->getUnrollFlag());
+
+ TIntermNode* init = node->getInit();
+ ASSERT(init != NULL);
+ TIntermAggregate* decl = init->getAsAggregate();
+ ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
+ TIntermSequence& declSeq = decl->getSequence();
+ ASSERT(declSeq.size() == 1);
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ ASSERT(symbol != NULL);
+ ASSERT(symbol->getBasicType() == EbtInt);
+
+ info.id = symbol->getId();
+
+ ASSERT(declInit->getRight() != NULL);
+ TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
+ ASSERT(initNode != NULL);
+
+ info.initValue = evaluateIntConstant(initNode);
+ info.currentValue = info.initValue;
+
+ TIntermNode* cond = node->getCondition();
+ ASSERT(cond != NULL);
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ ASSERT(binOp != NULL);
+ ASSERT(binOp->getRight() != NULL);
+ ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
+
+ info.incrementValue = getLoopIncrement(node);
+ info.stopValue = evaluateIntConstant(
+ binOp->getRight()->getAsConstantUnion());
+ info.op = binOp->getOp();
+}
+
+void ForLoopUnroll::Step()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ info.currentValue += info.incrementValue;
+}
+
+bool ForLoopUnroll::SatisfiesLoopCondition()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (info.op) {
+ case EOpEqual:
+ return (info.currentValue == info.stopValue);
+ case EOpNotEqual:
+ return (info.currentValue != info.stopValue);
+ case EOpLessThan:
+ return (info.currentValue < info.stopValue);
+ case EOpGreaterThan:
+ return (info.currentValue > info.stopValue);
+ case EOpLessThanEqual:
+ return (info.currentValue <= info.stopValue);
+ case EOpGreaterThanEqual:
+ return (info.currentValue >= info.stopValue);
+ default:
+ UNREACHABLE();
+ }
+ return false;
+}
+
+bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return i->currentValue;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+void ForLoopUnroll::Push(TLoopIndexInfo& info)
+{
+ mLoopIndexStack.push_back(info);
+}
+
+void ForLoopUnroll::Pop()
+{
+ mLoopIndexStack.pop_back();
+}
+
+// static
+void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(
+ TIntermNode* root)
+{
+ ASSERT(root);
+
+ IntegerForLoopUnrollMarker marker;
+ root->traverse(&marker);
+}
+
+int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
+{
+ TIntermNode* expr = node->getExpression();
+ ASSERT(expr != NULL);
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermConstantUnion* incrementNode = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ ASSERT(binOp->getRight() != NULL);
+ incrementNode = binOp->getRight()->getAsConstantUnion();
+ ASSERT(incrementNode != NULL);
+ }
+
+ int increment = 0;
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = -1;
+ break;
+ case EOpAddAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = evaluateIntConstant(incrementNode);
+ break;
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = - evaluateIntConstant(incrementNode);
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ return increment;
+}
+
+int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
+{
+ ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
+ return node->getUnionArrayPointer()->getIConst();
+}
+
diff --git a/src/3rdparty/angle/src/compiler/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/ForLoopUnroll.h
new file mode 100644
index 0000000000..e800e25b1f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ForLoopUnroll.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+struct TLoopIndexInfo {
+ int id;
+ int initValue;
+ int stopValue;
+ int incrementValue;
+ TOperator op;
+ int currentValue;
+};
+
+class ForLoopUnroll {
+public:
+ ForLoopUnroll() { }
+
+ void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info);
+
+ // Update the info.currentValue for the next loop iteration.
+ void Step();
+
+ // Return false if loop condition is no longer satisfied.
+ bool SatisfiesLoopCondition();
+
+ // Check if the symbol is the index of a loop that's unrolled.
+ bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol);
+
+ // Return the current value of a given loop index symbol.
+ int GetLoopIndexValue(TIntermSymbol* symbol);
+
+ void Push(TLoopIndexInfo& info);
+ void Pop();
+
+ static void MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode* root);
+
+private:
+ int getLoopIncrement(TIntermLoop* node);
+
+ int evaluateIntConstant(TIntermConstantUnion* node);
+
+ TVector<TLoopIndexInfo> mLoopIndexStack;
+};
+
diff --git a/src/3rdparty/angle/src/compiler/InfoSink.cpp b/src/3rdparty/angle/src/compiler/InfoSink.cpp
new file mode 100644
index 0000000000..ba32f781f5
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InfoSink.cpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InfoSink.h"
+
+void TInfoSinkBase::prefix(TPrefixType message) {
+ switch(message) {
+ case EPrefixNone:
+ break;
+ case EPrefixWarning:
+ sink.append("WARNING: ");
+ break;
+ case EPrefixError:
+ sink.append("ERROR: ");
+ break;
+ case EPrefixInternalError:
+ sink.append("INTERNAL ERROR: ");
+ break;
+ case EPrefixUnimplemented:
+ sink.append("UNIMPLEMENTED: ");
+ break;
+ case EPrefixNote:
+ sink.append("NOTE: ");
+ break;
+ default:
+ sink.append("UNKOWN ERROR: ");
+ break;
+ }
+}
+
+void TInfoSinkBase::location(TSourceLoc loc) {
+ int string = 0, line = 0;
+ DecodeSourceLoc(loc, &string, &line);
+
+ TPersistStringStream stream;
+ if (line)
+ stream << string << ":" << line;
+ else
+ stream << string << ":? ";
+ stream << ": ";
+
+ sink.append(stream.str());
+}
+
+void TInfoSinkBase::message(TPrefixType message, const char* s) {
+ prefix(message);
+ sink.append(s);
+ sink.append("\n");
+}
+
+void TInfoSinkBase::message(TPrefixType message, const char* s, TSourceLoc loc) {
+ prefix(message);
+ location(loc);
+ sink.append(s);
+ sink.append("\n");
+}
diff --git a/src/3rdparty/angle/src/compiler/InfoSink.h b/src/3rdparty/angle/src/compiler/InfoSink.h
new file mode 100644
index 0000000000..e2224e918d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InfoSink.h
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include <math.h>
+#include "compiler/Common.h"
+
+// Returns the fractional part of the given floating-point number.
+inline float fractionalPart(float f) {
+ float intPart = 0.0f;
+ return modff(f, &intPart);
+}
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+ EPrefixNone,
+ EPrefixWarning,
+ EPrefixError,
+ EPrefixInternalError,
+ EPrefixUnimplemented,
+ EPrefixNote
+};
+
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+ TInfoSinkBase() {}
+
+ template <typename T>
+ TInfoSinkBase& operator<<(const T& t) {
+ TPersistStringStream stream;
+ stream << t;
+ sink.append(stream.str());
+ return *this;
+ }
+ // Override << operator for specific types. It is faster to append strings
+ // and characters directly to the sink.
+ TInfoSinkBase& operator<<(char c) {
+ sink.append(1, c);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const char* str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TPersistString& str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TString& str) {
+ sink.append(str.c_str());
+ return *this;
+ }
+ // Make sure floats are written with correct precision.
+ TInfoSinkBase& operator<<(float f) {
+ // Make sure that at least one decimal point is written. If a number
+ // does not have a fractional part, the default precision format does
+ // not write the decimal portion which gets interpreted as integer by
+ // the compiler.
+ TPersistStringStream stream;
+ if (fractionalPart(f) == 0.0f) {
+ stream.precision(1);
+ stream << std::showpoint << std::fixed << f;
+ } else {
+ stream.unsetf(std::ios::fixed);
+ stream.unsetf(std::ios::scientific);
+ stream.precision(8);
+ stream << f;
+ }
+ sink.append(stream.str());
+ return *this;
+ }
+ // Write boolean values as their names instead of integral value.
+ TInfoSinkBase& operator<<(bool b) {
+ const char* str = b ? "true" : "false";
+ sink.append(str);
+ return *this;
+ }
+
+ void erase() { sink.clear(); }
+ int size() { return static_cast<int>(sink.size()); }
+
+ const TPersistString& str() const { return sink; }
+ const char* c_str() const { return sink.c_str(); }
+
+ void prefix(TPrefixType message);
+ void location(TSourceLoc loc);
+ void message(TPrefixType message, const char* s);
+ void message(TPrefixType message, const char* s, TSourceLoc loc);
+
+private:
+ TPersistString sink;
+};
+
+class TInfoSink {
+public:
+ TInfoSinkBase info;
+ TInfoSinkBase debug;
+ TInfoSinkBase obj;
+};
+
+#endif // _INFOSINK_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/Initialize.cpp b/src/3rdparty/angle/src/compiler/Initialize.cpp
new file mode 100644
index 0000000000..3e94ce7ba8
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Initialize.cpp
@@ -0,0 +1,657 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Create strings that declare built-in definitions, add built-ins that
+// cannot be expressed in the files, and establish mappings between
+// built-in functions and operators.
+//
+
+#include "compiler/Initialize.h"
+
+#include "compiler/intermediate.h"
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by both vertex and fragment shaders.
+//
+//============================================================================
+static TString BuiltInFunctionsCommon(const ShBuiltInResources& resources)
+{
+ TString s;
+
+ //
+ // Angle and Trigonometric Functions.
+ //
+ s.append(TString("float radians(float degrees);"));
+ s.append(TString("vec2 radians(vec2 degrees);"));
+ s.append(TString("vec3 radians(vec3 degrees);"));
+ s.append(TString("vec4 radians(vec4 degrees);"));
+
+ s.append(TString("float degrees(float radians);"));
+ s.append(TString("vec2 degrees(vec2 radians);"));
+ s.append(TString("vec3 degrees(vec3 radians);"));
+ s.append(TString("vec4 degrees(vec4 radians);"));
+
+ s.append(TString("float sin(float angle);"));
+ s.append(TString("vec2 sin(vec2 angle);"));
+ s.append(TString("vec3 sin(vec3 angle);"));
+ s.append(TString("vec4 sin(vec4 angle);"));
+
+ s.append(TString("float cos(float angle);"));
+ s.append(TString("vec2 cos(vec2 angle);"));
+ s.append(TString("vec3 cos(vec3 angle);"));
+ s.append(TString("vec4 cos(vec4 angle);"));
+
+ s.append(TString("float tan(float angle);"));
+ s.append(TString("vec2 tan(vec2 angle);"));
+ s.append(TString("vec3 tan(vec3 angle);"));
+ s.append(TString("vec4 tan(vec4 angle);"));
+
+ s.append(TString("float asin(float x);"));
+ s.append(TString("vec2 asin(vec2 x);"));
+ s.append(TString("vec3 asin(vec3 x);"));
+ s.append(TString("vec4 asin(vec4 x);"));
+
+ s.append(TString("float acos(float x);"));
+ s.append(TString("vec2 acos(vec2 x);"));
+ s.append(TString("vec3 acos(vec3 x);"));
+ s.append(TString("vec4 acos(vec4 x);"));
+
+ s.append(TString("float atan(float y, float x);"));
+ s.append(TString("vec2 atan(vec2 y, vec2 x);"));
+ s.append(TString("vec3 atan(vec3 y, vec3 x);"));
+ s.append(TString("vec4 atan(vec4 y, vec4 x);"));
+
+ s.append(TString("float atan(float y_over_x);"));
+ s.append(TString("vec2 atan(vec2 y_over_x);"));
+ s.append(TString("vec3 atan(vec3 y_over_x);"));
+ s.append(TString("vec4 atan(vec4 y_over_x);"));
+
+ //
+ // Exponential Functions.
+ //
+ s.append(TString("float pow(float x, float y);"));
+ s.append(TString("vec2 pow(vec2 x, vec2 y);"));
+ s.append(TString("vec3 pow(vec3 x, vec3 y);"));
+ s.append(TString("vec4 pow(vec4 x, vec4 y);"));
+
+ s.append(TString("float exp(float x);"));
+ s.append(TString("vec2 exp(vec2 x);"));
+ s.append(TString("vec3 exp(vec3 x);"));
+ s.append(TString("vec4 exp(vec4 x);"));
+
+ s.append(TString("float log(float x);"));
+ s.append(TString("vec2 log(vec2 x);"));
+ s.append(TString("vec3 log(vec3 x);"));
+ s.append(TString("vec4 log(vec4 x);"));
+
+ s.append(TString("float exp2(float x);"));
+ s.append(TString("vec2 exp2(vec2 x);"));
+ s.append(TString("vec3 exp2(vec3 x);"));
+ s.append(TString("vec4 exp2(vec4 x);"));
+
+ s.append(TString("float log2(float x);"));
+ s.append(TString("vec2 log2(vec2 x);"));
+ s.append(TString("vec3 log2(vec3 x);"));
+ s.append(TString("vec4 log2(vec4 x);"));
+
+ s.append(TString("float sqrt(float x);"));
+ s.append(TString("vec2 sqrt(vec2 x);"));
+ s.append(TString("vec3 sqrt(vec3 x);"));
+ s.append(TString("vec4 sqrt(vec4 x);"));
+
+ s.append(TString("float inversesqrt(float x);"));
+ s.append(TString("vec2 inversesqrt(vec2 x);"));
+ s.append(TString("vec3 inversesqrt(vec3 x);"));
+ s.append(TString("vec4 inversesqrt(vec4 x);"));
+
+ //
+ // Common Functions.
+ //
+ s.append(TString("float abs(float x);"));
+ s.append(TString("vec2 abs(vec2 x);"));
+ s.append(TString("vec3 abs(vec3 x);"));
+ s.append(TString("vec4 abs(vec4 x);"));
+
+ s.append(TString("float sign(float x);"));
+ s.append(TString("vec2 sign(vec2 x);"));
+ s.append(TString("vec3 sign(vec3 x);"));
+ s.append(TString("vec4 sign(vec4 x);"));
+
+ s.append(TString("float floor(float x);"));
+ s.append(TString("vec2 floor(vec2 x);"));
+ s.append(TString("vec3 floor(vec3 x);"));
+ s.append(TString("vec4 floor(vec4 x);"));
+
+ s.append(TString("float ceil(float x);"));
+ s.append(TString("vec2 ceil(vec2 x);"));
+ s.append(TString("vec3 ceil(vec3 x);"));
+ s.append(TString("vec4 ceil(vec4 x);"));
+
+ s.append(TString("float fract(float x);"));
+ s.append(TString("vec2 fract(vec2 x);"));
+ s.append(TString("vec3 fract(vec3 x);"));
+ s.append(TString("vec4 fract(vec4 x);"));
+
+ s.append(TString("float mod(float x, float y);"));
+ s.append(TString("vec2 mod(vec2 x, float y);"));
+ s.append(TString("vec3 mod(vec3 x, float y);"));
+ s.append(TString("vec4 mod(vec4 x, float y);"));
+ s.append(TString("vec2 mod(vec2 x, vec2 y);"));
+ s.append(TString("vec3 mod(vec3 x, vec3 y);"));
+ s.append(TString("vec4 mod(vec4 x, vec4 y);"));
+
+ s.append(TString("float min(float x, float y);"));
+ s.append(TString("vec2 min(vec2 x, float y);"));
+ s.append(TString("vec3 min(vec3 x, float y);"));
+ s.append(TString("vec4 min(vec4 x, float y);"));
+ s.append(TString("vec2 min(vec2 x, vec2 y);"));
+ s.append(TString("vec3 min(vec3 x, vec3 y);"));
+ s.append(TString("vec4 min(vec4 x, vec4 y);"));
+
+ s.append(TString("float max(float x, float y);"));
+ s.append(TString("vec2 max(vec2 x, float y);"));
+ s.append(TString("vec3 max(vec3 x, float y);"));
+ s.append(TString("vec4 max(vec4 x, float y);"));
+ s.append(TString("vec2 max(vec2 x, vec2 y);"));
+ s.append(TString("vec3 max(vec3 x, vec3 y);"));
+ s.append(TString("vec4 max(vec4 x, vec4 y);"));
+
+ s.append(TString("float clamp(float x, float minVal, float maxVal);"));
+ s.append(TString("vec2 clamp(vec2 x, float minVal, float maxVal);"));
+ s.append(TString("vec3 clamp(vec3 x, float minVal, float maxVal);"));
+ s.append(TString("vec4 clamp(vec4 x, float minVal, float maxVal);"));
+ s.append(TString("vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);"));
+ s.append(TString("vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);"));
+ s.append(TString("vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);"));
+
+ s.append(TString("float mix(float x, float y, float a);"));
+ s.append(TString("vec2 mix(vec2 x, vec2 y, float a);"));
+ s.append(TString("vec3 mix(vec3 x, vec3 y, float a);"));
+ s.append(TString("vec4 mix(vec4 x, vec4 y, float a);"));
+ s.append(TString("vec2 mix(vec2 x, vec2 y, vec2 a);"));
+ s.append(TString("vec3 mix(vec3 x, vec3 y, vec3 a);"));
+ s.append(TString("vec4 mix(vec4 x, vec4 y, vec4 a);"));
+
+ s.append(TString("float step(float edge, float x);"));
+ s.append(TString("vec2 step(vec2 edge, vec2 x);"));
+ s.append(TString("vec3 step(vec3 edge, vec3 x);"));
+ s.append(TString("vec4 step(vec4 edge, vec4 x);"));
+ s.append(TString("vec2 step(float edge, vec2 x);"));
+ s.append(TString("vec3 step(float edge, vec3 x);"));
+ s.append(TString("vec4 step(float edge, vec4 x);"));
+
+ s.append(TString("float smoothstep(float edge0, float edge1, float x);"));
+ s.append(TString("vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);"));
+ s.append(TString("vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);"));
+ s.append(TString("vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x);"));
+ s.append(TString("vec2 smoothstep(float edge0, float edge1, vec2 x);"));
+ s.append(TString("vec3 smoothstep(float edge0, float edge1, vec3 x);"));
+ s.append(TString("vec4 smoothstep(float edge0, float edge1, vec4 x);"));
+
+ //
+ // Geometric Functions.
+ //
+ s.append(TString("float length(float x);"));
+ s.append(TString("float length(vec2 x);"));
+ s.append(TString("float length(vec3 x);"));
+ s.append(TString("float length(vec4 x);"));
+
+ s.append(TString("float distance(float p0, float p1);"));
+ s.append(TString("float distance(vec2 p0, vec2 p1);"));
+ s.append(TString("float distance(vec3 p0, vec3 p1);"));
+ s.append(TString("float distance(vec4 p0, vec4 p1);"));
+
+ s.append(TString("float dot(float x, float y);"));
+ s.append(TString("float dot(vec2 x, vec2 y);"));
+ s.append(TString("float dot(vec3 x, vec3 y);"));
+ s.append(TString("float dot(vec4 x, vec4 y);"));
+
+ s.append(TString("vec3 cross(vec3 x, vec3 y);"));
+ s.append(TString("float normalize(float x);"));
+ s.append(TString("vec2 normalize(vec2 x);"));
+ s.append(TString("vec3 normalize(vec3 x);"));
+ s.append(TString("vec4 normalize(vec4 x);"));
+
+ s.append(TString("float faceforward(float N, float I, float Nref);"));
+ s.append(TString("vec2 faceforward(vec2 N, vec2 I, vec2 Nref);"));
+ s.append(TString("vec3 faceforward(vec3 N, vec3 I, vec3 Nref);"));
+ s.append(TString("vec4 faceforward(vec4 N, vec4 I, vec4 Nref);"));
+
+ s.append(TString("float reflect(float I, float N);"));
+ s.append(TString("vec2 reflect(vec2 I, vec2 N);"));
+ s.append(TString("vec3 reflect(vec3 I, vec3 N);"));
+ s.append(TString("vec4 reflect(vec4 I, vec4 N);"));
+
+ s.append(TString("float refract(float I, float N, float eta);"));
+ s.append(TString("vec2 refract(vec2 I, vec2 N, float eta);"));
+ s.append(TString("vec3 refract(vec3 I, vec3 N, float eta);"));
+ s.append(TString("vec4 refract(vec4 I, vec4 N, float eta);"));
+
+ //
+ // Matrix Functions.
+ //
+ s.append(TString("mat2 matrixCompMult(mat2 x, mat2 y);"));
+ s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);"));
+ s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);"));
+
+ //
+ // Vector relational functions.
+ //
+ s.append(TString("bvec2 lessThan(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 lessThan(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 lessThan(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 lessThan(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 lessThan(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 lessThan(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 lessThanEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 lessThanEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 lessThanEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 lessThanEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 lessThanEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 lessThanEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 greaterThan(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 greaterThan(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 greaterThan(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 greaterThan(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 greaterThan(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 greaterThan(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 greaterThanEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 greaterThanEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 greaterThanEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 greaterThanEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 greaterThanEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 greaterThanEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 equal(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 equal(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 equal(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 equal(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 equal(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 equal(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 equal(bvec2 x, bvec2 y);"));
+ s.append(TString("bvec3 equal(bvec3 x, bvec3 y);"));
+ s.append(TString("bvec4 equal(bvec4 x, bvec4 y);"));
+
+ s.append(TString("bvec2 notEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 notEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 notEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 notEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 notEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 notEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 notEqual(bvec2 x, bvec2 y);"));
+ s.append(TString("bvec3 notEqual(bvec3 x, bvec3 y);"));
+ s.append(TString("bvec4 notEqual(bvec4 x, bvec4 y);"));
+
+ s.append(TString("bool any(bvec2 x);"));
+ s.append(TString("bool any(bvec3 x);"));
+ s.append(TString("bool any(bvec4 x);"));
+
+ s.append(TString("bool all(bvec2 x);"));
+ s.append(TString("bool all(bvec3 x);"));
+ s.append(TString("bool all(bvec4 x);"));
+
+ s.append(TString("bvec2 not(bvec2 x);"));
+ s.append(TString("bvec3 not(bvec3 x);"));
+ s.append(TString("bvec4 not(bvec4 x);"));
+
+ //
+ // Texture Functions.
+ //
+ s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);"));
+ s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);"));
+
+ if (resources.OES_EGL_image_external) {
+ s.append(TString("vec4 texture2D(samplerExternalOES sampler, vec2 coord);"));
+ s.append(TString("vec4 texture2DProj(samplerExternalOES sampler, vec3 coord);"));
+ s.append(TString("vec4 texture2DProj(samplerExternalOES sampler, vec4 coord);"));
+ }
+
+ if (resources.ARB_texture_rectangle) {
+ s.append(TString("vec4 texture2DRect(sampler2DRect sampler, vec2 coord);"));
+ s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec3 coord);"));
+ s.append(TString("vec4 texture2DRectProj(sampler2DRect sampler, vec4 coord);"));
+ }
+
+ //
+ // Noise functions.
+ //
+ //s.append(TString("float noise1(float x);"));
+ //s.append(TString("float noise1(vec2 x);"));
+ //s.append(TString("float noise1(vec3 x);"));
+ //s.append(TString("float noise1(vec4 x);"));
+
+ //s.append(TString("vec2 noise2(float x);"));
+ //s.append(TString("vec2 noise2(vec2 x);"));
+ //s.append(TString("vec2 noise2(vec3 x);"));
+ //s.append(TString("vec2 noise2(vec4 x);"));
+
+ //s.append(TString("vec3 noise3(float x);"));
+ //s.append(TString("vec3 noise3(vec2 x);"));
+ //s.append(TString("vec3 noise3(vec3 x);"));
+ //s.append(TString("vec3 noise3(vec4 x);"));
+
+ //s.append(TString("vec4 noise4(float x);"));
+ //s.append(TString("vec4 noise4(vec2 x);"));
+ //s.append(TString("vec4 noise4(vec3 x);"));
+ //s.append(TString("vec4 noise4(vec4 x);"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by vertex shaders only.
+//
+//============================================================================
+static TString BuiltInFunctionsVertex(const ShBuiltInResources& resources)
+{
+ TString s;
+
+ //
+ // Geometric Functions.
+ //
+ //s.append(TString("vec4 ftransform();"));
+
+ //
+ // Texture Functions.
+ //
+ s.append(TString("vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);"));
+ s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);"));
+ s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);"));
+ s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by fragment shaders only.
+//
+//============================================================================
+static TString BuiltInFunctionsFragment(const ShBuiltInResources& resources)
+{
+ TString s;
+
+ //
+ // Texture Functions.
+ //
+ s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord, float bias);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);"));
+ s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);"));
+
+ if (resources.OES_standard_derivatives) {
+ s.append(TString("float dFdx(float p);"));
+ s.append(TString("vec2 dFdx(vec2 p);"));
+ s.append(TString("vec3 dFdx(vec3 p);"));
+ s.append(TString("vec4 dFdx(vec4 p);"));
+
+ s.append(TString("float dFdy(float p);"));
+ s.append(TString("vec2 dFdy(vec2 p);"));
+ s.append(TString("vec3 dFdy(vec3 p);"));
+ s.append(TString("vec4 dFdy(vec4 p);"));
+
+ s.append(TString("float fwidth(float p);"));
+ s.append(TString("vec2 fwidth(vec2 p);"));
+ s.append(TString("vec3 fwidth(vec3 p);"));
+ s.append(TString("vec4 fwidth(vec4 p);"));
+ }
+
+ return s;
+}
+
+//============================================================================
+//
+// Standard uniforms.
+//
+//============================================================================
+static TString StandardUniforms()
+{
+ TString s;
+
+ //
+ // Depth range in window coordinates
+ //
+ s.append(TString("struct gl_DepthRangeParameters {"));
+ s.append(TString(" highp float near;")); // n
+ s.append(TString(" highp float far;")); // f
+ s.append(TString(" highp float diff;")); // f - n
+ s.append(TString("};"));
+ s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Default precision for vertex shaders.
+//
+//============================================================================
+static TString DefaultPrecisionVertex()
+{
+ TString s;
+
+ s.append(TString("precision highp int;"));
+ s.append(TString("precision highp float;"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Default precision for fragment shaders.
+//
+//============================================================================
+static TString DefaultPrecisionFragment()
+{
+ TString s;
+
+ s.append(TString("precision mediump int;"));
+ // No default precision for float in fragment shaders
+
+ return s;
+}
+
+//============================================================================
+//
+// Implementation dependent built-in constants.
+//
+//============================================================================
+static TString BuiltInConstants(ShShaderSpec spec, const ShBuiltInResources &resources)
+{
+ TStringStream s;
+
+ s << "const int gl_MaxVertexAttribs = " << resources.MaxVertexAttribs << ";";
+ s << "const int gl_MaxVertexUniformVectors = " << resources.MaxVertexUniformVectors << ";";
+
+ s << "const int gl_MaxVaryingVectors = " << resources.MaxVaryingVectors << ";";
+ s << "const int gl_MaxVertexTextureImageUnits = " << resources.MaxVertexTextureImageUnits << ";";
+ s << "const int gl_MaxCombinedTextureImageUnits = " << resources.MaxCombinedTextureImageUnits << ";";
+ s << "const int gl_MaxTextureImageUnits = " << resources.MaxTextureImageUnits << ";";
+ s << "const int gl_MaxFragmentUniformVectors = " << resources.MaxFragmentUniformVectors << ";";
+
+ if (spec != SH_CSS_SHADERS_SPEC)
+ s << "const int gl_MaxDrawBuffers = " << resources.MaxDrawBuffers << ";";
+
+ return s.str();
+}
+
+void TBuiltIns::initialize(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources)
+{
+ switch (type) {
+ case SH_FRAGMENT_SHADER:
+ builtInStrings.push_back(DefaultPrecisionFragment());
+ builtInStrings.push_back(BuiltInFunctionsCommon(resources));
+ builtInStrings.push_back(BuiltInFunctionsFragment(resources));
+ builtInStrings.push_back(StandardUniforms());
+ break;
+
+ case SH_VERTEX_SHADER:
+ builtInStrings.push_back(DefaultPrecisionVertex());
+ builtInStrings.push_back(BuiltInFunctionsCommon(resources));
+ builtInStrings.push_back(BuiltInFunctionsVertex(resources));
+ builtInStrings.push_back(StandardUniforms());
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ builtInStrings.push_back(BuiltInConstants(spec, resources));
+}
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable)
+{
+ //
+ // First, insert some special built-in variables that are not in
+ // the built-in header files.
+ //
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
+
+ //
+ // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
+ // Instead, css_MixColor and css_ColorMatrix are available.
+ //
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
+ } else {
+ symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, true)));
+ }
+
+ break;
+
+ case SH_VERTEX_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ //
+ // Next, identify which built-ins from the already loaded headers have
+ // a mapping to an operator. Those that are not identified as such are
+ // expected to be resolved through a library of functions, versus as
+ // operations.
+ //
+ symbolTable.relateToOperator("not", EOpVectorLogicalNot);
+
+ symbolTable.relateToOperator("matrixCompMult", EOpMul);
+
+ symbolTable.relateToOperator("equal", EOpVectorEqual);
+ symbolTable.relateToOperator("notEqual", EOpVectorNotEqual);
+ symbolTable.relateToOperator("lessThan", EOpLessThan);
+ symbolTable.relateToOperator("greaterThan", EOpGreaterThan);
+ symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual);
+ symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual);
+
+ symbolTable.relateToOperator("radians", EOpRadians);
+ symbolTable.relateToOperator("degrees", EOpDegrees);
+ symbolTable.relateToOperator("sin", EOpSin);
+ symbolTable.relateToOperator("cos", EOpCos);
+ symbolTable.relateToOperator("tan", EOpTan);
+ symbolTable.relateToOperator("asin", EOpAsin);
+ symbolTable.relateToOperator("acos", EOpAcos);
+ symbolTable.relateToOperator("atan", EOpAtan);
+
+ symbolTable.relateToOperator("pow", EOpPow);
+ symbolTable.relateToOperator("exp2", EOpExp2);
+ symbolTable.relateToOperator("log", EOpLog);
+ symbolTable.relateToOperator("exp", EOpExp);
+ symbolTable.relateToOperator("log2", EOpLog2);
+ symbolTable.relateToOperator("sqrt", EOpSqrt);
+ symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt);
+
+ symbolTable.relateToOperator("abs", EOpAbs);
+ symbolTable.relateToOperator("sign", EOpSign);
+ symbolTable.relateToOperator("floor", EOpFloor);
+ symbolTable.relateToOperator("ceil", EOpCeil);
+ symbolTable.relateToOperator("fract", EOpFract);
+ symbolTable.relateToOperator("mod", EOpMod);
+ symbolTable.relateToOperator("min", EOpMin);
+ symbolTable.relateToOperator("max", EOpMax);
+ symbolTable.relateToOperator("clamp", EOpClamp);
+ symbolTable.relateToOperator("mix", EOpMix);
+ symbolTable.relateToOperator("step", EOpStep);
+ symbolTable.relateToOperator("smoothstep", EOpSmoothStep);
+
+ symbolTable.relateToOperator("length", EOpLength);
+ symbolTable.relateToOperator("distance", EOpDistance);
+ symbolTable.relateToOperator("dot", EOpDot);
+ symbolTable.relateToOperator("cross", EOpCross);
+ symbolTable.relateToOperator("normalize", EOpNormalize);
+ symbolTable.relateToOperator("faceforward", EOpFaceForward);
+ symbolTable.relateToOperator("reflect", EOpReflect);
+ symbolTable.relateToOperator("refract", EOpRefract);
+
+ symbolTable.relateToOperator("any", EOpAny);
+ symbolTable.relateToOperator("all", EOpAll);
+
+ // Map language-specific operators.
+ switch(type) {
+ case SH_VERTEX_SHADER:
+ break;
+ case SH_FRAGMENT_SHADER:
+ if (resources.OES_standard_derivatives) {
+ symbolTable.relateToOperator("dFdx", EOpDFdx);
+ symbolTable.relateToOperator("dFdy", EOpDFdy);
+ symbolTable.relateToOperator("fwidth", EOpFwidth);
+
+ symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives");
+ }
+ break;
+ default: break;
+ }
+
+ // Finally add resource-specific variables.
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ // Set up gl_FragData. The array size.
+ TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
+ }
+ break;
+ default: break;
+ }
+}
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ extBehavior["GL_OES_standard_derivatives"] = EBhUndefined;
+ if (resources.OES_EGL_image_external)
+ extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
+ if (resources.ARB_texture_rectangle)
+ extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+}
diff --git a/src/3rdparty/angle/src/compiler/Initialize.h b/src/3rdparty/angle/src/compiler/Initialize.h
new file mode 100644
index 0000000000..8b0adc6b4c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Initialize.h
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "compiler/Common.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+typedef TVector<TString> TBuiltInStrings;
+
+class TBuiltIns {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ void initialize(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources);
+ const TBuiltInStrings& getBuiltInStrings() { return builtInStrings; }
+
+protected:
+ TBuiltInStrings builtInStrings;
+};
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable);
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extensionBehavior);
+
+#endif // _INITIALIZE_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/InitializeDll.cpp b/src/3rdparty/angle/src/compiler/InitializeDll.cpp
new file mode 100644
index 0000000000..8763cfeea8
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InitializeDll.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InitializeDll.h"
+
+#include "compiler/InitializeGlobals.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/osinclude.h"
+
+OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+bool InitProcess()
+{
+ if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
+ //
+ // Function is re-entrant.
+ //
+ return true;
+ }
+
+ ThreadInitializeIndex = OS_AllocTLSIndex();
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
+ return false;
+ }
+
+
+ if (!InitializePoolIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize global pool");
+ return false;
+ }
+
+ if (!InitializeParseContextIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize parse context");
+ return false;
+ }
+
+ return InitThread();
+}
+
+bool DetachProcess()
+{
+ bool success = true;
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+ return true;
+
+ success = DetachThread();
+
+ if (!FreeParseContextIndex())
+ success = false;
+
+ FreePoolIndex();
+
+ OS_FreeTLSIndex(ThreadInitializeIndex);
+ ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+ return success;
+}
+
+bool InitThread()
+{
+ //
+ // This function is re-entrant
+ //
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitThread(): Process hasn't been initalised.");
+ return false;
+ }
+
+ if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
+ return true;
+
+ InitializeGlobalPools();
+
+ if (!InitializeGlobalParseContext())
+ return false;
+
+ if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
+ assert(0 && "InitThread(): Unable to set init flag.");
+ return false;
+ }
+
+ return true;
+}
+
+bool DetachThread()
+{
+ bool success = true;
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+ return true;
+
+ //
+ // Function is re-entrant and this thread may not have been initalised.
+ //
+ if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
+ if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
+ assert(0 && "DetachThread(): Unable to clear init flag.");
+ success = false;
+ }
+
+ if (!FreeParseContext())
+ success = false;
+
+ FreeGlobalPools();
+ }
+
+ return success;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/InitializeDll.h b/src/3rdparty/angle/src/compiler/InitializeDll.h
new file mode 100644
index 0000000000..857238eeae
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InitializeDll.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+bool InitProcess();
+bool DetachProcess();
+
+bool InitThread();
+bool DetachThread();
+
+#endif // __INITIALIZEDLL_H
+
diff --git a/src/3rdparty/angle/src/compiler/InitializeGlobals.h b/src/3rdparty/angle/src/compiler/InitializeGlobals.h
new file mode 100644
index 0000000000..842a45281d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InitializeGlobals.h
@@ -0,0 +1,15 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+void InitializeGlobalPools();
+void FreeGlobalPools();
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp b/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp
new file mode 100644
index 0000000000..1f40cf5800
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InitializeParseContext.cpp
@@ -0,0 +1,96 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InitializeParseContext.h"
+
+#include "compiler/osinclude.h"
+
+OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializeParseContextIndex()
+{
+ if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
+ return false;
+ }
+
+ //
+ // Allocate a TLS index.
+ //
+ GlobalParseContextIndex = OS_AllocTLSIndex();
+
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
+ return false;
+ }
+
+ return true;
+}
+
+bool FreeParseContextIndex()
+{
+ OS_TLSIndex tlsiIndex = GlobalParseContextIndex;
+
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "FreeParseContextIndex(): Parse Context index not initalized");
+ return false;
+ }
+
+ GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+ return OS_FreeTLSIndex(tlsiIndex);
+}
+
+bool InitializeGlobalParseContext()
+{
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalized");
+ return false;
+ }
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+ if (lpParseContext != 0) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalized");
+ return false;
+ }
+
+ TThreadParseContext *lpThreadData = new TThreadParseContext();
+ if (lpThreadData == 0) {
+ assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context");
+ return false;
+ }
+
+ lpThreadData->lpGlobalParseContext = 0;
+ OS_SetTLSValue(GlobalParseContextIndex, lpThreadData);
+
+ return true;
+}
+
+bool FreeParseContext()
+{
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "FreeParseContext(): Parse Context index not initalized");
+ return false;
+ }
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+ if (lpParseContext)
+ delete lpParseContext;
+
+ return true;
+}
+
+TParseContextPointer& GetGlobalParseContext()
+{
+ //
+ // Minimal error checking for speed
+ //
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+
+ return lpParseContext->lpGlobalParseContext;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/InitializeParseContext.h
new file mode 100644
index 0000000000..aa53b735d4
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/InitializeParseContext.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+
+bool InitializeParseContextIndex();
+bool FreeParseContextIndex();
+
+bool InitializeGlobalParseContext();
+bool FreeParseContext();
+
+struct TParseContext;
+typedef TParseContext* TParseContextPointer;
+extern TParseContextPointer& GetGlobalParseContext();
+#define GlobalParseContext GetGlobalParseContext()
+
+typedef struct TThreadParseContextRec
+{
+ TParseContext *lpGlobalParseContext;
+} TThreadParseContext;
+
+#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/IntermTraverse.cpp
new file mode 100644
index 0000000000..a13877f18f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/IntermTraverse.cpp
@@ -0,0 +1,293 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+// preVisit, postVisit, and rightToLeft control what order
+// nodes are visited in.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermSymbol::traverse(TIntermTraverser* it)
+{
+ it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser* it)
+{
+ it->visitConstantUnion(this);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermBinary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if(it->preVisit)
+ {
+ visit = it->visitBinary(PreVisit, this);
+ }
+
+ //
+ // Visit the children, in the right order.
+ //
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(right)
+ {
+ right->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && left)
+ {
+ left->traverse(it);
+ }
+ }
+ else
+ {
+ if(left)
+ {
+ left->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && right)
+ {
+ right->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if(visit && it->postVisit)
+ {
+ it->visitBinary(PostVisit, this);
+ }
+}
+
+//
+// Traverse a unary node. Same comments in binary node apply here.
+//
+void TIntermUnary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitUnary(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ operand->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitUnary(PostVisit, this);
+}
+
+//
+// Traverse an aggregate node. Same comments in binary node apply here.
+//
+void TIntermAggregate::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitAggregate(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.front())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.back())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitAggregate(PostVisit, this);
+ }
+}
+
+//
+// Traverse a selection node. Same comments in binary node apply here.
+//
+void TIntermSelection::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitSelection(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ if (it->rightToLeft) {
+ if (falseBlock)
+ falseBlock->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ condition->traverse(it);
+ } else {
+ condition->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ if (falseBlock)
+ falseBlock->traverse(it);
+ }
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitSelection(PostVisit, this);
+}
+
+//
+// Traverse a loop node. Same comments in binary node apply here.
+//
+void TIntermLoop::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitLoop(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+ }
+ else
+ {
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitLoop(PostVisit, this);
+ }
+}
+
+//
+// Traverse a branch node. Same comments in binary node apply here.
+//
+void TIntermBranch::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitBranch(PreVisit, this);
+
+ if (visit && expression) {
+ it->incrementDepth();
+ expression->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitBranch(PostVisit, this);
+}
+
diff --git a/src/3rdparty/angle/src/compiler/Intermediate.cpp b/src/3rdparty/angle/src/compiler/Intermediate.cpp
new file mode 100644
index 0000000000..92c450530e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Intermediate.cpp
@@ -0,0 +1,1447 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "compiler/localintermediate.h"
+#include "compiler/QualifierAlive.h"
+#include "compiler/RemoveTree.h"
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
+
+static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
+ return left > right ? left : right;
+}
+
+const char* getOperatorString(TOperator op) {
+ switch (op) {
+ case EOpInitialize: return "=";
+ case EOpAssign: return "=";
+ case EOpAddAssign: return "+=";
+ case EOpSubAssign: return "-=";
+ case EOpDivAssign: return "/=";
+
+ // Fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign: return "*=";
+
+ // Fall-through.
+ case EOpIndexDirect:
+ case EOpIndexIndirect: return "[]";
+
+ case EOpIndexDirectStruct: return ".";
+ case EOpVectorSwizzle: return ".";
+ case EOpAdd: return "+";
+ case EOpSub: return "-";
+ case EOpMul: return "*";
+ case EOpDiv: return "/";
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: return "==";
+ case EOpNotEqual: return "!=";
+ case EOpLessThan: return "<";
+ case EOpGreaterThan: return ">";
+ case EOpLessThanEqual: return "<=";
+ case EOpGreaterThanEqual: return ">=";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix: return "*";
+
+ case EOpLogicalOr: return "||";
+ case EOpLogicalXor: return "^^";
+ case EOpLogicalAnd: return "&&";
+ case EOpNegative: return "-";
+ case EOpVectorLogicalNot: return "not";
+ case EOpLogicalNot: return "!";
+ case EOpPostIncrement: return "++";
+ case EOpPostDecrement: return "--";
+ case EOpPreIncrement: return "++";
+ case EOpPreDecrement: return "--";
+
+ // Fall-through.
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool: return "bool";
+
+ // Fall-through.
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat: return "float";
+
+ // Fall-through.
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt: return "int";
+
+ case EOpRadians: return "radians";
+ case EOpDegrees: return "degrees";
+ case EOpSin: return "sin";
+ case EOpCos: return "cos";
+ case EOpTan: return "tan";
+ case EOpAsin: return "asin";
+ case EOpAcos: return "acos";
+ case EOpAtan: return "atan";
+ case EOpExp: return "exp";
+ case EOpLog: return "log";
+ case EOpExp2: return "exp2";
+ case EOpLog2: return "log2";
+ case EOpSqrt: return "sqrt";
+ case EOpInverseSqrt: return "inversesqrt";
+ case EOpAbs: return "abs";
+ case EOpSign: return "sign";
+ case EOpFloor: return "floor";
+ case EOpCeil: return "ceil";
+ case EOpFract: return "fract";
+ case EOpLength: return "length";
+ case EOpNormalize: return "normalize";
+ case EOpDFdx: return "dFdx";
+ case EOpDFdy: return "dFdy";
+ case EOpFwidth: return "fwidth";
+ case EOpAny: return "any";
+ case EOpAll: return "all";
+
+ default: break;
+ }
+ return "";
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
+{
+ TIntermSymbol* node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable)
+{
+ switch (op) {
+ case EOpEqual:
+ case EOpNotEqual:
+ if (left->isArray())
+ return 0;
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
+ return 0;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
+ return 0;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+ return 0;
+ default: break;
+ }
+
+ //
+ // First try converting the children to compatible types.
+ //
+ if (left->getType().getStruct() && right->getType().getStruct()) {
+ if (left->getType() != right->getType())
+ return 0;
+ } else {
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child)
+ right = child;
+ else {
+ child = addConversion(op, right->getType(), left);
+ if (child)
+ left = child;
+ else
+ return 0;
+ }
+ }
+
+ //
+ // Need a new node holding things together then. Make
+ // one and promote it to the right type.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = right->getLine();
+ node->setLine(line);
+
+ node->setLeft(left);
+ node->setRight(right);
+ if (!node->promote(infoSink))
+ return 0;
+
+ //
+ // See if we can fold constants.
+ //
+ TIntermTyped* typedReturnNode = 0;
+ TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+ TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+ if (leftTempConstant && rightTempConstant) {
+ typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
+
+ if (typedReturnNode)
+ return typedReturnNode;
+ }
+
+ return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
+{
+ //
+ // Like adding binary math, except the conversion can only go
+ // from right to left.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = left->getLine();
+ node->setLine(line);
+
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child == 0)
+ return 0;
+
+ node->setLeft(left);
+ node->setRight(child);
+ if (! node->promote(infoSink))
+ return 0;
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
+{
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = index->getLine();
+ node->setLine(line);
+ node->setLeft(base);
+ node->setRight(index);
+
+ // caller should set the type
+
+ return node;
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable)
+{
+ TIntermUnary* node;
+ TIntermTyped* child = childNode->getAsTyped();
+
+ if (child == 0) {
+ infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
+ return 0;
+ }
+
+ switch (op) {
+ case EOpLogicalNot:
+ if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+ return 0;
+ }
+ break;
+
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+ return 0;
+ default: break;
+ }
+
+ //
+ // Do we need to promote the operand?
+ //
+ // Note: Implicit promotions were removed from the language.
+ //
+ TBasicType newType = EbtVoid;
+ switch (op) {
+ case EOpConstructInt: newType = EbtInt; break;
+ case EOpConstructBool: newType = EbtBool; break;
+ case EOpConstructFloat: newType = EbtFloat; break;
+ default: break;
+ }
+
+ if (newType != EbtVoid) {
+ child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
+ child->getNominalSize(),
+ child->isMatrix(),
+ child->isArray()),
+ child);
+ if (child == 0)
+ return 0;
+ }
+
+ //
+ // For constructors, we are now done, it's all in the conversion.
+ //
+ switch (op) {
+ case EOpConstructInt:
+ case EOpConstructBool:
+ case EOpConstructFloat:
+ return child;
+ default: break;
+ }
+
+ TIntermConstantUnion *childTempConstant = 0;
+ if (child->getAsConstantUnion())
+ childTempConstant = child->getAsConstantUnion();
+
+ //
+ // Make a new node for the operator.
+ //
+ node = new TIntermUnary(op);
+ if (line == 0)
+ line = child->getLine();
+ node->setLine(line);
+ node->setOperand(child);
+
+ if (! node->promote(infoSink))
+ return 0;
+
+ if (childTempConstant) {
+ TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
+
+ if (newChild)
+ return newChild;
+ }
+
+ return node;
+}
+
+//
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters. Sequences
+// of instructions are also aggregates, but they just direnctly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate but no operator was set.
+//
+TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
+{
+ TIntermAggregate* aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node) {
+ aggNode = node->getAsAggregate();
+ if (aggNode == 0 || aggNode->getOp() != EOpNull) {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence().push_back(node);
+ if (line == 0)
+ line = node->getLine();
+ }
+ } else
+ aggNode = new TIntermAggregate();
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ if (line != 0)
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Convert one type to another.
+//
+// Returns the node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Return 0 if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+ //
+ // Does the base type allow operation?
+ //
+ switch (node->getBasicType()) {
+ case EbtVoid:
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ return 0;
+ default: break;
+ }
+
+ //
+ // Otherwise, if types are identical, no problem
+ //
+ if (type == node->getType())
+ return node;
+
+ //
+ // If one's a structure, then no conversions.
+ //
+ if (type.getStruct() || node->getType().getStruct())
+ return 0;
+
+ //
+ // If one's an array, then no conversions.
+ //
+ if (type.isArray() || node->getType().isArray())
+ return 0;
+
+ TBasicType promoteTo;
+
+ switch (op) {
+ //
+ // Explicit conversions
+ //
+ case EOpConstructBool:
+ promoteTo = EbtBool;
+ break;
+ case EOpConstructFloat:
+ promoteTo = EbtFloat;
+ break;
+ case EOpConstructInt:
+ promoteTo = EbtInt;
+ break;
+ default:
+ //
+ // implicit conversions were removed from the language.
+ //
+ if (type.getBasicType() != node->getType().getBasicType())
+ return 0;
+ //
+ // Size and structure could still differ, but that's
+ // handled by operator promotion.
+ //
+ return node;
+ }
+
+ if (node->getAsConstantUnion()) {
+
+ return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
+ } else {
+
+ //
+ // Add a new newNode for the conversion.
+ //
+ TIntermUnary* newNode = 0;
+
+ TOperator newOp = EOpNull;
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToFloat; break;
+ case EbtBool: newOp = EOpConvBoolToFloat; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToBool; break;
+ case EbtFloat: newOp = EOpConvFloatToBool; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getBasicType()) {
+ case EbtBool: newOp = EOpConvBoolToInt; break;
+ case EbtFloat: newOp = EOpConvFloatToInt; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine());
+ return 0;
+ }
+
+ TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
+ newNode = new TIntermUnary(newOp, type);
+ newNode->setLine(node->getLine());
+ newNode->setOperand(node);
+
+ return newNode;
+ }
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
+{
+ if (left == 0 && right == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = 0;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull) {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence().push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence().push_back(right);
+
+ if (line != 0)
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless 0 was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = new TIntermAggregate;
+ aggNode->getSequence().push_back(node);
+
+ if (line != 0)
+ aggNode->setLine(line);
+ else
+ aggNode->setLine(node->getLine());
+
+ return aggNode;
+}
+
+//
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the selection node created.
+//
+TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
+{
+ //
+ // For compile time constant selections, prune the code and
+ // test now.
+ //
+
+ if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
+ if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst() == true)
+ return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
+ else
+ return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
+ }
+
+ TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+ node->setLine(line);
+
+ return node;
+}
+
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
+{
+ if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
+ return right;
+ } else {
+ TIntermTyped *commaAggregate = growAggregate(left, right, line);
+ commaAggregate->getAsAggregate()->setOp(EOpComma);
+ commaAggregate->setType(right->getType());
+ commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
+ return commaAggregate;
+ }
+}
+
+//
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the selection node created, or 0 if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
+{
+ //
+ // Get compatible types.
+ //
+ TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
+ if (child)
+ falseBlock = child;
+ else {
+ child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
+ if (child)
+ trueBlock = child;
+ else
+ return 0;
+ }
+
+ //
+ // See if all the operands are constant, then fold it otherwise not.
+ //
+
+ if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
+ return trueBlock;
+ else
+ return falseBlock;
+ }
+
+ //
+ // Make a selection node.
+ //
+ TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+ node->getTypePointer()->setQualifier(EvqTemporary);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line)
+{
+ TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
+{
+
+ TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+ node->setLine(line);
+ TIntermConstantUnion* constIntNode;
+ TIntermSequence &sequenceVector = node->getSequence();
+ ConstantUnion* unionArray;
+
+ for (int i = 0; i < fields.num; i++) {
+ unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[i]);
+ constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
+ sequenceVector.push_back(constIntNode);
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line)
+{
+ TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
+{
+ TIntermBranch* node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// This is to be executed once the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root)
+{
+ if (root == 0)
+ return true;
+
+ //
+ // First, finish off the top level sequence, if any
+ //
+ TIntermAggregate* aggRoot = root->getAsAggregate();
+ if (aggRoot && aggRoot->getOp() == EOpNull)
+ aggRoot->setOp(EOpSequence);
+
+ return true;
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::remove(TIntermNode* root)
+{
+ if (root)
+ RemoveAllTreeNodes(root);
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+// Returns true if state is modified.
+//
+bool TIntermOperator::modifiesState() const
+{
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ case EOpConstructStruct:
+ return true;
+ default:
+ return false;
+ }
+}
+//
+// Make sure the type of a unary operator is appropriate for its
+// combination of operation and operand type.
+//
+// Returns false in nothing makes sense.
+//
+bool TIntermUnary::promote(TInfoSink&)
+{
+ switch (op) {
+ case EOpLogicalNot:
+ if (operand->getBasicType() != EbtBool)
+ return false;
+ break;
+ case EOpNegative:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ if (operand->getBasicType() == EbtBool)
+ return false;
+ break;
+
+ // operators for built-ins are already type checked against their prototype
+ case EOpAny:
+ case EOpAll:
+ case EOpVectorLogicalNot:
+ return true;
+
+ default:
+ if (operand->getBasicType() != EbtFloat)
+ return false;
+ }
+
+ setType(operand->getType());
+
+ return true;
+}
+
+//
+// Establishes the type of the resultant operation, as well as
+// makes the operator the correct one for the operands.
+//
+// Returns false if operator can't work on operands.
+//
+bool TIntermBinary::promote(TInfoSink& infoSink)
+{
+ // This function only handles scalars, vectors, and matrices.
+ if (left->isArray() || right->isArray()) {
+ infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
+ return false;
+ }
+
+ // GLSL ES 2.0 does not support implicit type casting.
+ // So the basic type should always match.
+ if (left->getBasicType() != right->getBasicType())
+ return false;
+
+ //
+ // Base assumption: just make the type the same as the left
+ // operand. Then only deviations from this need be coded.
+ //
+ setType(left->getType());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
+ getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ int size = std::max(left->getNominalSize(), right->getNominalSize());
+
+ //
+ // All scalars. Code after this test assumes this case is removed!
+ //
+ if (size == 1) {
+ switch (op) {
+ //
+ // Promote to conditional
+ //
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ //
+ // And and Or operate on conditionals
+ //
+ case EOpLogicalAnd:
+ case EOpLogicalOr:
+ // Both operands must be of type bool.
+ if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
+ // Are the sizes compatible?
+ //
+ if (left->getNominalSize() != right->getNominalSize()) {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
+ return false;
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
+
+ //
+ // Can these two operands be combined?
+ //
+ TBasicType basicType = left->getBasicType();
+ switch (op) {
+ case EOpMul:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrix;
+ else {
+ op = EOpMatrixTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ op = EOpMatrixTimesVector;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ } else {
+ op = EOpMatrixTimesScalar;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrix;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ op = EOpVectorTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
+ return false;
+ }
+ break;
+ case EOpMulAssign:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrixAssign;
+ else {
+ return false;
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ return false;
+ } else {
+ op = EOpMatrixTimesScalarAssign;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrixAssign;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ if (! left->isVector())
+ return false;
+ op = EOpVectorTimesScalarAssign;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
+ return false;
+ }
+ break;
+
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ const TTypeList* fields = leftNodeType.getStruct();
+
+ size_t structSize = fields->size();
+ int index = 0;
+
+ for (size_t j = 0; j < structSize; j++) {
+ int size = (*fields)[j].type->getObjectSize();
+ for (int i = 0; i < size; i++) {
+ if ((*fields)[j].type->getBasicType() == EbtStruct) {
+ if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
+ return false;
+ } else {
+ if (leftUnionArray[index] != rightUnionArray[index])
+ return false;
+ index++;
+ }
+
+ }
+ }
+ return true;
+}
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ if (leftNodeType.isArray()) {
+ TType typeWithoutArrayness = leftNodeType;
+ typeWithoutArrayness.clearArrayness();
+
+ int arraySize = leftNodeType.getArraySize();
+
+ for (int i = 0; i < arraySize; ++i) {
+ int offset = typeWithoutArrayness.getObjectSize() * i;
+ if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
+ return false;
+ }
+ } else
+ return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
+
+ return true;
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
+{
+ ConstantUnion *unionArray = getUnionArrayPointer();
+ int objectSize = getType().getObjectSize();
+
+ if (constantNode) { // binary operations
+ TIntermConstantUnion *node = constantNode->getAsConstantUnion();
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ TType returnType = getType();
+
+ // for a case like float f = 1.2 + vec4(2,3,4,5);
+ if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
+ rightUnionArray = new ConstantUnion[objectSize];
+ for (int i = 0; i < objectSize; ++i)
+ rightUnionArray[i] = *node->getUnionArrayPointer();
+ returnType = getType();
+ } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
+ // for a case like float f = vec4(2,3,4,5) + 1.2;
+ unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
+ for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
+ unionArray[i] = *getUnionArrayPointer();
+ returnType = node->getType();
+ objectSize = constantNode->getType().getObjectSize();
+ }
+
+ ConstantUnion* tempConstArray = 0;
+ TIntermConstantUnion *tempNode;
+
+ bool boolNodeFlag = false;
+ switch(op) {
+ case EOpAdd:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] + rightUnionArray[i];
+ }
+ break;
+ case EOpSub:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] - rightUnionArray[i];
+ }
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] * rightUnionArray[i];
+ }
+ break;
+ case EOpMatrixTimesMatrix:
+ if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
+ return 0;
+ }
+ {// support MSVC++6.0
+ int size = getNominalSize();
+ tempConstArray = new ConstantUnion[size*size];
+ for (int row = 0; row < size; row++) {
+ for (int column = 0; column < size; column++) {
+ tempConstArray[size * column + row].setFConst(0.0f);
+ for (int i = 0; i < size; i++) {
+ tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
+ }
+ }
+ }
+ }
+ break;
+ case EOpDiv:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++) {
+ switch (getType().getBasicType()) {
+ case EbtFloat:
+ if (rightUnionArray[i] == 0.0f) {
+ infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+ tempConstArray[i].setFConst(FLT_MAX);
+ } else
+ tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
+ break;
+
+ case EbtInt:
+ if (rightUnionArray[i] == 0) {
+ infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+ tempConstArray[i].setIConst(INT_MAX);
+ } else
+ tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ if (node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
+ return 0;
+ }
+ tempConstArray = new ConstantUnion[getNominalSize()];
+
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
+ }
+ }
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpVectorTimesMatrix:
+ if (getType().getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
+ return 0;
+ }
+
+ tempConstArray = new ConstantUnion[getNominalSize()];
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
+ }
+ }
+ }
+ break;
+
+ case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] && rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] || rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalXor:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
+ default: assert(false && "Default missing");
+ }
+ }
+ break;
+
+ case EOpLessThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray < *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpGreaterThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray > *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpLessThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray > *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+ case EOpGreaterThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray < *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+
+ case EOpEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (int i = 0; i < objectSize; i++) {
+ if (unionArray[i] != rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpNotEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (int i = 0; i < objectSize; i++) {
+ if (unionArray[i] == rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
+ return 0;
+ }
+ tempNode = new TIntermConstantUnion(tempConstArray, returnType);
+ tempNode->setLine(getLine());
+
+ return tempNode;
+ } else {
+ //
+ // Do unary operations
+ //
+ TIntermConstantUnion *newNode = 0;
+ ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+ for (int i = 0; i < objectSize; i++) {
+ switch(op) {
+ case EOpNegative:
+ switch (getType().getBasicType()) {
+ case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
+ case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+ return 0;
+ }
+ break;
+ case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ }
+ newNode = new TIntermConstantUnion(tempConstArray, getType());
+ newNode->setLine(getLine());
+ return newNode;
+ }
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
+{
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ int size = node->getType().getObjectSize();
+
+ ConstantUnion *leftUnionArray = new ConstantUnion[size];
+
+ for (int i=0; i < size; i++) {
+
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst()));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst()));
+ break;
+ case EbtFloat:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ case EbtBool:
+ leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst()));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
+ break;
+ case EbtBool:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f);
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
+ return 0;
+ }
+
+ }
+
+ const TType& t = node->getType();
+
+ return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
+}
+
diff --git a/src/3rdparty/angle/src/compiler/MMap.h b/src/3rdparty/angle/src/compiler/MMap.h
new file mode 100644
index 0000000000..a308671514
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/MMap.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _MMAP_INCLUDED_
+#define _MMAP_INCLUDED_
+
+//
+// Encapsulate memory mapped files
+//
+
+class TMMap {
+public:
+ TMMap(const char* fileName) :
+ fSize(-1), // -1 is the error value returned by GetFileSize()
+ fp(NULL),
+ fBuff(0) // 0 is the error value returned by MapViewOfFile()
+ {
+ if ((fp = fopen(fileName, "r")) == NULL)
+ return;
+ char c = getc(fp);
+ fSize = 0;
+ while (c != EOF) {
+ fSize++;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ fSize++;
+ rewind(fp);
+ fBuff = (char*)malloc(sizeof(char) * fSize);
+ int count = 0;
+ c = getc(fp);
+ while (c != EOF) {
+ fBuff[count++] = c;
+ c = getc(fp);
+ }
+ fBuff[count++] = c;
+ }
+
+ char* getData() { return fBuff; }
+ int getSize() { return fSize; }
+
+ ~TMMap() {
+ if (fp != NULL)
+ fclose(fp);
+ }
+
+private:
+ int fSize; // size of file to map in
+ FILE *fp;
+ char* fBuff; // the actual data;
+};
+
+#endif // _MMAP_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp b/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp
new file mode 100644
index 0000000000..a50310154d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/MapLongVariableNames.cpp
@@ -0,0 +1,122 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/MapLongVariableNames.h"
+
+namespace {
+
+TString mapLongName(int id, const TString& name, bool isGlobal)
+{
+ ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
+ TStringStream stream;
+ stream << "webgl_";
+ if (isGlobal)
+ stream << "g";
+ stream << id;
+ if (name[0] != '_')
+ stream << "_";
+ stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
+ return stream.str();
+}
+
+LongNameMap* gLongNameMapInstance = NULL;
+
+} // anonymous namespace
+
+LongNameMap::LongNameMap()
+ : refCount(0)
+{
+}
+
+LongNameMap::~LongNameMap()
+{
+}
+
+// static
+LongNameMap* LongNameMap::GetInstance()
+{
+ if (gLongNameMapInstance == NULL)
+ gLongNameMapInstance = new LongNameMap;
+ gLongNameMapInstance->refCount++;
+ return gLongNameMapInstance;
+}
+
+void LongNameMap::Release()
+{
+ ASSERT(gLongNameMapInstance == this);
+ ASSERT(refCount > 0);
+ refCount--;
+ if (refCount == 0) {
+ delete gLongNameMapInstance;
+ gLongNameMapInstance = NULL;
+ }
+}
+
+const char* LongNameMap::Find(const char* originalName) const
+{
+ std::map<std::string, std::string>::const_iterator it = mLongNameMap.find(
+ originalName);
+ if (it != mLongNameMap.end())
+ return (*it).second.c_str();
+ return NULL;
+}
+
+void LongNameMap::Insert(const char* originalName, const char* mappedName)
+{
+ mLongNameMap.insert(std::map<std::string, std::string>::value_type(
+ originalName, mappedName));
+}
+
+int LongNameMap::Size() const
+{
+ return mLongNameMap.size();
+}
+
+MapLongVariableNames::MapLongVariableNames(LongNameMap* globalMap)
+{
+ ASSERT(globalMap);
+ mGlobalMap = globalMap;
+}
+
+void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol)
+{
+ ASSERT(symbol != NULL);
+ if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) {
+ switch (symbol->getQualifier()) {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqInvariantVaryingIn:
+ case EvqInvariantVaryingOut:
+ case EvqUniform:
+ symbol->setSymbol(
+ mapGlobalLongName(symbol->getSymbol()));
+ break;
+ default:
+ symbol->setSymbol(
+ mapLongName(symbol->getId(), symbol->getSymbol(), false));
+ break;
+ };
+ }
+}
+
+bool MapLongVariableNames::visitLoop(Visit, TIntermLoop* node)
+{
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ return true;
+}
+
+TString MapLongVariableNames::mapGlobalLongName(const TString& name)
+{
+ ASSERT(mGlobalMap);
+ const char* mappedName = mGlobalMap->Find(name.c_str());
+ if (mappedName != NULL)
+ return mappedName;
+ int id = mGlobalMap->Size();
+ TString rt = mapLongName(id, name, true);
+ mGlobalMap->Insert(name.c_str(), rt.c_str());
+ return rt;
+}
diff --git a/src/3rdparty/angle/src/compiler/MapLongVariableNames.h b/src/3rdparty/angle/src/compiler/MapLongVariableNames.h
new file mode 100644
index 0000000000..fb2c7e81cb
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/MapLongVariableNames.h
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/VariableInfo.h"
+
+// This size does not include '\0' in the end.
+#define MAX_SHORTENED_IDENTIFIER_SIZE 32
+
+// This is a ref-counted singleton. GetInstance() returns a pointer to the
+// singleton, and after use, call Release(). GetInstance() and Release() should
+// be paired.
+class LongNameMap {
+public:
+ static LongNameMap* GetInstance();
+ void Release();
+
+ // Return the mapped name if <originalName, mappedName> is in the map;
+ // otherwise, return NULL.
+ const char* Find(const char* originalName) const;
+
+ // Insert a pair into the map.
+ void Insert(const char* originalName, const char* mappedName);
+
+ // Return the number of entries in the map.
+ int Size() const;
+
+private:
+ LongNameMap();
+ ~LongNameMap();
+
+ size_t refCount;
+ std::map<std::string, std::string> mLongNameMap;
+};
+
+// Traverses intermediate tree to map attributes and uniforms names that are
+// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE.
+class MapLongVariableNames : public TIntermTraverser {
+public:
+ MapLongVariableNames(LongNameMap* globalMap);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+
+private:
+ TString mapGlobalLongName(const TString& name);
+
+ LongNameMap* mGlobalMap;
+};
+
+#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_
diff --git a/src/3rdparty/angle/src/compiler/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/OutputESSL.cpp
new file mode 100644
index 0000000000..64ee92d44e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputESSL.cpp
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputESSL.h"
+
+TOutputESSL::TOutputESSL(TInfoSinkBase& objSink)
+ : TOutputGLSLBase(objSink)
+{
+}
+
+bool TOutputESSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase& out = objSink();
+ out << getPrecisionString(precision);
+ return true;
+}
diff --git a/src/3rdparty/angle/src/compiler/OutputESSL.h b/src/3rdparty/angle/src/compiler/OutputESSL.h
new file mode 100644
index 0000000000..4fa73c8047
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputESSL.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputESSL : public TOutputGLSLBase
+{
+public:
+ TOutputESSL(TInfoSinkBase& objSink);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision precision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
diff --git a/src/3rdparty/angle/src/compiler/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/OutputGLSL.cpp
new file mode 100644
index 0000000000..dd31b4b58b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputGLSL.cpp
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSL.h"
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
+ : TOutputGLSLBase(objSink)
+{
+}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
diff --git a/src/3rdparty/angle/src/compiler/OutputGLSL.h b/src/3rdparty/angle/src/compiler/OutputGLSL.h
new file mode 100644
index 0000000000..0fe2356eb7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputGLSL.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+public:
+ TOutputGLSL(TInfoSinkBase& objSink);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp
new file mode 100644
index 0000000000..552fa5066d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputGLSLBase.cpp
@@ -0,0 +1,720 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSLBase.h"
+#include "compiler/debug.h"
+
+namespace
+{
+TString getTypeName(const TType& type)
+{
+ TInfoSinkBase out;
+ if (type.isMatrix())
+ {
+ out << "mat";
+ out << type.getNominalSize();
+ }
+ else if (type.isVector())
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat: out << "vec"; break;
+ case EbtInt: out << "ivec"; break;
+ case EbtBool: out << "bvec"; break;
+ default: UNREACHABLE(); break;
+ }
+ out << type.getNominalSize();
+ }
+ else
+ {
+ if (type.getBasicType() == EbtStruct)
+ out << type.getTypeName();
+ else
+ out << type.getBasicString();
+ }
+ return TString(out.c_str());
+}
+
+TString arrayBrackets(const TType& type)
+{
+ ASSERT(type.isArray());
+ TInfoSinkBase out;
+ out << "[" << type.getArraySize() << "]";
+ return TString(out.c_str());
+}
+
+bool isSingleStatement(TIntermNode* node) {
+ if (const TIntermAggregate* aggregate = node->getAsAggregate())
+ {
+ return (aggregate->getOp() != EOpFunction) &&
+ (aggregate->getOp() != EOpSequence);
+ }
+ else if (const TIntermSelection* selection = node->getAsSelectionNode())
+ {
+ // Ternary operators are usually part of an assignment operator.
+ // This handles those rare cases in which they are all by themselves.
+ return selection->usesTernaryOperator();
+ }
+ else if (node->getAsLoopNode())
+ {
+ return false;
+ }
+ return true;
+}
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
+ : TIntermTraverser(true, true, true),
+ mObjSink(objSink),
+ mDeclaringVariables(false)
+{
+}
+
+void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
+{
+ TInfoSinkBase& out = objSink();
+ if (visit == PreVisit && preStr)
+ {
+ out << preStr;
+ }
+ else if (visit == InVisit && inStr)
+ {
+ out << inStr;
+ }
+ else if (visit == PostVisit && postStr)
+ {
+ out << postStr;
+ }
+}
+
+void TOutputGLSLBase::writeVariableType(const TType& type)
+{
+ TInfoSinkBase& out = objSink();
+ TQualifier qualifier = type.getQualifier();
+ // TODO(alokp): Validate qualifier for variable declarations.
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
+ out << type.getQualifierString() << " ";
+ // Declare the struct if we have not done so already.
+ if ((type.getBasicType() == EbtStruct) &&
+ (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
+ {
+ out << "struct " << type.getTypeName() << "{\n";
+ const TTypeList* structure = type.getStruct();
+ ASSERT(structure != NULL);
+ for (size_t i = 0; i < structure->size(); ++i)
+ {
+ const TType* fieldType = (*structure)[i].type;
+ ASSERT(fieldType != NULL);
+ if (writeVariablePrecision(fieldType->getPrecision()))
+ out << " ";
+ out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
+ if (fieldType->isArray())
+ out << arrayBrackets(*fieldType);
+ out << ";\n";
+ }
+ out << "}";
+ mDeclaredStructs.insert(type.getTypeName());
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
+{
+ TInfoSinkBase& out = objSink();
+ for (TIntermSequence::const_iterator iter = args.begin();
+ iter != args.end(); ++iter)
+ {
+ const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
+ ASSERT(arg != NULL);
+
+ const TType& type = arg->getType();
+ writeVariableType(type);
+
+ const TString& name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << name;
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ // Put a comma if this is not the last argument.
+ if (iter != args.end() - 1)
+ out << ", ";
+ }
+}
+
+const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
+ const ConstantUnion* pConstUnion)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << type.getTypeName() << "(";
+ const TTypeList* structure = type.getStruct();
+ ASSERT(structure != NULL);
+ for (size_t i = 0; i < structure->size(); ++i)
+ {
+ const TType* fieldType = (*structure)[i].type;
+ ASSERT(fieldType != NULL);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != structure->size() - 1) out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ int size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType) out << getTypeName(type) << "(";
+ for (int i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat: out << pConstUnion->getFConst(); break;
+ case EbtInt: out << pConstUnion->getIConst(); break;
+ case EbtBool: out << pConstUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+ if (i != size - 1) out << ", ";
+ }
+ if (writeType) out << ")";
+ }
+ return pConstUnion;
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+ if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
+ out << mLoopUnroll.GetLoopIndexValue(node);
+ else
+ out << node->getSymbol();
+
+ if (mDeclaringVariables && node->getType().isArray())
+ out << arrayBrackets(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
+ case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
+ case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ writeTriplet(visit, NULL, "[", "]");
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ out << ".";
+ // TODO(alokp): ASSERT
+ out << node->getType().getFieldName();
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence& sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+ {
+ TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const ConstantUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE(); break;
+ }
+ }
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
+ case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
+ case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
+ case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
+ case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString preString;
+ TString postString = ")";
+
+ switch (node->getOp())
+ {
+ case EOpNegative: preString = "(-"; break;
+ case EOpVectorLogicalNot: preString = "not("; break;
+ case EOpLogicalNot: preString = "(!"; break;
+
+ case EOpPostIncrement: preString = "("; postString = "++)"; break;
+ case EOpPostDecrement: preString = "("; postString = "--)"; break;
+ case EOpPreIncrement: preString = "(++"; break;
+ case EOpPreDecrement: preString = "(--"; break;
+
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "bool("; break;
+ case 2: preString = "bvec2("; break;
+ case 3: preString = "bvec3("; break;
+ case 4: preString = "bvec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "float("; break;
+ case 2: preString = "vec2("; break;
+ case 3: preString = "vec3("; break;
+ case 4: preString = "vec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "int("; break;
+ case 2: preString = "ivec2("; break;
+ case 3: preString = "ivec3("; break;
+ case 4: preString = "ivec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+
+ case EOpRadians: preString = "radians("; break;
+ case EOpDegrees: preString = "degrees("; break;
+ case EOpSin: preString = "sin("; break;
+ case EOpCos: preString = "cos("; break;
+ case EOpTan: preString = "tan("; break;
+ case EOpAsin: preString = "asin("; break;
+ case EOpAcos: preString = "acos("; break;
+ case EOpAtan: preString = "atan("; break;
+
+ case EOpExp: preString = "exp("; break;
+ case EOpLog: preString = "log("; break;
+ case EOpExp2: preString = "exp2("; break;
+ case EOpLog2: preString = "log2("; break;
+ case EOpSqrt: preString = "sqrt("; break;
+ case EOpInverseSqrt: preString = "inversesqrt("; break;
+
+ case EOpAbs: preString = "abs("; break;
+ case EOpSign: preString = "sign("; break;
+ case EOpFloor: preString = "floor("; break;
+ case EOpCeil: preString = "ceil("; break;
+ case EOpFract: preString = "fract("; break;
+
+ case EOpLength: preString = "length("; break;
+ case EOpNormalize: preString = "normalize("; break;
+
+ case EOpDFdx: preString = "dFdx("; break;
+ case EOpDFdy: preString = "dFdy("; break;
+ case EOpFwidth: preString = "fwidth("; break;
+
+ case EOpAny: preString = "any("; break;
+ case EOpAll: preString = "all("; break;
+
+ default: UNREACHABLE(); break;
+ }
+
+ if (visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+
+ return true;
+}
+
+bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (node->usesTernaryOperator())
+ {
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueBlock()->traverse(this);
+ out << ") : (";
+ node->getFalseBlock()->traverse(this);
+ out << "))";
+ }
+ else
+ {
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ incrementDepth();
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ TString preString;
+ bool delayedWrite = false;
+ switch (node->getOp())
+ {
+ case EOpSequence: {
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "{\n";
+
+ incrementDepth();
+ const TIntermSequence& sequence = node->getSequence();
+ for (TIntermSequence::const_iterator iter = sequence.begin();
+ iter != sequence.end(); ++iter)
+ {
+ TIntermNode* node = *iter;
+ ASSERT(node != NULL);
+ node->traverse(this);
+
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ decrementDepth();
+
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "}\n";
+ visitChildren = false;
+ break;
+ }
+ case EOpPrototype: {
+ // Function declaration.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << node->getName();
+
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+
+ visitChildren = false;
+ break;
+ }
+ case EOpFunction: {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << TFunction::unmangleName(node->getName());
+
+ incrementDepth();
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence& sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate* params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate* body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ visitCodeBlock(body);
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpFunctionCall:
+ // Function call.
+ if (visit == PreVisit)
+ {
+ TString functionName = TFunction::unmangleName(node->getName());
+ out << functionName << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+ case EOpParameters: {
+ // Function parameters.
+ ASSERT(visit == PreVisit);
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+ visitChildren = false;
+ break;
+ }
+ case EOpDeclaration: {
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence& sequence = node->getSequence();
+ const TIntermTyped* variable = sequence.front()->getAsTyped();
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ }
+ case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
+ case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
+ case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
+ case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
+ case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
+ case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
+ case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
+ case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
+ case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
+ case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
+ case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
+ case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
+ case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
+ case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
+ case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
+ case EOpConstructStruct:
+ if (visit == PreVisit)
+ {
+ const TType& type = node->getType();
+ ASSERT(type.getBasicType() == EbtStruct);
+ out << type.getTypeName() << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+
+ case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
+ case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
+ case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
+ case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
+ case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
+ case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
+ case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
+
+ case EOpMod: preString = "mod("; delayedWrite = true; break;
+ case EOpPow: preString = "pow("; delayedWrite = true; break;
+ case EOpAtan: preString = "atan("; delayedWrite = true; break;
+ case EOpMin: preString = "min("; delayedWrite = true; break;
+ case EOpMax: preString = "max("; delayedWrite = true; break;
+ case EOpClamp: preString = "clamp("; delayedWrite = true; break;
+ case EOpMix: preString = "mix("; delayedWrite = true; break;
+ case EOpStep: preString = "step("; delayedWrite = true; break;
+ case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
+
+ case EOpDistance: preString = "distance("; delayedWrite = true; break;
+ case EOpDot: preString = "dot("; delayedWrite = true; break;
+ case EOpCross: preString = "cross("; delayedWrite = true; break;
+ case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
+ case EOpReflect: preString = "reflect("; delayedWrite = true; break;
+ case EOpRefract: preString = "refract("; delayedWrite = true; break;
+ case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
+
+ default: UNREACHABLE(); break;
+ }
+ if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ if (delayedWrite)
+ writeTriplet(visit, preString.c_str(), ", ", ")");
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ incrementDepth();
+ // Loop header.
+ TLoopType loopType = node->getType();
+ if (loopType == ELoopFor) // for loop
+ {
+ if (!node->getUnrollFlag()) {
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
+ }
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ")\n";
+ }
+ else // do-while loop
+ {
+ ASSERT(loopType == ELoopDoWhile);
+ out << "do\n";
+ }
+
+ // Loop body.
+ if (node->getUnrollFlag())
+ {
+ TLoopIndexInfo indexInfo;
+ mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
+ mLoopUnroll.Push(indexInfo);
+ while (mLoopUnroll.SatisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnroll.Step();
+ }
+ mLoopUnroll.Pop();
+ }
+ else
+ {
+ visitCodeBlock(node->getBody());
+ }
+
+ // Loop footer.
+ if (loopType == ELoopDoWhile) // do-while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+ decrementDepth();
+
+ // No need to visit children. They have been already processed in
+ // this function.
+ return false;
+}
+
+bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
+{
+ switch (node->getFlowOp())
+ {
+ case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
+ case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
+ case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
+ case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
+ TInfoSinkBase &out = objSink();
+ if (node != NULL)
+ {
+ node->traverse(this);
+ // Single statements not part of a sequence need to be terminated
+ // with semi-colon.
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ else
+ {
+ out << "{\n}\n"; // Empty code block.
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/OutputGLSLBase.h
new file mode 100644
index 0000000000..efd0b5fc2d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputGLSLBase.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+
+#include <set>
+
+#include "compiler/ForLoopUnroll.h"
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+public:
+ TOutputGLSLBase(TInfoSinkBase& objSink);
+
+protected:
+ TInfoSinkBase& objSink() { return mObjSink; }
+ void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
+ void writeVariableType(const TType& type);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TIntermSequence& args);
+ const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
+
+ virtual void visitSymbol(TIntermSymbol* node);
+ virtual void visitConstantUnion(TIntermConstantUnion* node);
+ virtual bool visitBinary(Visit visit, TIntermBinary* node);
+ virtual bool visitUnary(Visit visit, TIntermUnary* node);
+ virtual bool visitSelection(Visit visit, TIntermSelection* node);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
+ virtual bool visitLoop(Visit visit, TIntermLoop* node);
+ virtual bool visitBranch(Visit visit, TIntermBranch* node);
+
+ void visitCodeBlock(TIntermNode* node);
+
+private:
+ TInfoSinkBase& mObjSink;
+ bool mDeclaringVariables;
+
+ // Structs are declared as the tree is traversed. This set contains all
+ // the structs already declared. It is maintained so that a struct is
+ // declared only once.
+ typedef std::set<TString> DeclaredStructs;
+ DeclaredStructs mDeclaredStructs;
+
+ ForLoopUnroll mLoopUnroll;
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/src/3rdparty/angle/src/compiler/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/OutputHLSL.cpp
new file mode 100644
index 0000000000..a430695744
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputHLSL.cpp
@@ -0,0 +1,2664 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputHLSL.h"
+
+#include "common/angleutils.h"
+#include "compiler/debug.h"
+#include "compiler/InfoSink.h"
+#include "compiler/UnfoldShortCircuit.h"
+#include "compiler/SearchSymbol.h"
+#include "compiler/DetectDiscontinuity.h"
+
+#include <stdio.h>
+#include <algorithm>
+
+namespace sh
+{
+// Integer to TString conversion
+TString str(int i)
+{
+ char buffer[20];
+ snprintf(buffer, sizeof(buffer), "%d", i);
+ return buffer;
+}
+
+OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
+{
+ mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
+ mInsideFunction = false;
+
+ mUsesTexture2D = false;
+ mUsesTexture2D_bias = false;
+ mUsesTexture2DProj = false;
+ mUsesTexture2DProj_bias = false;
+ mUsesTexture2DProjLod = false;
+ mUsesTexture2DLod = false;
+ mUsesTextureCube = false;
+ mUsesTextureCube_bias = false;
+ mUsesTextureCubeLod = false;
+ mUsesTexture2DLod0 = false;
+ mUsesTexture2DLod0_bias = false;
+ mUsesTexture2DProjLod0 = false;
+ mUsesTexture2DProjLod0_bias = false;
+ mUsesTextureCubeLod0 = false;
+ mUsesTextureCubeLod0_bias = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesXor = false;
+ mUsesMod1 = false;
+ mUsesMod2v = false;
+ mUsesMod2f = false;
+ mUsesMod3v = false;
+ mUsesMod3f = false;
+ mUsesMod4v = false;
+ mUsesMod4f = false;
+ mUsesFaceforward1 = false;
+ mUsesFaceforward2 = false;
+ mUsesFaceforward3 = false;
+ mUsesFaceforward4 = false;
+ mUsesEqualMat2 = false;
+ mUsesEqualMat3 = false;
+ mUsesEqualMat4 = false;
+ mUsesEqualVec2 = false;
+ mUsesEqualVec3 = false;
+ mUsesEqualVec4 = false;
+ mUsesEqualIVec2 = false;
+ mUsesEqualIVec3 = false;
+ mUsesEqualIVec4 = false;
+ mUsesEqualBVec2 = false;
+ mUsesEqualBVec3 = false;
+ mUsesEqualBVec4 = false;
+ mUsesAtan2_1 = false;
+ mUsesAtan2_2 = false;
+ mUsesAtan2_3 = false;
+ mUsesAtan2_4 = false;
+
+ mScopeDepth = 0;
+
+ mUniqueIndex = 0;
+
+ mContainsLoopDiscontinuity = false;
+ mOutputLod0Function = false;
+ mInsideDiscontinuousLoop = false;
+
+ mExcessiveLoopIndex = NULL;
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ delete mUnfoldShortCircuit;
+}
+
+void OutputHLSL::output()
+{
+ mContainsLoopDiscontinuity = containsLoopDiscontinuity(mContext.treeRoot);
+
+ mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
+ header();
+
+ mContext.infoSink().obj << mHeader.c_str();
+ mContext.infoSink().obj << mBody.c_str();
+}
+
+TInfoSinkBase &OutputHLSL::getBodyStream()
+{
+ return mBody;
+}
+
+int OutputHLSL::vectorSize(const TType &type) const
+{
+ int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
+ int arraySize = type.isArray() ? type.getArraySize() : 1;
+
+ return elementSize * arraySize;
+}
+
+void OutputHLSL::header()
+{
+ ShShaderType shaderType = mContext.shaderType;
+ TInfoSinkBase &out = mHeader;
+
+ for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
+ {
+ out << *structDeclaration;
+ }
+
+ for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
+ {
+ out << *constructor;
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER)
+ {
+ TString uniforms;
+ TString varyings;
+
+ TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
+ int semanticIndex = 0;
+
+ for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
+ {
+ const TSymbol *symbol = (*namedSymbol).second;
+ const TString &name = symbol->getName();
+
+ if (symbol->isVariable())
+ {
+ const TVariable *variable = static_cast<const TVariable*>(symbol);
+ const TType &type = variable->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
+ {
+ uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
+ {
+ if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
+ {
+ // Program linking depends on this exact format
+ varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+
+ semanticIndex += type.isArray() ? type.getArraySize() : 1;
+ }
+ }
+ else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
+ {
+ // Globals are declared and intialized as an aggregate node
+ }
+ else if (qualifier == EvqConst)
+ {
+ // Constants are repeated as literals where used
+ }
+ else UNREACHABLE();
+ }
+ }
+
+ out << "// Varyings\n";
+ out << varyings;
+ out << "\n"
+ "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
+
+ if (mUsesFragCoord)
+ {
+ out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "static bool gl_FrontFacing = false;\n";
+ }
+
+ out << "\n";
+
+ if (mUsesFragCoord)
+ {
+ out << "uniform float4 dx_Coord;\n"
+ "uniform float2 dx_Depth;\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "uniform bool dx_PointsOrLines;\n"
+ "uniform bool dx_FrontCCW;\n";
+ }
+
+ out << "\n";
+ out << uniforms;
+ out << "\n";
+
+ if (mUsesTexture2D)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2D(s, t);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2D_bias)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dproj(s, t);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj_bias)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBE(s, t);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube_bias)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
+ "{\n"
+ " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
+ "}\n"
+ "\n";
+ }
+
+ // These *Lod0 intrinsics are not available in GL fragment shaders.
+ // They are used to sample using discontinuous texture coordinates.
+ if (mUsesTexture2DLod0)
+ {
+ out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DLod0_bias)
+ {
+ out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProjLod0)
+ {
+ out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProjLod0_bias)
+ {
+ out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCubeLod0)
+ {
+ out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCubeLod0_bias)
+ {
+ out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+ }
+ else // Vertex shader
+ {
+ TString uniforms;
+ TString attributes;
+ TString varyings;
+
+ TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
+
+ for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
+ {
+ const TSymbol *symbol = (*namedSymbol).second;
+ const TString &name = symbol->getName();
+
+ if (symbol->isVariable())
+ {
+ const TVariable *variable = static_cast<const TVariable*>(symbol);
+ const TType &type = variable->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
+ {
+ uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqAttribute)
+ {
+ if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
+ {
+ attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
+ {
+ if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
+ {
+ // Program linking depends on this exact format
+ varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
+ {
+ // Globals are declared and intialized as an aggregate node
+ }
+ else if (qualifier == EvqConst)
+ {
+ // Constants are repeated as literals where used
+ }
+ else UNREACHABLE();
+ }
+ }
+
+ out << "// Attributes\n";
+ out << attributes;
+ out << "\n"
+ "static float4 gl_Position = float4(0, 0, 0, 0);\n";
+
+ if (mUsesPointSize)
+ {
+ out << "static float gl_PointSize = float(1);\n";
+ }
+
+ out << "\n"
+ "// Varyings\n";
+ out << varyings;
+ out << "\n"
+ "uniform float2 dx_HalfPixelSize;\n"
+ "\n";
+ out << uniforms;
+ out << "\n";
+
+ if (mUsesTexture2D)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DLod)
+ {
+ out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProjLod)
+ {
+ out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCubeLod)
+ {
+ out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n"
+ "}\n"
+ "\n";
+ }
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "#define GL_USES_FRAG_COORD\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "#define GL_USES_POINT_COORD\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "#define GL_USES_FRONT_FACING\n";
+ }
+
+ if (mUsesPointSize)
+ {
+ out << "#define GL_USES_POINT_SIZE\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n"
+ "uniform float3 dx_DepthRange;"
+ "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ if (mUsesXor)
+ {
+ out << "bool xor(bool p, bool q)\n"
+ "{\n"
+ " return (p || q) && !(p && q);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod1)
+ {
+ out << "float mod(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2v)
+ {
+ out << "float2 mod(float2 x, float2 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2f)
+ {
+ out << "float2 mod(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3v)
+ {
+ out << "float3 mod(float3 x, float3 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3f)
+ {
+ out << "float3 mod(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4v)
+ {
+ out << "float4 mod(float4 x, float4 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4f)
+ {
+ out << "float4 mod(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward1)
+ {
+ out << "float faceforward(float N, float I, float Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward2)
+ {
+ out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward3)
+ {
+ out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward4)
+ {
+ out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesEqualMat2)
+ {
+ out << "bool equal(float2x2 m, float2x2 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualMat3)
+ {
+ out << "bool equal(float3x3 m, float3x3 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
+ " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualMat4)
+ {
+ out << "bool equal(float4x4 m, float4x4 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] && m[0][3] == n[0][3] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] && m[1][3] == n[1][3] &&\n"
+ " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2] && m[2][3] == n[2][3] &&\n"
+ " m[3][0] == n[3][0] && m[3][1] == n[3][1] && m[3][2] == n[3][2] && m[3][3] == n[3][3];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec2)
+ {
+ out << "bool equal(float2 v, float2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec3)
+ {
+ out << "bool equal(float3 v, float3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec4)
+ {
+ out << "bool equal(float4 v, float4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec2)
+ {
+ out << "bool equal(int2 v, int2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec3)
+ {
+ out << "bool equal(int3 v, int3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec4)
+ {
+ out << "bool equal(int4 v, int4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec2)
+ {
+ out << "bool equal(bool2 v, bool2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec3)
+ {
+ out << "bool equal(bool3 v, bool3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec4)
+ {
+ out << "bool equal(bool4 v, bool4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_1)
+ {
+ out << "float atanyx(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
+ " return atan2(y, x);\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_2)
+ {
+ out << "float2 atanyx(float2 y, float2 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_3)
+ {
+ out << "float3 atanyx(float3 y, float3 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_4)
+ {
+ out << "float4 atanyx(float4 y, float4 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
+ " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
+ "}\n";
+ }
+}
+
+void OutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ TString name = node->getSymbol();
+
+ if (name == "gl_FragColor")
+ {
+ out << "gl_Color[0]";
+ }
+ else if (name == "gl_FragData")
+ {
+ out << "gl_Color";
+ }
+ else if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else if (name == "gl_FragCoord")
+ {
+ mUsesFragCoord = true;
+ out << name;
+ }
+ else if (name == "gl_PointCoord")
+ {
+ mUsesPointCoord = true;
+ out << name;
+ }
+ else if (name == "gl_FrontFacing")
+ {
+ mUsesFrontFacing = true;
+ out << name;
+ }
+ else if (name == "gl_PointSize")
+ {
+ mUsesPointSize = true;
+ out << name;
+ }
+ else
+ {
+ TQualifier qualifier = node->getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ mReferencedUniforms.insert(name.c_str());
+ out << decorateUniform(name, node->getType());
+ }
+ else if (qualifier == EvqAttribute)
+ {
+ mReferencedAttributes.insert(name.c_str());
+ out << decorate(name);
+ }
+ else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
+ {
+ mReferencedVaryings.insert(name.c_str());
+ out << decorate(name);
+ }
+ else
+ {
+ out << decorate(name);
+ }
+ }
+}
+
+bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ // GLSL allows to write things like "float x = x;" where a new variable x is defined
+ // and the value of an existing variable x is assigned. HLSL uses C semantics (the
+ // new variable is created before the assignment is evaluated), so we need to convert
+ // this to "float t = x, x = t;".
+
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ TIntermTyped *expression = node->getRight();
+
+ sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
+ expression->traverse(&searchSymbol);
+ bool sameSymbol = searchSymbol.foundMatch();
+
+ if (sameSymbol)
+ {
+ // Type already printed
+ out << "t" + str(mUniqueIndex) + " = ";
+ expression->traverse(this);
+ out << ", ";
+ symbolNode->traverse(this);
+ out << " = t" + str(mUniqueIndex);
+
+ mUniqueIndex++;
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ }
+ break;
+ case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
+ case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", transpose(";
+ }
+ else
+ {
+ out << ")))";
+ }
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", ";
+ }
+ else
+ {
+ out << "))";
+ }
+ break;
+ case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
+ case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ out << "." + decorateField(node->getType().getFieldName(), node->getLeft()->getType());
+
+ return false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+
+ TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
+
+ if (swizzle)
+ {
+ TIntermSequence &sequence = swizzle->getSequence();
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+
+ if (element)
+ {
+ int i = element->getUnionArrayPointer()[0].getIConst();
+
+ switch (i)
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ return false; // Fully processed
+ }
+ break;
+ case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
+ case EOpEqual:
+ case EOpNotEqual:
+ if (node->getLeft()->isScalar())
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "(", " != ", ")");
+ }
+ }
+ else if (node->getLeft()->getBasicType() == EbtStruct)
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ out << "(";
+ }
+ else
+ {
+ out << "!(";
+ }
+
+ const TTypeList *fields = node->getLeft()->getType().getStruct();
+
+ for (size_t i = 0; i < fields->size(); i++)
+ {
+ const TType *fieldType = (*fields)[i].type;
+
+ node->getLeft()->traverse(this);
+ out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType()) + " == ";
+ node->getRight()->traverse(this);
+ out << "." + decorateField(fieldType->getFieldName(), node->getLeft()->getType());
+
+ if (i < fields->size() - 1)
+ {
+ out << " && ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ else
+ {
+ if (node->getLeft()->isMatrix())
+ {
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualMat2 = true; break;
+ case 3: mUsesEqualMat3 = true; break;
+ case 4: mUsesEqualMat4 = true; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if (node->getLeft()->isVector())
+ {
+ switch (node->getLeft()->getBasicType())
+ {
+ case EbtFloat:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualVec2 = true; break;
+ case 3: mUsesEqualVec3 = true; break;
+ case 4: mUsesEqualVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EbtInt:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualIVec2 = true; break;
+ case 3: mUsesEqualIVec3 = true; break;
+ case 4: mUsesEqualIVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EbtBool:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualBVec2 = true; break;
+ case 3: mUsesEqualBVec3 = true; break;
+ case 4: mUsesEqualBVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "equal(", ", ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "!equal(", ", ", ")");
+ }
+ }
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
+ case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
+ case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
+ case EOpLogicalOr:
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ case EOpLogicalXor:
+ mUsesXor = true;
+ outputTriplet(visit, "xor(", ", ", ")");
+ break;
+ case EOpLogicalAnd:
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
+ case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
+ case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
+ case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
+ case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "bool(", "", ")"); break;
+ case 2: outputTriplet(visit, "bool2(", "", ")"); break;
+ case 3: outputTriplet(visit, "bool3(", "", ")"); break;
+ case 4: outputTriplet(visit, "bool4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "float(", "", ")"); break;
+ case 2: outputTriplet(visit, "float2(", "", ")"); break;
+ case 3: outputTriplet(visit, "float3(", "", ")"); break;
+ case 4: outputTriplet(visit, "float4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "int(", "", ")"); break;
+ case 2: outputTriplet(visit, "int2(", "", ")"); break;
+ case 3: outputTriplet(visit, "int3(", "", ")"); break;
+ case 4: outputTriplet(visit, "int4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
+ case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
+ case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
+ case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
+ case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
+ case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
+ case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
+ case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
+ case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
+ case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
+ case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
+ case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
+ case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
+ case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
+ case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
+ case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
+ case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
+ case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
+ case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
+ case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
+ case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
+ case EOpDFdx:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddx(", "", ")");
+ }
+ break;
+ case EOpDFdy:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddy(", "", ")");
+ }
+ break;
+ case EOpFwidth:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "fwidth(", "", ")");
+ }
+ break;
+ case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
+ case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ {
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ mScopeDepth++;
+
+ if (mScopeBracket.size() < mScopeDepth)
+ {
+ mScopeBracket.push_back(0); // New scope level
+ }
+ else
+ {
+ mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
+ }
+ }
+
+ for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
+ {
+ outputLineDirective((*sit)->getLine());
+
+ traverseStatements(*sit);
+
+ out << ";\n";
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getEndLine());
+ out << "}\n";
+
+ mScopeDepth--;
+ }
+
+ return false;
+ }
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ TIntermSequence &sequence = node->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+ bool visit = true;
+
+ if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+ {
+ if (variable->getType().getStruct())
+ {
+ addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
+ }
+
+ if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
+ {
+ if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << typeString(variable->getType()) + " ";
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << arrayString(symbol->getType());
+ out << " = " + initializer(variable->getType());
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+
+ if (visit && this->inVisit)
+ {
+ if (*sit != sequence.back())
+ {
+ visit = this->visitAggregate(InVisit, node);
+ }
+ }
+ }
+
+ if (visit && this->postVisit)
+ {
+ this->visitAggregate(PostVisit, node);
+ }
+ }
+ else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
+ {
+ // Already added to constructor map
+ }
+ else UNREACHABLE();
+ }
+
+ return false;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ break;
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
+
+ TIntermSequence &arguments = node->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ");\n";
+
+ // Also prototype the Lod0 variant if needed
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+ }
+ break;
+ case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
+ case EOpFunction:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ out << typeString(node->getType()) << " ";
+
+ if (name == "main")
+ {
+ out << "gl_main(";
+ }
+ else
+ {
+ out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
+ }
+
+ TIntermSequence &sequence = node->getSequence();
+ TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ if (symbol->getType().getStruct())
+ {
+ addConstructor(symbol->getType(), scopedStruct(symbol->getType().getTypeName()), NULL);
+ }
+
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ")\n"
+ "{\n";
+
+ if (sequence.size() > 1)
+ {
+ mInsideFunction = true;
+ sequence[1]->traverse(this);
+ mInsideFunction = false;
+ }
+
+ out << "}\n";
+
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ if (name != "main")
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+ }
+
+ return false;
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ if (visit == PreVisit)
+ {
+ TString name = TFunction::unmangleName(node->getName());
+ bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
+
+ if (node->isUserDefined())
+ {
+ out << decorate(name) << (lod0 ? "Lod0(" : "(");
+ }
+ else
+ {
+ if (name == "texture2D")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2D = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2D_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2D(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DLod0(";
+ }
+ }
+ else if (name == "texture2DProj")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DProj = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProj_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProj(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DProjLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProjLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProjLod0(";
+ }
+ }
+ else if (name == "textureCube")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTextureCube = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCube_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCube(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTextureCubeLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCubeLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCubeLod0(";
+ }
+ }
+ else if (name == "texture2DLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DLod(";
+ }
+ else if (name == "texture2DProjLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProjLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProjLod(";
+ }
+ else if (name == "textureCubeLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCubeLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCubeLod(";
+ }
+ else UNREACHABLE();
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ }
+ break;
+ case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
+ case EOpConstructFloat:
+ addConstructor(node->getType(), "vec1", &node->getSequence());
+ outputTriplet(visit, "vec1(", "", ")");
+ break;
+ case EOpConstructVec2:
+ addConstructor(node->getType(), "vec2", &node->getSequence());
+ outputTriplet(visit, "vec2(", ", ", ")");
+ break;
+ case EOpConstructVec3:
+ addConstructor(node->getType(), "vec3", &node->getSequence());
+ outputTriplet(visit, "vec3(", ", ", ")");
+ break;
+ case EOpConstructVec4:
+ addConstructor(node->getType(), "vec4", &node->getSequence());
+ outputTriplet(visit, "vec4(", ", ", ")");
+ break;
+ case EOpConstructBool:
+ addConstructor(node->getType(), "bvec1", &node->getSequence());
+ outputTriplet(visit, "bvec1(", "", ")");
+ break;
+ case EOpConstructBVec2:
+ addConstructor(node->getType(), "bvec2", &node->getSequence());
+ outputTriplet(visit, "bvec2(", ", ", ")");
+ break;
+ case EOpConstructBVec3:
+ addConstructor(node->getType(), "bvec3", &node->getSequence());
+ outputTriplet(visit, "bvec3(", ", ", ")");
+ break;
+ case EOpConstructBVec4:
+ addConstructor(node->getType(), "bvec4", &node->getSequence());
+ outputTriplet(visit, "bvec4(", ", ", ")");
+ break;
+ case EOpConstructInt:
+ addConstructor(node->getType(), "ivec1", &node->getSequence());
+ outputTriplet(visit, "ivec1(", "", ")");
+ break;
+ case EOpConstructIVec2:
+ addConstructor(node->getType(), "ivec2", &node->getSequence());
+ outputTriplet(visit, "ivec2(", ", ", ")");
+ break;
+ case EOpConstructIVec3:
+ addConstructor(node->getType(), "ivec3", &node->getSequence());
+ outputTriplet(visit, "ivec3(", ", ", ")");
+ break;
+ case EOpConstructIVec4:
+ addConstructor(node->getType(), "ivec4", &node->getSequence());
+ outputTriplet(visit, "ivec4(", ", ", ")");
+ break;
+ case EOpConstructMat2:
+ addConstructor(node->getType(), "mat2", &node->getSequence());
+ outputTriplet(visit, "mat2(", ", ", ")");
+ break;
+ case EOpConstructMat3:
+ addConstructor(node->getType(), "mat3", &node->getSequence());
+ outputTriplet(visit, "mat3(", ", ", ")");
+ break;
+ case EOpConstructMat4:
+ addConstructor(node->getType(), "mat4", &node->getSequence());
+ outputTriplet(visit, "mat4(", ", ", ")");
+ break;
+ case EOpConstructStruct:
+ addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
+ outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
+ case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
+ case EOpMod:
+ {
+ // We need to look at the number of components in both arguments
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
+ + node->getSequence()[1]->getAsTyped()->getNominalSize())
+ {
+ case 11: mUsesMod1 = true; break;
+ case 22: mUsesMod2v = true; break;
+ case 21: mUsesMod2f = true; break;
+ case 33: mUsesMod3v = true; break;
+ case 31: mUsesMod3f = true; break;
+ case 44: mUsesMod4v = true; break;
+ case 41: mUsesMod4f = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "mod(", ", ", ")");
+ }
+ break;
+ case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpAtan:
+ ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
+ {
+ case 1: mUsesAtan2_1 = true; break;
+ case 2: mUsesAtan2_2 = true; break;
+ case 3: mUsesAtan2_3 = true; break;
+ case 4: mUsesAtan2_4 = true; break;
+ default: UNREACHABLE();
+ }
+ outputTriplet(visit, "atanyx(", ", ", ")");
+ break;
+ case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
+ case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
+ case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
+ case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
+ case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpFaceForward:
+ {
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
+ {
+ case 1: mUsesFaceforward1 = true; break;
+ case 2: mUsesFaceforward2 = true; break;
+ case 3: mUsesFaceforward3 = true; break;
+ case 4: mUsesFaceforward4 = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "faceforward(", ", ", ")");
+ }
+ break;
+ case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (node->usesTernaryOperator())
+ {
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ }
+ else // if/else statement
+ {
+ mUnfoldShortCircuit->traverse(node->getCondition());
+
+ out << "if(";
+
+ node->getCondition()->traverse(this);
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ if (node->getTrueBlock())
+ {
+ traverseStatements(node->getTrueBlock());
+ }
+
+ outputLineDirective(node->getLine());
+ out << ";\n}\n";
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ out << "{\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ traverseStatements(node->getFalseBlock());
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ out << ";\n}\n";
+ }
+ }
+
+ return false;
+}
+
+void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
+{
+ bool wasDiscontinuous = mInsideDiscontinuousLoop;
+
+ if (!mInsideDiscontinuousLoop)
+ {
+ mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
+ }
+
+ if (handleExcessiveLoop(node))
+ {
+ return false;
+ }
+
+ TInfoSinkBase &out = mBody;
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ out << "{do\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+ }
+ else
+ {
+ out << "{for(";
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+ }
+
+ if (node->getBody())
+ {
+ traverseStatements(node->getBody());
+ }
+
+ outputLineDirective(node->getLine());
+ out << ";}\n";
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ outputLineDirective(node->getCondition()->getLine());
+ out << "while(\n";
+
+ node->getCondition()->traverse(this);
+
+ out << ");";
+ }
+
+ out << "}\n";
+
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
+ case EOpBreak:
+ if (visit == PreVisit)
+ {
+ if (mExcessiveLoopIndex)
+ {
+ out << "{Break";
+ mExcessiveLoopIndex->traverse(this);
+ out << " = true; break;}\n";
+ }
+ else
+ {
+ out << "break;\n";
+ }
+ }
+ break;
+ case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ {
+ if (node->getExpression())
+ {
+ out << "return ";
+ }
+ else
+ {
+ out << "return;\n";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getExpression())
+ {
+ out << ";\n";
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+void OutputHLSL::traverseStatements(TIntermNode *node)
+{
+ if (isSingleStatement(node))
+ {
+ mUnfoldShortCircuit->traverse(node);
+ }
+
+ node->traverse(this);
+}
+
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ TIntermAggregate *aggregate = node->getAsAggregate();
+
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpSequence)
+ {
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+}
+
+// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
+// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
+bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
+{
+ const int MAX_LOOP_ITERATIONS = 254;
+ TInfoSinkBase &out = mBody;
+
+ // Parse loops of the form:
+ // for(int index = initial; index [comparator] limit; index += increment)
+ TIntermSymbol *index = NULL;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+ if (init)
+ {
+ TIntermSequence &sequence = init->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && variable->getQualifier() == EvqTemporary)
+ {
+ TIntermBinary *assign = variable->getAsBinaryNode();
+
+ if (assign->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+ TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+ if (symbol && constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ index = symbol;
+ initial = constant->getUnionArrayPointer()[0].getIConst();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Parse comparator and limit value
+ if (index != NULL && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ comparator = test->getOp();
+ limit = constant->getUnionArrayPointer()[0].getIConst();
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != NULL && comparator != EOpNull && node->getExpression())
+ {
+ TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+ TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+ if (binaryTerminal)
+ {
+ TOperator op = binaryTerminal->getOp();
+ TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ int value = constant->getUnionArrayPointer()[0].getIConst();
+
+ switch (op)
+ {
+ case EOpAddAssign: increment = value; break;
+ case EOpSubAssign: increment = -value; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+ }
+ else if (unaryTerminal)
+ {
+ TOperator op = unaryTerminal->getOp();
+
+ switch (op)
+ {
+ case EOpPostIncrement: increment = 1; break;
+ case EOpPostDecrement: increment = -1; break;
+ case EOpPreIncrement: increment = 1; break;
+ case EOpPreDecrement: increment = -1; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+
+ if (index != NULL && comparator != EOpNull && increment != 0)
+ {
+ if (comparator == EOpLessThanEqual)
+ {
+ comparator = EOpLessThan;
+ limit += 1;
+ }
+
+ if (comparator == EOpLessThan)
+ {
+ int iterations = (limit - initial) / increment;
+
+ if (iterations <= MAX_LOOP_ITERATIONS)
+ {
+ return false; // Not an excessive loop
+ }
+
+ TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
+ mExcessiveLoopIndex = index;
+
+ out << "{int ";
+ index->traverse(this);
+ out << ";\n"
+ "bool Break";
+ index->traverse(this);
+ out << " = false;\n";
+
+ bool firstLoopFragment = true;
+
+ while (iterations > 0)
+ {
+ int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
+
+ if (!firstLoopFragment)
+ {
+ out << "if(!Break";
+ index->traverse(this);
+ out << ") {\n";
+ }
+
+ if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
+ {
+ mExcessiveLoopIndex = NULL; // Stops setting the Break flag
+ }
+
+ // for(int index = initial; index < clampedLimit; index += increment)
+
+ out << "for(";
+ index->traverse(this);
+ out << " = ";
+ out << initial;
+
+ out << "; ";
+ index->traverse(this);
+ out << " < ";
+ out << clampedLimit;
+
+ out << "; ";
+ index->traverse(this);
+ out << " += ";
+ out << increment;
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine());
+ out << ";}\n";
+
+ if (!firstLoopFragment)
+ {
+ out << "}\n";
+ }
+
+ firstLoopFragment = false;
+
+ initial += MAX_LOOP_ITERATIONS * increment;
+ iterations -= MAX_LOOP_ITERATIONS;
+ }
+
+ out << "}";
+
+ mExcessiveLoopIndex = restoreIndex;
+
+ return true;
+ }
+ else UNIMPLEMENTED();
+ }
+
+ return false; // Not handled as an excessive loop
+}
+
+void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (visit == PreVisit)
+ {
+ out << preString;
+ }
+ else if (visit == InVisit)
+ {
+ out << inString;
+ }
+ else if (visit == PostVisit)
+ {
+ out << postString;
+ }
+}
+
+void OutputHLSL::outputLineDirective(int line)
+{
+ if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
+ {
+ mBody << "\n";
+ mBody << "#line " << line;
+
+ if (mContext.sourcePath)
+ {
+ mBody << " \"" << mContext.sourcePath << "\"";
+ }
+
+ mBody << "\n";
+ }
+}
+
+TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
+{
+ TQualifier qualifier = symbol->getQualifier();
+ const TType &type = symbol->getType();
+ TString name = symbol->getSymbol();
+
+ if (name.empty()) // HLSL demands named arguments, also for prototypes
+ {
+ name = "x" + str(mUniqueIndex++);
+ }
+ else
+ {
+ name = decorate(name);
+ }
+
+ return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
+}
+
+TString OutputHLSL::qualifierString(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqIn: return "in";
+ case EvqOut: return "out";
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ default: UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString OutputHLSL::typeString(const TType &type)
+{
+ if (type.getBasicType() == EbtStruct)
+ {
+ if (type.getTypeName() != "")
+ {
+ return structLookup(type.getTypeName());
+ }
+ else // Nameless structure, define in place
+ {
+ const TTypeList &fields = *type.getStruct();
+
+ TString string = "struct\n"
+ "{\n";
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TType &field = *fields[i].type;
+
+ string += " " + typeString(field) + " " + decorate(field.getFieldName()) + arrayString(field) + ";\n";
+ }
+
+ string += "} ";
+
+ return string;
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2: return "float2x2";
+ case 3: return "float3x3";
+ case 4: return "float4x4";
+ }
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1: return "float";
+ case 2: return "float2";
+ case 3: return "float3";
+ case 4: return "float4";
+ }
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1: return "int";
+ case 2: return "int2";
+ case 3: return "int3";
+ case 4: return "int4";
+ }
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1: return "bool";
+ case 2: return "bool2";
+ case 3: return "bool3";
+ case 4: return "bool4";
+ }
+ case EbtVoid:
+ return "void";
+ case EbtSampler2D:
+ return "sampler2D";
+ case EbtSamplerCube:
+ return "samplerCUBE";
+ case EbtSamplerExternalOES:
+ return "sampler2D";
+ default:
+ break;
+ }
+ }
+
+ UNIMPLEMENTED(); // FIXME
+ return "<unknown type>";
+}
+
+TString OutputHLSL::arrayString(const TType &type)
+{
+ if (!type.isArray())
+ {
+ return "";
+ }
+
+ return "[" + str(type.getArraySize()) + "]";
+}
+
+TString OutputHLSL::initializer(const TType &type)
+{
+ TString string;
+
+ for (int component = 0; component < type.getObjectSize(); component++)
+ {
+ string += "0";
+
+ if (component < type.getObjectSize() - 1)
+ {
+ string += ", ";
+ }
+ }
+
+ return "{" + string + "}";
+}
+
+void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
+{
+ if (name == "")
+ {
+ return; // Nameless structures don't have constructors
+ }
+
+ if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
+ {
+ return; // Already added
+ }
+
+ TType ctorType = type;
+ ctorType.clearArrayness();
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ TString ctorName = type.getStruct() ? decorate(name) : name;
+
+ typedef std::vector<TType> ParameterArray;
+ ParameterArray ctorParameters;
+
+ if (type.getStruct())
+ {
+ mStructNames.insert(decorate(name));
+
+ TString structure;
+ structure += "struct " + decorate(name) + "\n"
+ "{\n";
+
+ const TTypeList &fields = *type.getStruct();
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TType &field = *fields[i].type;
+
+ structure += " " + typeString(field) + " " + decorateField(field.getFieldName(), type) + arrayString(field) + ";\n";
+ }
+
+ structure += "};\n";
+
+ if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
+ {
+ mStructDeclarations.push_back(structure);
+ }
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ ctorParameters.push_back(*fields[i].type);
+ }
+ }
+ else if (parameters)
+ {
+ for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
+ {
+ ctorParameters.push_back((*parameter)->getAsTyped()->getType());
+ }
+ }
+ else UNREACHABLE();
+
+ TString constructor;
+
+ if (ctorType.getStruct())
+ {
+ constructor += ctorName + " " + ctorName + "_ctor(";
+ }
+ else // Built-in type
+ {
+ constructor += typeString(ctorType) + " " + ctorName + "(";
+ }
+
+ for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+ {
+ const TType &type = ctorParameters[parameter];
+
+ constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
+
+ if (parameter < ctorParameters.size() - 1)
+ {
+ constructor += ", ";
+ }
+ }
+
+ constructor += ")\n"
+ "{\n";
+
+ if (ctorType.getStruct())
+ {
+ constructor += " " + ctorName + " structure = {";
+ }
+ else
+ {
+ constructor += " return " + typeString(ctorType) + "(";
+ }
+
+ if (ctorType.isMatrix() && ctorParameters.size() == 1)
+ {
+ int dim = ctorType.getNominalSize();
+ const TType &parameter = ctorParameters[0];
+
+ if (parameter.isScalar())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ constructor += TString((row == col) ? "x0" : "0.0");
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else if (parameter.isMatrix())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
+ {
+ constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
+ }
+ else
+ {
+ constructor += TString((row == col) ? "1.0" : "0.0");
+ }
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+ else
+ {
+ int remainingComponents = ctorType.getObjectSize();
+ int parameterIndex = 0;
+
+ while (remainingComponents > 0)
+ {
+ const TType &parameter = ctorParameters[parameterIndex];
+ bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
+
+ constructor += "x" + str(parameterIndex);
+
+ if (parameter.isScalar())
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (parameter.isVector())
+ {
+ if (remainingComponents == parameter.getObjectSize() || moreParameters)
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (remainingComponents < parameter.getNominalSize())
+ {
+ switch (remainingComponents)
+ {
+ case 1: constructor += ".x"; break;
+ case 2: constructor += ".xy"; break;
+ case 3: constructor += ".xyz"; break;
+ case 4: constructor += ".xyzw"; break;
+ default: UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else UNREACHABLE();
+ }
+ else if (parameter.isMatrix() || parameter.getStruct())
+ {
+ ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
+
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else UNREACHABLE();
+
+ if (moreParameters)
+ {
+ parameterIndex++;
+ }
+
+ if (remainingComponents)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+
+ if (ctorType.getStruct())
+ {
+ constructor += "};\n"
+ " return structure;\n"
+ "}\n";
+ }
+ else
+ {
+ constructor += ");\n"
+ "}\n";
+ }
+
+ mConstructors.insert(constructor);
+}
+
+const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << structLookup(type.getTypeName()) + "_ctor(";
+
+ const TTypeList *structure = type.getStruct();
+
+ for (size_t i = 0; i < structure->size(); i++)
+ {
+ const TType *fieldType = (*structure)[i].type;
+
+ constUnion = writeConstantUnion(*fieldType, constUnion);
+
+ if (i != structure->size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ }
+ else
+ {
+ int size = type.getObjectSize();
+ bool writeType = size > 1;
+
+ if (writeType)
+ {
+ out << typeString(type) << "(";
+ }
+
+ for (int i = 0; i < size; i++, constUnion++)
+ {
+ switch (constUnion->getType())
+ {
+ case EbtFloat: out << constUnion->getFConst(); break;
+ case EbtInt: out << constUnion->getIConst(); break;
+ case EbtBool: out << constUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ if (writeType)
+ {
+ out << ")";
+ }
+ }
+
+ return constUnion;
+}
+
+TString OutputHLSL::scopeString(unsigned int depthLimit)
+{
+ TString string;
+
+ for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
+ {
+ string += "_" + str(i);
+ }
+
+ return string;
+}
+
+TString OutputHLSL::scopedStruct(const TString &typeName)
+{
+ if (typeName == "")
+ {
+ return typeName;
+ }
+
+ return typeName + scopeString(mScopeDepth);
+}
+
+TString OutputHLSL::structLookup(const TString &typeName)
+{
+ for (int depth = mScopeDepth; depth >= 0; depth--)
+ {
+ TString scopedName = decorate(typeName + scopeString(depth));
+
+ for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
+ {
+ if (*structName == scopedName)
+ {
+ return scopedName;
+ }
+ }
+ }
+
+ UNREACHABLE(); // Should have found a matching constructor
+
+ return typeName;
+}
+
+TString OutputHLSL::decorate(const TString &string)
+{
+ if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
+ {
+ return "_" + string;
+ }
+
+ return string;
+}
+
+TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
+{
+ if (type.isArray())
+ {
+ return "ar_" + string; // Allows identifying arrays of size 1
+ }
+ else if (type.getBasicType() == EbtSamplerExternalOES)
+ {
+ return "ex_" + string;
+ }
+
+ return decorate(string);
+}
+
+TString OutputHLSL::decorateField(const TString &string, const TType &structure)
+{
+ if (structure.getTypeName().compare(0, 3, "gl_") != 0)
+ {
+ return decorate(string);
+ }
+
+ return string;
+}
+}
diff --git a/src/3rdparty/angle/src/compiler/OutputHLSL.h b/src/3rdparty/angle/src/compiler/OutputHLSL.h
new file mode 100644
index 0000000000..dc843fb366
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/OutputHLSL.h
@@ -0,0 +1,152 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_OUTPUTHLSL_H_
+#define COMPILER_OUTPUTHLSL_H_
+
+#include <list>
+#include <set>
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class UnfoldShortCircuit;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ explicit OutputHLSL(TParseContext &context);
+ ~OutputHLSL();
+
+ void output();
+
+ TInfoSinkBase &getBodyStream();
+
+ TString typeString(const TType &type);
+ static TString qualifierString(TQualifier qualifier);
+ static TString arrayString(const TType &type);
+ static TString initializer(const TType &type);
+ static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes
+ static TString decorateUniform(const TString &string, const TType &type);
+ static TString decorateField(const TString &string, const TType &structure);
+
+ protected:
+ void header();
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ void traverseStatements(TIntermNode *node);
+ bool isSingleStatement(TIntermNode *node);
+ bool handleExcessiveLoop(TIntermLoop *node);
+ void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString);
+ void outputLineDirective(int line);
+ TString argumentString(const TIntermSymbol *symbol);
+ int vectorSize(const TType &type) const;
+
+ void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
+ const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+
+ TString scopeString(unsigned int depthLimit);
+ TString scopedStruct(const TString &typeName);
+ TString structLookup(const TString &typeName);
+
+ TParseContext &mContext;
+ UnfoldShortCircuit *mUnfoldShortCircuit;
+ bool mInsideFunction;
+
+ // Output streams
+ TInfoSinkBase mHeader;
+ TInfoSinkBase mBody;
+ TInfoSinkBase mFooter;
+
+ std::set<std::string> mReferencedUniforms;
+ std::set<std::string> mReferencedAttributes;
+ std::set<std::string> mReferencedVaryings;
+
+ // Parameters determining what goes in the header output
+ bool mUsesTexture2D;
+ bool mUsesTexture2D_bias;
+ bool mUsesTexture2DLod;
+ bool mUsesTexture2DProj;
+ bool mUsesTexture2DProj_bias;
+ bool mUsesTexture2DProjLod;
+ bool mUsesTextureCube;
+ bool mUsesTextureCube_bias;
+ bool mUsesTextureCubeLod;
+ bool mUsesTexture2DLod0;
+ bool mUsesTexture2DLod0_bias;
+ bool mUsesTexture2DProjLod0;
+ bool mUsesTexture2DProjLod0_bias;
+ bool mUsesTextureCubeLod0;
+ bool mUsesTextureCubeLod0_bias;
+ bool mUsesDepthRange;
+ bool mUsesFragCoord;
+ bool mUsesPointCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesXor;
+ bool mUsesMod1;
+ bool mUsesMod2v;
+ bool mUsesMod2f;
+ bool mUsesMod3v;
+ bool mUsesMod3f;
+ bool mUsesMod4v;
+ bool mUsesMod4f;
+ bool mUsesFaceforward1;
+ bool mUsesFaceforward2;
+ bool mUsesFaceforward3;
+ bool mUsesFaceforward4;
+ bool mUsesEqualMat2;
+ bool mUsesEqualMat3;
+ bool mUsesEqualMat4;
+ bool mUsesEqualVec2;
+ bool mUsesEqualVec3;
+ bool mUsesEqualVec4;
+ bool mUsesEqualIVec2;
+ bool mUsesEqualIVec3;
+ bool mUsesEqualIVec4;
+ bool mUsesEqualBVec2;
+ bool mUsesEqualBVec3;
+ bool mUsesEqualBVec4;
+ bool mUsesAtan2_1;
+ bool mUsesAtan2_2;
+ bool mUsesAtan2_3;
+ bool mUsesAtan2_4;
+
+ typedef std::set<TString> Constructors;
+ Constructors mConstructors;
+
+ typedef std::set<TString> StructNames;
+ StructNames mStructNames;
+
+ typedef std::list<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ typedef std::vector<int> ScopeBracket;
+ ScopeBracket mScopeBracket;
+ unsigned int mScopeDepth;
+
+ int mUniqueIndex; // For creating unique names
+
+ bool mContainsLoopDiscontinuity;
+ bool mOutputLod0Function;
+ bool mInsideDiscontinuousLoop;
+
+ TIntermSymbol *mExcessiveLoopIndex;
+};
+}
+
+#endif // COMPILER_OUTPUTHLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/ParseHelper.cpp b/src/3rdparty/angle/src/compiler/ParseHelper.cpp
new file mode 100644
index 0000000000..508f1726a7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ParseHelper.cpp
@@ -0,0 +1,1528 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ParseHelper.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/glslang.h"
+#include "compiler/preprocessor/new/SourceLocation.h"
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a vector.
+//
+bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line)
+{
+ fields.num = (int) compString.size();
+ if (fields.num > 4) {
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+
+ enum {
+ exyzw,
+ ergba,
+ estpq,
+ } fieldSet[4];
+
+ for (int i = 0; i < fields.num; ++i) {
+ switch (compString[i]) {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+ }
+
+ for (int i = 0; i < fields.num; ++i) {
+ if (fields.offsets[i] >= vecSize) {
+ error(line, "vector field selection out of range", compString.c_str());
+ return false;
+ }
+
+ if (i > 0) {
+ if (fieldSet[i] != fieldSet[i-1]) {
+ error(line, "illegal - vector component fields not from the same set", compString.c_str());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a matrix.
+//
+bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line)
+{
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = -1;
+ fields.col = -1;
+
+ if (compString.size() != 2) {
+ error(line, "illegal length of matrix field selection", compString.c_str());
+ return false;
+ }
+
+ if (compString[0] == '_') {
+ if (compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeCol = true;
+ fields.col = compString[1] - '0';
+ } else if (compString[1] == '_') {
+ if (compString[0] < '0' || compString[0] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeRow = true;
+ fields.row = compString[0] - '0';
+ } else {
+ if (compString[0] < '0' || compString[0] > '3' ||
+ compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.row = compString[0] - '0';
+ fields.col = compString[1] - '0';
+ }
+
+ if (fields.row >= matSize || fields.col >= matSize) {
+ error(line, "matrix field selection out of range", compString.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Errors
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Track whether errors have occurred.
+//
+void TParseContext::recover()
+{
+}
+
+//
+// Used by flex/bison to output all syntax and parsing errors.
+//
+void TParseContext::error(TSourceLoc loc,
+ const char* reason, const char* token,
+ const char* extraInfo)
+{
+ pp::SourceLocation srcLoc;
+ DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line);
+ diagnostics.writeInfo(pp::Diagnostics::ERROR,
+ srcLoc, reason, token, extraInfo);
+
+}
+
+void TParseContext::warning(TSourceLoc loc,
+ const char* reason, const char* token,
+ const char* extraInfo) {
+ pp::SourceLocation srcLoc;
+ DecodeSourceLoc(loc, &srcLoc.file, &srcLoc.line);
+ diagnostics.writeInfo(pp::Diagnostics::WARNING,
+ srcLoc, reason, token, extraInfo);
+}
+
+void TParseContext::trace(const char* str)
+{
+ diagnostics.writeDebug(str);
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(int line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(int line, const char* op, TString operand)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
+ << " (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand type", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(int line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
+ << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand types ", op, extraInfo.c_str());
+}
+
+bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){
+ if (!checksPrecisionErrors)
+ return false;
+ switch( type ){
+ case EbtFloat:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified for (float)", "" );
+ return true;
+ }
+ break;
+ case EbtInt:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified (int)", "" );
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+//
+// Both test and if necessary, spit out an error, to see if the node is really
+// an l-value that can be operated on this way.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node)
+{
+ TIntermSymbol* symNode = node->getAsSymbolNode();
+ TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode) {
+ bool errorReturn;
+
+ switch(binaryNode->getOp()) {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ return lValueErrorCheck(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
+ if (!errorReturn) {
+ int offset[4] = {0,0,0,0};
+
+ TIntermTyped* rightNode = binaryNode->getRight();
+ TIntermAggregate *aggrNode = rightNode->getAsAggregate();
+
+ for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
+ p != aggrNode->getSequence().end(); p++) {
+ int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
+ offset[value]++;
+ if (offset[value] > 1) {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+
+ return true;
+ }
+ }
+ }
+
+ return errorReturn;
+ default:
+ break;
+ }
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ const char* symbol = 0;
+ if (symNode != 0)
+ symbol = symNode->getSymbol().c_str();
+
+ const char* message = 0;
+ switch (node->getQualifier()) {
+ case EvqConst: message = "can't modify a const"; break;
+ case EvqConstReadOnly: message = "can't modify a const"; break;
+ 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 EvqInput: message = "can't modify an input"; break;
+ case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
+ case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
+ case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
+ default:
+
+ //
+ // Type that can't be written to?
+ //
+ switch (node->getBasicType()) {
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ message = "can't modify a sampler";
+ break;
+ case EbtVoid:
+ message = "can't modify void";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (message == 0 && binaryNode == 0 && symNode == 0) {
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ //
+ // Everything else is okay, no error.
+ //
+ if (message == 0)
+ return false;
+
+ //
+ // If we get here, we have an error and a message.
+ //
+ if (symNode) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "\"" << symbol << "\" (" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+ else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "(" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::constErrorCheck(TIntermTyped* node)
+{
+ if (node->getQualifier() == EvqConst)
+ return false;
+
+ error(node->getLine(), "constant expression required", "");
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
+{
+ if (node->getBasicType() == EbtInt && node->getNominalSize() == 1)
+ return false;
+
+ error(node->getLine(), "integer expression required", token);
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::globalErrorCheck(int line, bool global, const char* token)
+{
+ if (global)
+ return false;
+
+ error(line, "only allowed at global scope", token);
+
+ return true;
+}
+
+//
+// For now, keep it simple: if it starts "gl_", it's reserved, independent
+// of scope. Except, if the symbol table is at the built-in push-level,
+// which is when we are parsing built-ins.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
+// webgl shader.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::reservedErrorCheck(int line, const TString& identifier)
+{
+ static const char* reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel()) {
+ if (identifier.compare(0, 3, "gl_") == 0) {
+ error(line, reservedErrMsg, "gl_");
+ return true;
+ }
+ if (isWebGLBasedSpec(shaderSpec)) {
+ if (identifier.compare(0, 6, "webgl_") == 0) {
+ error(line, reservedErrMsg, "webgl_");
+ return true;
+ }
+ if (identifier.compare(0, 7, "_webgl_") == 0) {
+ error(line, reservedErrMsg, "_webgl_");
+ return true;
+ }
+ if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
+ error(line, reservedErrMsg, "css_");
+ return true;
+ }
+ }
+ if (identifier.find("__") != TString::npos) {
+ error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Make sure there is enough data provided to the constructor to build
+// something of the type of the constructor. Also returns the type of
+// the constructor.
+//
+// Returns true if there was an error in construction.
+//
+bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
+{
+ *type = function.getReturnType();
+
+ bool constructingMatrix = false;
+ switch(op) {
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Note: It's okay to have too many components available, but not okay to have unused
+ // arguments. 'full' will go to true when enough args have been seen. If we loop
+ // again, there is an extra argument, so 'overfull' will become true.
+ //
+
+ int size = 0;
+ bool constType = true;
+ bool full = false;
+ bool overFull = false;
+ bool matrixInMatrix = false;
+ bool arrayArg = false;
+ for (int i = 0; i < function.getParamCount(); ++i) {
+ const TParameter& param = function.getParam(i);
+ size += param.type->getObjectSize();
+
+ if (constructingMatrix && param.type->isMatrix())
+ matrixInMatrix = true;
+ if (full)
+ overFull = true;
+ if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
+ full = true;
+ if (param.type->getQualifier() != EvqConst)
+ constType = false;
+ if (param.type->isArray())
+ arrayArg = true;
+ }
+
+ if (constType)
+ type->setQualifier(EvqConst);
+
+ if (type->isArray() && type->getArraySize() != function.getParamCount()) {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return true;
+ }
+
+ if (arrayArg && op != EOpConstructStruct) {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return true;
+ }
+
+ if (matrixInMatrix && !type->isArray()) {
+ if (function.getParamCount() != 1) {
+ error(line, "constructing matrix from matrix can only take one argument", "constructor");
+ return true;
+ }
+ }
+
+ if (overFull) {
+ error(line, "too many arguments", "constructor");
+ return true;
+ }
+
+ if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) {
+ error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
+ return true;
+ }
+
+ if (!type->isMatrix() || !matrixInMatrix) {
+ if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
+ (op == EOpConstructStruct && size < type->getObjectSize())) {
+ error(line, "not enough data provided for construction", "constructor");
+ return true;
+ }
+ }
+
+ TIntermTyped *typed = node ? node->getAsTyped() : 0;
+ if (typed == 0) {
+ error(line, "constructor argument does not have a type", "constructor");
+ return true;
+ }
+ if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
+ error(line, "cannot convert a sampler", "constructor");
+ return true;
+ }
+ if (typed->getBasicType() == EbtVoid) {
+ error(line, "cannot convert a void", "constructor");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if a void variable has been declared and raise an error message for such a case
+//
+// returns true in case of an error
+//
+bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType)
+{
+ if (pubType.type == EbtVoid) {
+ error(line, "illegal use of type 'void'", identifier.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type)
+{
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(int line, const TPublicType& pType)
+{
+ if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason)
+{
+ if (pType.type == EbtStruct) {
+ if (containsSampler(*pType.userDef)) {
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+
+ return true;
+ }
+
+ return false;
+ } else if (IsSampler(pType.type)) {
+ error(line, reason, getBasicString(pType.type));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
+{
+ if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
+ pType.type == EbtStruct) {
+ error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
+
+ return true;
+ }
+
+ if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
+{
+ if ((qualifier == EvqOut || qualifier == EvqInOut) &&
+ type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
+ error(line, "samplers cannot be output parameters", type.getBasicString());
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::containsSampler(TType& type)
+{
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct) {
+ TTypeList& structure = *type.getStruct();
+ for (unsigned int i = 0; i < structure.size(); ++i) {
+ if (containsSampler(*structure[i].type))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Do size checking for an array type's size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
+{
+ TIntermConstantUnion* constant = expr->getAsConstantUnion();
+ if (constant == 0 || constant->getBasicType() != EbtInt) {
+ error(line, "array size must be a constant integer expression", "");
+ return true;
+ }
+
+ size = constant->getUnionArrayPointer()->getIConst();
+
+ if (size <= 0) {
+ error(line, "array size must be a positive integer", "");
+ size = 1;
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this qualifier can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
+{
+ if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) {
+ error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this type can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type)
+{
+ //
+ // Can the type be an array?
+ //
+ if (type.array) {
+ error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do all the semantic checking for declaring an array, with and
+// without a size, and make the right changes to the symbol table.
+//
+// size == 0 means no specified size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable)
+{
+ //
+ // Don't check for reserved word use until after we know it's not in the symbol table,
+ // because reserved arrays can be redeclared.
+ //
+
+ bool builtIn = false;
+ bool sameScope = false;
+ TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
+ if (symbol == 0 || !sameScope) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+
+ if (! symbolTable.insert(*variable)) {
+ delete variable;
+ error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
+ return true;
+ }
+ } else {
+ if (! symbol->isVariable()) {
+ error(line, "variable expected", identifier.c_str());
+ return true;
+ }
+
+ variable = static_cast<TVariable*>(symbol);
+ if (! variable->getType().isArray()) {
+ error(line, "redeclaring non-array as array", identifier.c_str());
+ return true;
+ }
+ if (variable->getType().getArraySize() > 0) {
+ error(line, "redeclaration of array with size", identifier.c_str());
+ return true;
+ }
+
+ if (! variable->getType().sameElementType(TType(type))) {
+ error(line, "redeclaration of array with a different type", identifier.c_str());
+ return true;
+ }
+
+ TType* t = variable->getArrayInformationType();
+ while (t != 0) {
+ if (t->getMaxArraySize() > type.arraySize) {
+ error(line, "higher index value already used for the array", identifier.c_str());
+ return true;
+ }
+ t->setArraySize(type.arraySize);
+ t = t->getArrayInformationType();
+ }
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line)
+{
+ bool builtIn = false;
+ TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn);
+ if (symbol == 0) {
+ error(line, " undeclared identifier", node->getSymbol().c_str());
+ return true;
+ }
+ TVariable* variable = static_cast<TVariable*>(symbol);
+
+ type->setArrayInformationType(variable->getArrayInformationType());
+ variable->updateArrayInformationType(type);
+
+ // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers
+ // its an error
+ if (node->getSymbol() == "gl_FragData") {
+ TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn);
+ ASSERT(fragData);
+
+ int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst();
+ if (fragDataValue <= size) {
+ error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers");
+ return true;
+ }
+ }
+
+ // we dont want to update the maxArraySize when this flag is not set, we just want to include this
+ // node type in the chain of node types so that its updated when a higher maxArraySize comes in.
+ if (!updateFlag)
+ return false;
+
+ size++;
+ variable->getType().setMaxArraySize(size);
+ type->setMaxArraySize(size);
+ TType* tt = type;
+
+ while(tt->getArrayInformationType() != 0) {
+ tt = tt->getArrayInformationType();
+ tt->setMaxArraySize(size);
+ }
+
+ return false;
+}
+
+//
+// Enforce non-initializer type/qualifier rules.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array)
+{
+ if (type.qualifier == EvqConst)
+ {
+ // Make the qualifier make sense.
+ type.qualifier = EvqTemporary;
+
+ if (array)
+ {
+ error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else if (type.isStructureContainingArrays())
+ {
+ error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else
+ {
+ error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do semantic checking for a variable declaration that has no initializer,
+// and update the symbol table.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable)
+{
+ if (reservedErrorCheck(line, identifier))
+ recover();
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ delete variable;
+ variable = 0;
+ return true;
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
+{
+ if (qualifier != EvqConst && qualifier != EvqTemporary) {
+ error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
+ return true;
+ }
+ if (qualifier == EvqConst && paramQualifier != EvqIn) {
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
+ return true;
+ }
+
+ if (qualifier == EvqConst)
+ type->setQualifier(EvqConstReadOnly);
+ else
+ type->setQualifier(paramQualifier);
+
+ return false;
+}
+
+bool TParseContext::extensionErrorCheck(int line, const TString& extension)
+{
+ const TExtensionBehavior& extBehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
+ if (iter == extBehavior.end()) {
+ error(line, "extension", extension.c_str(), "is not supported");
+ return true;
+ }
+ // In GLSL ES, an extension's default behavior is "disable".
+ if (iter->second == EBhDisable || iter->second == EBhUndefined) {
+ error(line, "extension", extension.c_str(), "is disabled");
+ return true;
+ }
+ if (iter->second == EBhWarn) {
+ warning(line, "extension", extension.c_str(), "is being used");
+ return false;
+ }
+
+ return false;
+}
+
+bool TParseContext::supportsExtension(const char* extension)
+{
+ const TExtensionBehavior& extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+ return (iter != extbehavior.end());
+}
+
+void TParseContext::handleExtensionDirective(int line, const char* extName, const char* behavior)
+{
+ pp::SourceLocation loc;
+ DecodeSourceLoc(line, &loc.file, &loc.line);
+ directiveHandler.handleExtension(loc, extName, behavior);
+}
+
+void TParseContext::handlePragmaDirective(int line, const char* name, const char* value)
+{
+ pp::SourceLocation loc;
+ DecodeSourceLoc(line, &loc.file, &loc.line);
+ directiveHandler.handlePragma(loc, name, value);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise 0.
+//
+const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn)
+{
+ // First find by unmangled name to check whether the function name has been
+ // hidden by a variable name or struct typename.
+ const TSymbol* symbol = symbolTable.find(call->getName(), builtIn);
+ if (symbol == 0) {
+ symbol = symbolTable.find(call->getMangledName(), builtIn);
+ }
+
+ if (symbol == 0) {
+ error(line, "no matching overloaded function found", call->getName().c_str());
+ return 0;
+ }
+
+ if (!symbol->isFunction()) {
+ error(line, "function name expected", call->getName().c_str());
+ return 0;
+ }
+
+ return static_cast<const TFunction*>(symbol);
+}
+
+//
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
+{
+ TType type = TType(pType);
+
+ if (variable == 0) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ if (voidErrorCheck(line, identifier, pType))
+ return true;
+
+ //
+ // add variable to symbol table
+ //
+ variable = new TVariable(&identifier, type);
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ return true;
+ // don't delete variable, it's used by error recovery, and the pool
+ // pop will take care of the memory
+ }
+ }
+
+ //
+ // identifier must be of type constant, a global, or a temporary
+ //
+ TQualifier qualifier = variable->getType().getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
+ error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
+ return true;
+ }
+ //
+ // test for and propagate constant
+ //
+
+ if (qualifier == EvqConst) {
+ if (qualifier != initializer->getType().getQualifier()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " assigning non-constant to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (type != initializer->getType()) {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (initializer->getAsConstantUnion()) {
+ ConstantUnion* unionArray = variable->getConstPointer();
+
+ if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
+ *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
+ } else {
+ variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+ }
+ } else if (initializer->getAsSymbolNode()) {
+ const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
+ const TVariable* tVar = static_cast<const TVariable*>(symbol);
+
+ ConstantUnion* constArray = tVar->getConstPointer();
+ variable->shareConstPointer(constArray);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " cannot assign to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ }
+
+ if (qualifier != EvqConst) {
+ TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (intermNode == 0) {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
+ }
+ } else
+ intermNode = 0;
+
+ return false;
+}
+
+bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
+{
+ ASSERT(aggrNode != NULL);
+ if (!aggrNode->isConstructor())
+ return false;
+
+ bool allConstant = true;
+
+ // check if all the child nodes are constants so that they can be inserted into
+ // the parent node
+ TIntermSequence &sequence = aggrNode->getSequence() ;
+ for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
+ if (!(*p)->getAsTyped()->getAsConstantUnion())
+ return false;
+ }
+
+ return allConstant;
+}
+
+// This function is used to test for the correctness of the parameters passed to various constructor functions
+// and also convert them to the right datatype if it is allowed and required.
+//
+// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
+//
+TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggrNode = node->getAsAggregate();
+
+ TTypeList::const_iterator memberTypes;
+ if (op == EOpConstructStruct)
+ memberTypes = type->getStruct()->begin();
+
+ TType elementType = *type;
+ if (type->isArray())
+ elementType.clearArrayness();
+
+ bool singleArg;
+ if (aggrNode) {
+ if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
+ singleArg = true;
+ else
+ singleArg = false;
+ } else
+ singleArg = true;
+
+ TIntermTyped *newNode;
+ if (singleArg) {
+ // If structure constructor or array constructor is being called
+ // for only one parameter inside the structure, we need to call constructStruct function once.
+ if (type->isArray())
+ newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false);
+ else
+ newNode = constructBuiltIn(type, op, node, node->getLine(), false);
+
+ if (newNode && newNode->getAsAggregate()) {
+ TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+ }
+
+ return newNode;
+ }
+
+ //
+ // Handle list of arguments.
+ //
+ TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
+ // if the structure constructor contains more than one parameter, then construct
+ // each parameter
+
+ int paramCount = 0; // keeps a track of the constructor parameter number being checked
+
+ // for each parameter to the constructor call, check to see if the right type is passed or convert them
+ // to the right type if possible (and allowed).
+ // for structure constructors, just check if the right type is passed, no conversion is allowed.
+
+ for (TIntermSequence::iterator p = sequenceVector.begin();
+ p != sequenceVector.end(); p++, paramCount++) {
+ if (type->isArray())
+ newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true);
+ else
+ newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
+
+ if (newNode) {
+ *p = newNode;
+ }
+ }
+
+ TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
+ TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+
+ return constructor;
+}
+
+TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
+{
+ bool canBeFolded = areAllChildConst(aggrNode);
+ aggrNode->setType(type);
+ if (canBeFolded) {
+ bool returnVal = false;
+ ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
+ if (aggrNode->getSequence().size() == 1) {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
+ }
+ else {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
+ }
+ if (returnVal)
+ return 0;
+
+ return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+ }
+
+ return 0;
+}
+
+// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
+// for the parameter to the constructor (passed to this function). Essentially, it converts
+// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
+// float, then float is converted to int.
+//
+// Returns 0 for an error or the constructed node.
+//
+TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset)
+{
+ TIntermTyped* newNode;
+ TOperator basicOp;
+
+ //
+ // First, convert types as needed.
+ //
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ basicOp = EOpConstructFloat;
+ break;
+
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ basicOp = EOpConstructInt;
+ break;
+
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ basicOp = EOpConstructBool;
+ break;
+
+ default:
+ error(line, "unsupported construction", "");
+ recover();
+
+ return 0;
+ }
+ newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
+ if (newNode == 0) {
+ error(line, "can't convert", "constructor");
+ return 0;
+ }
+
+ //
+ // Now, if there still isn't an operation to do the construction, and we need one, add one.
+ //
+
+ // Otherwise, skip out early.
+ if (subset || (newNode != node && newNode->getType() == *type))
+ return newNode;
+
+ // setAggregateOperator will insert a new node for the constructor, as needed.
+ return intermediate.setAggregateOperator(newNode, op, line);
+}
+
+// This function tests for the type of the parameters to the structures constructors. Raises
+// an error message if the expected type does not match the parameter passed to the constructor.
+//
+// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
+//
+TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset)
+{
+ if (*type == node->getAsTyped()->getType()) {
+ if (subset)
+ return node->getAsTyped();
+ else
+ return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert parameter " << paramCount
+ << " from '" << node->getAsTyped()->getType().getBasicString()
+ << "' to '" << type->getBasicString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "constructor", extraInfo.c_str());
+ recover();
+ }
+
+ return 0;
+}
+
+//
+// This function returns the tree representation for the vector field(s) being accessed from contant vector.
+// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
+// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
+// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
+// a constant matrix.
+//
+TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ ConstantUnion *unionArray;
+ if (tempConstantNode) {
+ unionArray = tempConstantNode->getUnionArrayPointer();
+ ASSERT(unionArray);
+
+ if (!unionArray) {
+ return node;
+ }
+ } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
+ error(line, "Cannot offset into the vector", "Error");
+ recover();
+
+ return 0;
+ }
+
+ ConstantUnion* constArray = new ConstantUnion[fields.num];
+
+ for (int i = 0; i < fields.num; i++) {
+ if (fields.offsets[i] >= node->getType().getObjectSize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ fields.offsets[i] = 0;
+ }
+
+ constArray[i] = unionArray[fields.offsets[i]];
+
+ }
+ typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
+ return typedNode;
+}
+
+//
+// This function returns the column being accessed from a constant matrix. The values are retrieved from
+// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
+// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
+// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ if (index >= node->getType().getNominalSize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "matrix field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ int size = tempConstantNode->getType().getNominalSize();
+ typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the matrix", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns an element of an array accessed from a constant array. The values are retrieved from
+// the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
+// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+ TType arrayElementType = node->getType();
+ arrayElementType.clearArrayness();
+
+ if (index >= node->getType().getArraySize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ int arrayElementSize = arrayElementType.getObjectSize();
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the array", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns the value of a particular field inside a constant structure from the symbol table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
+// function and returns the parse-tree with the values of the embedded/nested struct.
+//
+TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line)
+{
+ const TTypeList* fields = node->getType().getStruct();
+ TIntermTyped *typedNode;
+ int instanceSize = 0;
+ unsigned int index = 0;
+ TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
+
+ for ( index = 0; index < fields->size(); ++index) {
+ if ((*fields)[index].type->getFieldName() == identifier) {
+ break;
+ } else {
+ instanceSize += (*fields)[index].type->getObjectSize();
+ }
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
+
+ typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
+ } else {
+ error(line, "Cannot offset into the structure", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+bool TParseContext::enterStructDeclaration(int line, const TString& identifier)
+{
+ ++structNestingLevel;
+
+ // Embedded structure definitions are not supported per GLSL ES spec.
+ // They aren't allowed in GLSL either, but we need to detect this here
+ // so we don't rely on the GLSL compiler to catch it.
+ if (structNestingLevel > 1) {
+ error(line, "", "Embedded struct definitions are not allowed");
+ return true;
+ }
+
+ return false;
+}
+
+void TParseContext::exitStructDeclaration()
+{
+ --structNestingLevel;
+}
+
+namespace {
+
+const int kWebGLMaxStructNesting = 4;
+
+} // namespace
+
+bool TParseContext::structNestingErrorCheck(TSourceLoc line, const TType& fieldType)
+{
+ if (!isWebGLBasedSpec(shaderSpec)) {
+ return false;
+ }
+
+ if (fieldType.getBasicType() != EbtStruct) {
+ return false;
+ }
+
+ // We're already inside a structure definition at this point, so add
+ // one to the field's struct nesting.
+ if (1 + fieldType.getDeepestStructNesting() > kWebGLMaxStructNesting) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "Reference of struct type " << fieldType.getTypeName()
+ << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting;
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "", extraInfo.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Parse an array of strings using yyparse.
+//
+// Returns 0 for success.
+//
+int PaParseStrings(int count, const char* const string[], const int length[],
+ TParseContext* context) {
+ if ((count == 0) || (string == NULL))
+ return 1;
+
+ if (glslang_initialize(context))
+ return 1;
+
+ int error = glslang_scan(count, string, length, context);
+ if (!error)
+ error = glslang_parse(context);
+
+ glslang_finalize(context);
+
+ return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
+}
+
+
+
diff --git a/src/3rdparty/angle/src/compiler/ParseHelper.h b/src/3rdparty/angle/src/compiler/ParseHelper.h
new file mode 100644
index 0000000000..824ee00f39
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ParseHelper.h
@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef _PARSER_HELPER_INCLUDED_
+#define _PARSER_HELPER_INCLUDED_
+
+#include "compiler/Diagnostics.h"
+#include "compiler/DirectiveHandler.h"
+#include "compiler/localintermediate.h"
+#include "compiler/preprocessor/new/Preprocessor.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+struct TMatrixFields {
+ bool wholeRow;
+ bool wholeCol;
+ int row;
+ int col;
+};
+
+//
+// The following are extra variables needed during parsing, grouped together so
+// they can be passed to the parser without needing a global.
+//
+struct TParseContext {
+ TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
+ intermediate(interm),
+ symbolTable(symt),
+ shaderType(type),
+ shaderSpec(spec),
+ compileOptions(options),
+ sourcePath(sourcePath),
+ treeRoot(0),
+ lexAfterType(false),
+ loopNestingLevel(0),
+ structNestingLevel(0),
+ inTypeParen(false),
+ currentFunctionType(NULL),
+ functionReturnsValue(false),
+ checksPrecisionErrors(checksPrecErrors),
+ diagnostics(is),
+ directiveHandler(ext, diagnostics),
+ preprocessor(&diagnostics, &directiveHandler),
+ scanner(NULL) { }
+ TIntermediate& intermediate; // to hold and build a parse tree
+ TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
+ ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ int compileOptions;
+ const char* sourcePath; // Path of source file or NULL.
+ TIntermNode* treeRoot; // root of parse tree being created
+ bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier
+ int loopNestingLevel; // 0 if outside all loops
+ int structNestingLevel; // incremented while parsing a struct declaration
+ bool inTypeParen; // true if in parentheses, looking only for an identifier
+ const TType* currentFunctionType; // the return type of the function that's currently being parsed
+ bool functionReturnsValue; // true if a non-void function has a return
+ bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
+ TString HashErrMsg;
+ bool AfterEOF;
+ TDiagnostics diagnostics;
+ TDirectiveHandler directiveHandler;
+ pp::Preprocessor preprocessor;
+ void* scanner;
+
+ int numErrors() const { return diagnostics.numErrors(); }
+ TInfoSink& infoSink() { return diagnostics.infoSink(); }
+ void error(TSourceLoc loc, const char *reason, const char* token,
+ const char* extraInfo="");
+ void warning(TSourceLoc loc, const char* reason, const char* token,
+ const char* extraInfo="");
+ void trace(const char* str);
+ void recover();
+
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line);
+ bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line);
+
+ bool reservedErrorCheck(int line, const TString& identifier);
+ void assignError(int line, const char* op, TString left, TString right);
+ void unaryOpError(int line, const char* op, TString operand);
+ void binaryOpError(int line, const char* op, TString left, TString right);
+ bool precisionErrorCheck(int line, TPrecision precision, TBasicType type);
+ bool lValueErrorCheck(int line, const char* op, TIntermTyped*);
+ bool constErrorCheck(TIntermTyped* node);
+ bool integerErrorCheck(TIntermTyped* node, const char* token);
+ bool globalErrorCheck(int line, bool global, const char* token);
+ bool constructorErrorCheck(int line, TIntermNode*, TFunction&, TOperator, TType*);
+ bool arraySizeErrorCheck(int line, TIntermTyped* expr, int& size);
+ bool arrayQualifierErrorCheck(int line, TPublicType type);
+ bool arrayTypeErrorCheck(int line, TPublicType type);
+ bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable);
+ bool voidErrorCheck(int, const TString&, const TPublicType&);
+ bool boolErrorCheck(int, const TIntermTyped*);
+ bool boolErrorCheck(int, const TPublicType&);
+ bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
+ bool structQualifierErrorCheck(int line, const TPublicType& pType);
+ bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
+ bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type, bool array);
+ bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable);
+ bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
+ bool extensionErrorCheck(int line, const TString&);
+
+ const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
+ bool supportsExtension(const char* extension);
+ void handleExtensionDirective(int line, const char* extName, const char* behavior);
+
+ const TPragma& pragma() const { return directiveHandler.pragma(); }
+ void handlePragmaDirective(int line, const char* name, const char* value);
+
+ bool containsSampler(TType& type);
+ bool areAllChildConst(TIntermAggregate* aggrNode);
+ const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
+ bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
+ bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
+
+ TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
+ TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
+ TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset);
+ TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset);
+ TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
+ TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
+ TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line);
+ TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
+
+ // Performs an error check for embedded struct declarations.
+ // Returns true if an error was raised due to the declaration of
+ // this struct.
+ bool enterStructDeclaration(TSourceLoc line, const TString& identifier);
+ void exitStructDeclaration();
+
+ bool structNestingErrorCheck(TSourceLoc line, const TType& fieldType);
+};
+
+int PaParseStrings(int count, const char* const string[], const int length[],
+ TParseContext* context);
+
+#endif // _PARSER_HELPER_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/PoolAlloc.cpp b/src/3rdparty/angle/src/compiler/PoolAlloc.cpp
new file mode 100644
index 0000000000..9ef4f59f5c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/PoolAlloc.cpp
@@ -0,0 +1,310 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/PoolAlloc.h"
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <stdio.h>
+
+#include "common/angleutils.h"
+#include "compiler/InitializeGlobals.h"
+#include "compiler/osinclude.h"
+
+OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
+
+void InitializeGlobalPools()
+{
+ TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+ if (globalPools)
+ return;
+
+ TThreadGlobalPools* threadData = new TThreadGlobalPools();
+ threadData->globalPoolAllocator = 0;
+
+ OS_SetTLSValue(PoolIndex, threadData);
+}
+
+void FreeGlobalPools()
+{
+ // Release the allocated memory for this thread.
+ TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+ if (!globalPools)
+ return;
+
+ delete globalPools;
+}
+
+bool InitializePoolIndex()
+{
+ // Allocate a TLS index.
+ if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX)
+ return false;
+
+ return true;
+}
+
+void FreePoolIndex()
+{
+ // Release the TLS index.
+ OS_FreeTLSIndex(PoolIndex);
+}
+
+TPoolAllocator& GetGlobalPoolAllocator()
+{
+ TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+
+ return *threadData->globalPoolAllocator;
+}
+
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
+{
+ TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+
+ threadData->globalPoolAllocator = poolAllocator;
+}
+
+//
+// Implement the functionality of the TPoolAllocator class, which
+// is documented in PoolAlloc.h.
+//
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
+ pageSize(growthIncrement),
+ alignment(allocationAlignment),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0)
+{
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4*1024)
+ pageSize = 4*1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
+ //
+ // Adjust alignment to be at least pointer aligned and
+ // power of 2.
+ //
+ size_t minAlign = sizeof(void*);
+ alignment &= ~(minAlign - 1);
+ if (alignment < minAlign)
+ alignment = minAlign;
+ size_t a = 1;
+ while (a < alignment)
+ a <<= 1;
+ alignment = a;
+ alignmentMask = a - 1;
+
+ //
+ // Align header skip
+ //
+ headerSkip = minAlign;
+ if (headerSkip < sizeof(tHeader)) {
+ headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+ }
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+ while (inUseList) {
+ tHeader* next = inUseList->nextPage;
+ inUseList->~tHeader();
+ delete [] reinterpret_cast<char*>(inUseList);
+ inUseList = next;
+ }
+
+ // We should not check the guard blocks
+ // here, because we did it already when the block was
+ // placed into the free list.
+ //
+ while (freeList) {
+ tHeader* next = freeList->nextPage;
+ delete [] reinterpret_cast<char*>(freeList);
+ freeList = next;
+ }
+}
+
+// Support MSVC++ 6.0
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal = 0xfe;
+const unsigned char TAllocation::userDataFill = 0xcd;
+
+#ifdef GUARD_BLOCKS
+ const size_t TAllocation::guardBlockSize = 16;
+#else
+ const size_t TAllocation::guardBlockSize = 0;
+#endif
+
+//
+// Check a single guard block for damage
+//
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+{
+#ifdef GUARD_BLOCKS
+ for (size_t x = 0; x < guardBlockSize; x++) {
+ if (blockMem[x] != val) {
+ char assertMsg[80];
+
+ // We don't print the assert message. It's here just to be helpful.
+#if defined(_MSC_VER)
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n",
+ locText, size, data());
+#else
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
+ locText, size, data());
+#endif
+ assert(0 && "PoolAlloc: Damage in guard block");
+ }
+ }
+#endif
+}
+
+
+void TPoolAllocator::push()
+{
+ tAllocState state = { currentPageOffset, inUseList };
+
+ stack.push_back(state);
+
+ //
+ // Indicate there is no current page to allocate from.
+ //
+ currentPageOffset = pageSize;
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+ if (stack.size() < 1)
+ return;
+
+ tHeader* page = stack.back().page;
+ currentPageOffset = stack.back().offset;
+
+ while (inUseList != page) {
+ // invoke destructor to free allocation list
+ inUseList->~tHeader();
+
+ tHeader* nextInUse = inUseList->nextPage;
+ if (inUseList->pageCount > 1)
+ delete [] reinterpret_cast<char*>(inUseList);
+ else {
+ inUseList->nextPage = freeList;
+ freeList = inUseList;
+ }
+ inUseList = nextInUse;
+ }
+
+ stack.pop_back();
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+ while (stack.size() > 0)
+ pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+ // If we are using guard blocks, all allocations are bracketed by
+ // them: [guardblock][allocation][guardblock]. numBytes is how
+ // much memory the caller asked for. allocationSize is the total
+ // size including guard blocks. In release build,
+ // guardBlockSize=0 and this all gets optimized away.
+ size_t allocationSize = TAllocation::allocationSize(numBytes);
+
+ //
+ // Just keep some interesting statistics.
+ //
+ ++numCalls;
+ totalBytes += numBytes;
+
+ //
+ // Do the allocation, most likely case first, for efficiency.
+ // This step could be moved to be inline sometime.
+ //
+ if (currentPageOffset + allocationSize <= pageSize) {
+ //
+ // Safe to allocate from currentPageOffset.
+ //
+ unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
+ currentPageOffset += allocationSize;
+ currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, memory, numBytes);
+ }
+
+ if (allocationSize + headerSkip > pageSize) {
+ //
+ // Do a multi-page allocation. Don't mix these with the others.
+ // The OS is efficient and allocating and free-ing multiple pages.
+ //
+ size_t numBytesToAlloc = allocationSize + headerSkip;
+ tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+ if (memory == 0)
+ return 0;
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+ inUseList = memory;
+
+ currentPageOffset = pageSize; // make next allocation come from a new page
+
+ // No guard blocks for multi-page allocations (yet)
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
+ }
+
+ //
+ // Need a simple page to allocate from.
+ //
+ tHeader* memory;
+ if (freeList) {
+ memory = freeList;
+ freeList = freeList->nextPage;
+ } else {
+ memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+ if (memory == 0)
+ return 0;
+ }
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, 1);
+ inUseList = memory;
+
+ unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
+ currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, ret, numBytes);
+}
+
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+ for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+ alloc->check();
+}
diff --git a/src/3rdparty/angle/src/compiler/PoolAlloc.h b/src/3rdparty/angle/src/compiler/PoolAlloc.h
new file mode 100644
index 0000000000..a8a59c69ac
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/PoolAlloc.h
@@ -0,0 +1,306 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#define GUARD_BLOCKS // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+// typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <stddef.h>
+#include <string.h>
+#include <vector>
+
+// If we are using guard blocks, we must track each indivual
+// allocation. If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+ TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+ size(size), mem(mem), prevAlloc(prev) {
+ // Allocations are bracketed:
+ // [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+ // This would be cleaner with if (guardBlockSize)..., but that
+ // makes the compiler print warnings about 0 length memsets,
+ // even with the if() protecting them.
+#ifdef GUARD_BLOCKS
+ memset(preGuard(), guardBlockBeginVal, guardBlockSize);
+ memset(data(), userDataFill, size);
+ memset(postGuard(), guardBlockEndVal, guardBlockSize);
+#endif
+ }
+
+ void check() const {
+ checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
+ checkGuardBlock(postGuard(), guardBlockEndVal, "after");
+ }
+
+ void checkAllocList() const;
+
+ // Return total size needed to accomodate user buffer of 'size',
+ // plus our tracking data.
+ inline static size_t allocationSize(size_t size) {
+ return size + 2 * guardBlockSize + headerSize();
+ }
+
+ // Offset from surrounding buffer to get to user data buffer.
+ inline static unsigned char* offsetAllocation(unsigned char* m) {
+ return m + guardBlockSize + headerSize();
+ }
+
+private:
+ void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+ // Find offsets to pre and post guard blocks, and user data buffer
+ unsigned char* preGuard() const { return mem + headerSize(); }
+ unsigned char* data() const { return preGuard() + guardBlockSize; }
+ unsigned char* postGuard() const { return data() + size; }
+
+ size_t size; // size of the user data area
+ unsigned char* mem; // beginning of our allocation (pts to header)
+ TAllocation* prevAlloc; // prior allocation in the chain
+
+ // Support MSVC++ 6.0
+ const static unsigned char guardBlockBeginVal;
+ const static unsigned char guardBlockEndVal;
+ const static unsigned char userDataFill;
+
+ const static size_t guardBlockSize;
+#ifdef GUARD_BLOCKS
+ inline static size_t headerSize() { return sizeof(TAllocation); }
+#else
+ inline static size_t headerSize() { return 0; }
+#endif
+};
+
+//
+// There are several stacks. One is to track the pushing and popping
+// of the user, and not yet implemented. The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS. Multi-page allocations
+// are returned to the OS. Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size. But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+ TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+ //
+ // Don't call the destructor just to free up the memory, call pop()
+ //
+ ~TPoolAllocator();
+
+ //
+ // Call push() to establish a new place to pop memory too. Does not
+ // have to be called to get things started.
+ //
+ void push();
+
+ //
+ // Call pop() to free all memory allocated since the last call to push(),
+ // or if no last call to push, frees all memory since first allocation.
+ //
+ void pop();
+
+ //
+ // Call popAll() to free all memory allocated.
+ //
+ void popAll();
+
+ //
+ // Call allocate() to actually acquire memory. Returns 0 if no memory
+ // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+ //
+ void* allocate(size_t numBytes);
+
+ //
+ // There is no deallocate. The point of this class is that
+ // deallocation can be skipped by the user of it, as the model
+ // of use is to simultaneously deallocate everything at once
+ // by calling pop(), and to not have to solve memory leak problems.
+ //
+
+protected:
+ friend struct tHeader;
+
+ struct tHeader {
+ tHeader(tHeader* nextPage, size_t pageCount) :
+ nextPage(nextPage),
+ pageCount(pageCount)
+#ifdef GUARD_BLOCKS
+ , lastAllocation(0)
+#endif
+ { }
+
+ ~tHeader() {
+#ifdef GUARD_BLOCKS
+ if (lastAllocation)
+ lastAllocation->checkAllocList();
+#endif
+ }
+
+ tHeader* nextPage;
+ size_t pageCount;
+#ifdef GUARD_BLOCKS
+ TAllocation* lastAllocation;
+#endif
+ };
+
+ struct tAllocState {
+ size_t offset;
+ tHeader* page;
+ };
+ typedef std::vector<tAllocState> tAllocStack;
+
+ // Track allocations if and only if we're using guard blocks
+ void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+#ifdef GUARD_BLOCKS
+ new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+ block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+ // This is optimized entirely away if GUARD_BLOCKS is not defined.
+ return TAllocation::offsetAllocation(memory);
+ }
+
+ size_t pageSize; // granularity of allocation from the OS
+ size_t alignment; // all returned allocations will be aligned at
+ // this granularity, which will be a power of 2
+ size_t alignmentMask;
+ size_t headerSkip; // amount of memory to skip to make room for the
+ // header (basically, size of header, rounded
+ // up to make it aligned
+ size_t currentPageOffset; // next offset in top of inUseList to allocate from
+ tHeader* freeList; // list of popped memory
+ tHeader* inUseList; // list of all memory currently being used
+ tAllocStack stack; // stack of where to allocate from, to partition pool
+
+ int numCalls; // just an interesting statistic
+ size_t totalBytes; // just an interesting statistic
+private:
+ TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator
+ TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor
+};
+
+
+//
+// There could potentially be many pools with pops happening at
+// different times. But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+extern TPoolAllocator& GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator);
+#define GlobalPoolAllocator GetGlobalPoolAllocator()
+
+struct TThreadGlobalPools
+{
+ TPoolAllocator* globalPoolAllocator;
+};
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class Other>
+ struct rebind {
+ typedef pool_allocator<Other> other;
+ };
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pool_allocator() : allocator(&GlobalPoolAllocator) { }
+ pool_allocator(TPoolAllocator& a) : allocator(&a) { }
+ pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+ template <class Other>
+ pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
+ allocator = p.allocator;
+ return *this;
+ }
+
+ template<class Other>
+ pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
+
+#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
+ // libCStd on some platforms have a different allocate/deallocate interface.
+ // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
+ // allocated, not the number of elements.
+ void* allocate(size_type n) {
+ return getAllocator().allocate(n);
+ }
+ void* allocate(size_type n, const void*) {
+ return getAllocator().allocate(n);
+ }
+ void deallocate(void*, size_type) {}
+#else
+ pointer allocate(size_type n) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ pointer allocate(size_type n, const void*) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ void deallocate(pointer, size_type) {}
+#endif // _RWSTD_ALLOCATOR
+
+ void construct(pointer p, const T& val) { new ((void *)p) T(val); }
+ void destroy(pointer p) { p->T::~T(); }
+
+ bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
+ bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+
+ size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+ size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+ void setAllocator(TPoolAllocator* a) { allocator = a; }
+ TPoolAllocator& getAllocator() const { return *allocator; }
+
+protected:
+ TPoolAllocator* allocator;
+};
+
+#endif // _POOLALLOC_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/Pragma.h b/src/3rdparty/angle/src/compiler/Pragma.h
new file mode 100644
index 0000000000..2f744123b8
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Pragma.h
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PRAGMA_H_
+#define COMPILER_PRAGMA_H_
+
+struct TPragma {
+ // By default optimization is turned on and debug is turned off.
+ TPragma() : optimize(true), debug(false) { }
+ TPragma(bool o, bool d) : optimize(o), debug(d) { }
+
+ bool optimize;
+ bool debug;
+};
+
+#endif // COMPILER_PRAGMA_H_
diff --git a/src/3rdparty/angle/src/compiler/QualifierAlive.cpp b/src/3rdparty/angle/src/compiler/QualifierAlive.cpp
new file mode 100644
index 0000000000..92a6874eb7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/QualifierAlive.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+class TAliveTraverser : public TIntermTraverser {
+public:
+ TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q)
+ {
+ }
+
+ bool wasFound() { return found; }
+
+protected:
+ bool found;
+ TQualifier qualifier;
+
+ void visitSymbol(TIntermSymbol*);
+ bool visitSelection(Visit, TIntermSelection*);
+};
+
+//
+// Report whether or not a variable of the given qualifier type
+// is guaranteed written. Not always possible to determine if
+// it is written conditionally.
+//
+// ?? It does not do this well yet, this is just a place holder
+// that simply determines if it was reference at all, anywhere.
+//
+bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
+{
+ TAliveTraverser it(qualifier);
+
+ if (node)
+ node->traverse(&it);
+
+ return it.wasFound();
+}
+
+void TAliveTraverser::visitSymbol(TIntermSymbol* node)
+{
+ //
+ // If it's what we're looking for, record it.
+ //
+ if (node->getQualifier() == qualifier)
+ found = true;
+}
+
+bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node)
+{
+ if (wasFound())
+ return false;
+
+ return true;
+}
diff --git a/src/3rdparty/angle/src/compiler/QualifierAlive.h b/src/3rdparty/angle/src/compiler/QualifierAlive.h
new file mode 100644
index 0000000000..872a06f721
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/QualifierAlive.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/src/3rdparty/angle/src/compiler/RemoveTree.cpp b/src/3rdparty/angle/src/compiler/RemoveTree.cpp
new file mode 100644
index 0000000000..a4b8c1e63e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/RemoveTree.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+#include "compiler/RemoveTree.h"
+
+//
+// Code to recursively delete the intermediate tree.
+//
+
+class RemoveTree : public TIntermTraverser
+{
+public:
+ RemoveTree() : TIntermTraverser(false, false, true)
+ {
+ }
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+};
+
+void RemoveTree::visitSymbol(TIntermSymbol* node)
+{
+ delete node;
+}
+
+bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node)
+{
+ delete node;
+
+ return true;
+}
+
+void RemoveTree::visitConstantUnion(TIntermConstantUnion* node)
+{
+ delete node;
+}
+
+//
+// Entry point.
+//
+void RemoveAllTreeNodes(TIntermNode* root)
+{
+ RemoveTree it;
+
+ root->traverse(&it);
+}
+
diff --git a/src/3rdparty/angle/src/compiler/RemoveTree.h b/src/3rdparty/angle/src/compiler/RemoveTree.h
new file mode 100644
index 0000000000..97a821679c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/RemoveTree.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+void RemoveAllTreeNodes(TIntermNode*);
diff --git a/src/3rdparty/angle/src/compiler/RenameFunction.h b/src/3rdparty/angle/src/compiler/RenameFunction.h
new file mode 100644
index 0000000000..3908bfddb8
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/RenameFunction.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_RENAME_FUNCTION
+#define COMPILER_RENAME_FUNCTION
+
+#include "compiler/intermediate.h"
+
+//
+// Renames a function, including its declaration and any calls to it.
+//
+class RenameFunction : public TIntermTraverser
+{
+public:
+ RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
+ : TIntermTraverser(true, false, false)
+ , mOldFunctionName(oldFunctionName)
+ , mNewFunctionName(newFunctionName) {}
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ TOperator op = node->getOp();
+ if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
+ node->setName(mNewFunctionName);
+ return true;
+ }
+
+private:
+ const TString mOldFunctionName;
+ const TString mNewFunctionName;
+};
+
+#endif // COMPILER_RENAME_FUNCTION
diff --git a/src/3rdparty/angle/src/compiler/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/SearchSymbol.cpp
new file mode 100644
index 0000000000..9368f1a4fa
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/SearchSymbol.cpp
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#include "compiler/SearchSymbol.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+{
+ match = false;
+}
+
+void SearchSymbol::traverse(TIntermNode *node)
+{
+ node->traverse(this);
+}
+
+void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode)
+{
+ if (symbolNode->getSymbol() == mSymbol)
+ {
+ match = true;
+ }
+}
+
+bool SearchSymbol::foundMatch() const
+{
+ return match;
+}
+}
diff --git a/src/3rdparty/angle/src/compiler/SearchSymbol.h b/src/3rdparty/angle/src/compiler/SearchSymbol.h
new file mode 100644
index 0000000000..6bc0b90feb
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/SearchSymbol.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#ifndef COMPILER_SEARCHSYMBOL_H_
+#define COMPILER_SEARCHSYMBOL_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class SearchSymbol : public TIntermTraverser
+{
+ public:
+ SearchSymbol(const TString &symbol);
+
+ void traverse(TIntermNode *node);
+ void visitSymbol(TIntermSymbol *symbolNode);
+
+ bool foundMatch() const;
+
+ protected:
+ const TString &mSymbol;
+ bool match;
+};
+}
+
+#endif // COMPILER_SEARCHSYMBOL_H_
diff --git a/src/3rdparty/angle/src/compiler/ShHandle.h b/src/3rdparty/angle/src/compiler/ShHandle.h
new file mode 100644
index 0000000000..6ba302ad04
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ShHandle.h
@@ -0,0 +1,142 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SHHANDLE_INCLUDED_
+#define _SHHANDLE_INCLUDED_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/BuiltInFunctionEmulator.h"
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/InfoSink.h"
+#include "compiler/SymbolTable.h"
+#include "compiler/VariableInfo.h"
+
+class LongNameMap;
+class TCompiler;
+class TDependencyGraph;
+
+//
+// Helper function to identify specs that are based on the WebGL spec,
+// like the CSS Shaders spec.
+//
+bool isWebGLBasedSpec(ShShaderSpec spec);
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+ TShHandleBase();
+ virtual ~TShHandleBase();
+ virtual TCompiler* getAsCompiler() { return 0; }
+
+protected:
+ // Memory allocator. Allocates and tracks memory required by the compiler.
+ // Deallocates all memory when compiler is destructed.
+ TPoolAllocator allocator;
+};
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+ TCompiler(ShShaderType type, ShShaderSpec spec);
+ virtual ~TCompiler();
+ virtual TCompiler* getAsCompiler() { return this; }
+
+ bool Init(const ShBuiltInResources& resources);
+ bool compile(const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions);
+
+ // Get results of the last compilation.
+ TInfoSink& getInfoSink() { return infoSink; }
+ const TVariableInfoList& getAttribs() const { return attribs; }
+ const TVariableInfoList& getUniforms() const { return uniforms; }
+ int getMappedNameMaxLength() const;
+
+protected:
+ ShShaderType getShaderType() const { return shaderType; }
+ ShShaderSpec getShaderSpec() const { return shaderSpec; }
+ // Initialize symbol-table with built-in symbols.
+ bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
+ // Clears the results from the previous compilation.
+ void clearResults();
+ // Return true if function recursion is detected.
+ bool detectRecursion(TIntermNode* root);
+ // Rewrites a shader's intermediate tree according to the CSS Shaders spec.
+ void rewriteCSSShader(TIntermNode* root);
+ // Returns true if the given shader does not exceed the minimum
+ // functionality mandated in GLSL 1.0 spec Appendix A.
+ bool validateLimitations(TIntermNode* root);
+ // Collect info for all attribs and uniforms.
+ void collectAttribsUniforms(TIntermNode* root);
+ // Map long variable names into shorter ones.
+ void mapLongVariableNames(TIntermNode* root);
+ // Translate to object code.
+ virtual void translate(TIntermNode* root) = 0;
+ // Returns true if, after applying the packing rules in the GLSL 1.017 spec
+ // Appendix A, section 7, the shader does not use too many uniforms.
+ bool enforcePackingRestrictions();
+ // Returns true if the shader passes the restrictions that aim to prevent timing attacks.
+ bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
+ // Returns true if the shader does not use samplers.
+ bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
+ // Returns true if the shader does not use sampler dependent values to affect control
+ // flow or in operations whose time can depend on the input values.
+ bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
+ // Get built-in extensions with default behavior.
+ const TExtensionBehavior& getExtensionBehavior() const;
+
+ const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+
+private:
+ ShShaderType shaderType;
+ ShShaderSpec shaderSpec;
+
+ int maxUniformVectors;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable symbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior extensionBehavior;
+
+ BuiltInFunctionEmulator builtInFunctionEmulator;
+
+ // Results of compilation.
+ TInfoSink infoSink; // Output sink.
+ TVariableInfoList attribs; // Active attributes in the compiled shader.
+ TVariableInfoList uniforms; // Active uniforms in the compiled shader.
+
+ // Cached copy of the ref-counted singleton.
+ LongNameMap* longNameMap;
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+void DeleteCompiler(TCompiler*);
+
+#endif // _SHHANDLE_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/ShaderLang.cpp
new file mode 100644
index 0000000000..56f5c7f2ec
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ShaderLang.cpp
@@ -0,0 +1,285 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Implement the top-level of interface to the compiler,
+// as defined in ShaderLang.h
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InitializeDll.h"
+#include "compiler/preprocessor/length_limits.h"
+#include "compiler/ShHandle.h"
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle,
+ int expectedValue)
+{
+ int activeUniformLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
+ int activeAttribLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
+ return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit);
+}
+
+static bool checkMappedNameMaxLength(const ShHandle handle, int expectedValue)
+{
+ int mappedNameMaxLength = 0;
+ ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
+ return (expectedValue == mappedNameMaxLength);
+}
+
+static void getVariableInfo(ShShaderInfo varType,
+ const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ if (!handle || !size || !type || !name)
+ return;
+ ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
+ (varType == SH_ACTIVE_UNIFORMS));
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return;
+
+ const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ?
+ compiler->getAttribs() : compiler->getUniforms();
+ if (index < 0 || index >= static_cast<int>(varList.size()))
+ return;
+
+ const TVariableInfo& varInfo = varList[index];
+ if (length) *length = varInfo.name.size();
+ *size = varInfo.size;
+ *type = varInfo.type;
+
+ // This size must match that queried by
+ // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
+ // in ShGetInfo, below.
+ int activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN;
+ ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength));
+ strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength);
+ name[activeUniformAndAttribLength - 1] = 0;
+ if (mappedName) {
+ // This size must match that queried by
+ // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
+ int maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
+ ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
+ strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
+ mappedName[maxMappedNameLength - 1] = 0;
+ }
+}
+
+//
+// Driver must call this first, once, before doing any other
+// compiler operations.
+//
+int ShInitialize()
+{
+ if (!InitProcess())
+ return 0;
+
+ return 1;
+}
+
+//
+// Cleanup symbol tables
+//
+int ShFinalize()
+{
+ if (!DetachProcess())
+ return 0;
+
+ return 1;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(ShBuiltInResources* resources)
+{
+ // Constants.
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ // Extensions.
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+ resources->ARB_texture_rectangle = 0;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources)
+{
+ if (!InitThread())
+ return 0;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ // Generate built-in symbol table.
+ if (!compiler->Init(*resources)) {
+ ShDestruct(base);
+ return 0;
+ }
+
+ return reinterpret_cast<void*>(base);
+}
+
+void ShDestruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+//
+// Do an actual compile on the given strings. The result is left
+// in the given compile object.
+//
+// Return: The return value of ShCompile is really boolean, indicating
+// success or failure.
+//
+int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions)
+{
+ if (!InitThread())
+ return 0;
+
+ if (handle == 0)
+ return 0;
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
+ return success ? 1 : 0;
+}
+
+void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ switch(pname)
+ {
+ case SH_INFO_LOG_LENGTH:
+ *params = compiler->getInfoSink().info.size() + 1;
+ break;
+ case SH_OBJECT_CODE_LENGTH:
+ *params = compiler->getInfoSink().obj.size() + 1;
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ *params = compiler->getUniforms().size();
+ break;
+ case SH_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_ACTIVE_ATTRIBUTES:
+ *params = compiler->getAttribs().size();
+ break;
+ case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_MAPPED_NAME_MAX_LENGTH:
+ // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
+ // handle array and struct dereferences.
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+void ShGetInfoLog(const ShHandle handle, char* infoLog)
+{
+ if (!handle || !infoLog)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(infoLog, infoSink.info.c_str());
+}
+
+//
+// Return any object code.
+//
+void ShGetObjectCode(const ShHandle handle, char* objCode)
+{
+ if (!handle || !objCode)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(objCode, infoSink.obj.c_str());
+}
+
+void ShGetActiveAttrib(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_ATTRIBUTES,
+ handle, index, length, size, type, name, mappedName);
+}
+
+void ShGetActiveUniform(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_UNIFORMS,
+ handle, index, length, size, type, name, mappedName);
+}
diff --git a/src/3rdparty/angle/src/compiler/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/SymbolTable.cpp
new file mode 100644
index 0000000000..847c1e4085
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/SymbolTable.cpp
@@ -0,0 +1,279 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Symbol table for parsing. Most functionaliy and main ideas
+// are documented in the header file.
+//
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4718)
+#endif
+
+#include "compiler/SymbolTable.h"
+
+#include <stdio.h>
+#include <algorithm>
+
+#include "common/angleutils.h"
+
+TType::TType(const TPublicType &p) :
+ type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
+ maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
+{
+ if (p.userDef) {
+ structure = p.userDef->getStruct();
+ typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+ computeDeepestStructNesting();
+ }
+}
+
+//
+// Recursively generate mangled names.
+//
+void TType::buildMangledName(TString& mangledName)
+{
+ if (isMatrix())
+ mangledName += 'm';
+ else if (isVector())
+ mangledName += 'v';
+
+ switch (type) {
+ case EbtFloat: mangledName += 'f'; break;
+ case EbtInt: mangledName += 'i'; break;
+ case EbtBool: mangledName += 'b'; break;
+ case EbtSampler2D: mangledName += "s2"; break;
+ case EbtSamplerCube: mangledName += "sC"; break;
+ case EbtStruct:
+ mangledName += "struct-";
+ if (typeName)
+ mangledName += *typeName;
+ {// support MSVC++6.0
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ mangledName += '-';
+ (*structure)[i].type->buildMangledName(mangledName);
+ }
+ }
+ default:
+ break;
+ }
+
+ mangledName += static_cast<char>('0' + getNominalSize());
+ if (isArray()) {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+}
+
+int TType::getStructSize() const
+{
+ if (!getStruct()) {
+ assert(false && "Not a struct");
+ return 0;
+ }
+
+ if (structureSize == 0)
+ for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+ structureSize += ((*tl).type)->getObjectSize();
+
+ return structureSize;
+}
+
+void TType::computeDeepestStructNesting()
+{
+ if (!getStruct()) {
+ return;
+ }
+
+ int maxNesting = 0;
+ for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); ++tl) {
+ maxNesting = std::max(maxNesting, ((*tl).type)->getDeepestStructNesting());
+ }
+
+ deepestStructNesting = 1 + maxNesting;
+}
+
+bool TType::isStructureContainingArrays() const
+{
+ if (!structure)
+ {
+ return false;
+ }
+
+ for (TTypeList::const_iterator member = structure->begin(); member != structure->end(); member++)
+ {
+ if (member->type->isArray() ||
+ member->type->isStructureContainingArrays())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Dump functions.
+//
+
+void TVariable::dump(TInfoSink& infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
+ if (type.isArray()) {
+ infoSink.debug << "[0]";
+ }
+ infoSink.debug << "\n";
+}
+
+void TFunction::dump(TInfoSink &infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
+}
+
+void TSymbolTableLevel::dump(TInfoSink &infoSink) const
+{
+ tLevel::const_iterator it;
+ for (it = level.begin(); it != level.end(); ++it)
+ (*it).second->dump(infoSink);
+}
+
+void TSymbolTable::dump(TInfoSink &infoSink) const
+{
+ for (int level = currentLevel(); level >= 0; --level) {
+ infoSink.debug << "LEVEL " << level << "\n";
+ table[level]->dump(infoSink);
+ }
+}
+
+//
+// Functions have buried pointers to delete.
+//
+TFunction::~TFunction()
+{
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
+}
+
+//
+// Symbol table levels are a map of pointers to symbols that have to be deleted.
+//
+TSymbolTableLevel::~TSymbolTableLevel()
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in operation. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
+{
+ tLevel::iterator it;
+ for (it = level.begin(); it != level.end(); ++it) {
+ if ((*it).second->isFunction()) {
+ TFunction* function = static_cast<TFunction*>((*it).second);
+ if (function->getName() == name)
+ function->relateToOperator(op);
+ }
+ }
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in extension. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
+ if (it->second->isFunction()) {
+ TFunction* function = static_cast<TFunction*>(it->second);
+ if (function->getName() == name)
+ function->relateToExtension(ext);
+ }
+ }
+}
+
+TSymbol::TSymbol(const TSymbol& copyOf)
+{
+ name = NewPoolTString(copyOf.name->c_str());
+ uniqueId = copyOf.uniqueId;
+}
+
+TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf)
+{
+ type.copyType(copyOf.type, remapper);
+ userType = copyOf.userType;
+ // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL
+ assert(copyOf.arrayInformationType == 0);
+ arrayInformationType = 0;
+
+ if (copyOf.unionArray) {
+ assert(!copyOf.type.getStruct());
+ assert(copyOf.type.getObjectSize() == 1);
+ unionArray = new ConstantUnion[1];
+ unionArray[0] = copyOf.unionArray[0];
+ } else
+ unionArray = 0;
+}
+
+TVariable* TVariable::clone(TStructureMap& remapper)
+{
+ TVariable *variable = new TVariable(*this, remapper);
+
+ return variable;
+}
+
+TFunction::TFunction(const TFunction& copyOf, TStructureMap& remapper) : TSymbol(copyOf)
+{
+ for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
+ TParameter param;
+ parameters.push_back(param);
+ parameters.back().copyParam(copyOf.parameters[i], remapper);
+ }
+
+ returnType.copyType(copyOf.returnType, remapper);
+ mangledName = copyOf.mangledName;
+ op = copyOf.op;
+ defined = copyOf.defined;
+}
+
+TFunction* TFunction::clone(TStructureMap& remapper)
+{
+ TFunction *function = new TFunction(*this, remapper);
+
+ return function;
+}
+
+TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
+{
+ TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
+ tLevel::iterator iter;
+ for (iter = level.begin(); iter != level.end(); ++iter) {
+ symTableLevel->insert(*iter->second->clone(remapper));
+ }
+
+ return symTableLevel;
+}
+
+void TSymbolTable::copyTable(const TSymbolTable& copyOf)
+{
+ TStructureMap remapper;
+ uniqueId = copyOf.uniqueId;
+ for (unsigned int i = 0; i < copyOf.table.size(); ++i) {
+ table.push_back(copyOf.table[i]->clone(remapper));
+ }
+ for( unsigned int i = 0; i < copyOf.precisionStack.size(); i++) {
+ precisionStack.push_back( copyOf.precisionStack[i] );
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/SymbolTable.h b/src/3rdparty/angle/src/compiler/SymbolTable.h
new file mode 100644
index 0000000000..a89499e4f4
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/SymbolTable.h
@@ -0,0 +1,359 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SYMBOL_TABLE_INCLUDED_
+#define _SYMBOL_TABLE_INCLUDED_
+
+//
+// Symbol table for parsing. Has these design characteristics:
+//
+// * Same symbol table can be used to compile many shaders, to preserve
+// effort of creating and loading with the large numbers of built-in
+// symbols.
+//
+// * Name mangling will be used to give each function a unique name
+// so that symbol table lookups are never ambiguous. This allows
+// a simpler symbol table structure.
+//
+// * Pushing and popping of scope, so symbol table will really be a stack
+// of symbol tables. Searched from the top, with new inserts going into
+// the top.
+//
+// * Constants: Compile time constant symbols will keep their values
+// in the symbol table. The parser can substitute constants at parse
+// time, including doing constant folding and constant propagation.
+//
+// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
+// are tracked in the intermediate representation, not the symbol table.
+//
+
+#include <assert.h>
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+//
+// Symbol base class. (Can build functions or variables out of these...)
+//
+class TSymbol {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TSymbol(const TString *n) : name(n) { }
+ virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
+ const TString& getName() const { return *name; }
+ virtual const TString& getMangledName() const { return getName(); }
+ virtual bool isFunction() const { return false; }
+ virtual bool isVariable() const { return false; }
+ void setUniqueId(int id) { uniqueId = id; }
+ int getUniqueId() const { return uniqueId; }
+ virtual void dump(TInfoSink &infoSink) const = 0;
+ TSymbol(const TSymbol&);
+ virtual TSymbol* clone(TStructureMap& remapper) = 0;
+
+protected:
+ const TString *name;
+ unsigned int uniqueId; // For real comparing during code generation
+};
+
+//
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class heirarchy for Constant variables;
+// Only one of int, bool, or float, (or none) is correct for
+// any particular use, but it's easy to do this way, and doesn't
+// seem worth having separate classes, and "getConst" can't simply return
+// different values for different types polymorphically, so this is
+// just simple and pragmatic.
+//
+class TVariable : public TSymbol {
+public:
+ TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
+ virtual ~TVariable() { }
+ virtual bool isVariable() const { return true; }
+ TType& getType() { return type; }
+ const TType& getType() const { return type; }
+ bool isUserType() const { return userType; }
+ void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); }
+ void updateArrayInformationType(TType *t) { arrayInformationType = t; }
+ TType* getArrayInformationType() { return arrayInformationType; }
+
+ virtual void dump(TInfoSink &infoSink) const;
+
+ ConstantUnion* getConstPointer()
+ {
+ if (!unionArray)
+ unionArray = new ConstantUnion[type.getObjectSize()];
+
+ return unionArray;
+ }
+
+ ConstantUnion* getConstPointer() const { return unionArray; }
+
+ void shareConstPointer( ConstantUnion *constArray)
+ {
+ if (unionArray == constArray)
+ return;
+
+ delete[] unionArray;
+ unionArray = constArray;
+ }
+ TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
+ virtual TVariable* clone(TStructureMap& remapper);
+
+protected:
+ TType type;
+ bool userType;
+ // we are assuming that Pool Allocator will free the memory allocated to unionArray
+ // when this object is destroyed
+ ConstantUnion *unionArray;
+ TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol
+};
+
+//
+// The function sub-class of symbols and the parser will need to
+// share this definition of a function parameter.
+//
+struct TParameter {
+ TString *name;
+ TType* type;
+ void copyParam(const TParameter& param, TStructureMap& remapper)
+ {
+ name = NewPoolTString(param.name->c_str());
+ type = param.type->clone(remapper);
+ }
+};
+
+//
+// The function sub-class of a symbol.
+//
+class TFunction : public TSymbol {
+public:
+ TFunction(TOperator o) :
+ TSymbol(0),
+ returnType(TType(EbtVoid, EbpUndefined)),
+ op(o),
+ defined(false) { }
+ TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
+ TSymbol(name),
+ returnType(retType),
+ mangledName(TFunction::mangleName(*name)),
+ op(tOp),
+ defined(false) { }
+ virtual ~TFunction();
+ virtual bool isFunction() const { return true; }
+
+ static TString mangleName(const TString& name) { return name + '('; }
+ static TString unmangleName(const TString& mangledName)
+ {
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+ }
+
+ void addParameter(TParameter& p)
+ {
+ parameters.push_back(p);
+ mangledName = mangledName + p.type->getMangledName();
+ }
+
+ const TString& getMangledName() const { return mangledName; }
+ const TType& getReturnType() const { return returnType; }
+
+ void relateToOperator(TOperator o) { op = o; }
+ TOperator getBuiltInOp() const { return op; }
+
+ void relateToExtension(const TString& ext) { extension = ext; }
+ const TString& getExtension() const { return extension; }
+
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+
+ int getParamCount() const { return static_cast<int>(parameters.size()); }
+ const TParameter& getParam(int i) const { return parameters[i]; }
+
+ virtual void dump(TInfoSink &infoSink) const;
+ TFunction(const TFunction&, TStructureMap& remapper);
+ virtual TFunction* clone(TStructureMap& remapper);
+
+protected:
+ typedef TVector<TParameter> TParamList;
+ TParamList parameters;
+ TType returnType;
+ TString mangledName;
+ TOperator op;
+ TString extension;
+ bool defined;
+};
+
+
+class TSymbolTableLevel {
+public:
+ typedef TMap<TString, TSymbol*> tLevel;
+ typedef tLevel::const_iterator const_iterator;
+ typedef const tLevel::value_type tLevelPair;
+ typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TSymbolTableLevel() { }
+ ~TSymbolTableLevel();
+
+ bool insert(TSymbol& symbol)
+ {
+ //
+ // returning true means symbol was added to the table
+ //
+ tInsertResult result;
+ result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
+
+ return result.second;
+ }
+
+ TSymbol* find(const TString& name) const
+ {
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return 0;
+ else
+ return (*it).second;
+ }
+
+ const_iterator begin() const
+ {
+ return level.begin();
+ }
+
+ const_iterator end() const
+ {
+ return level.end();
+ }
+
+ void relateToOperator(const char* name, TOperator op);
+ void relateToExtension(const char* name, const TString& ext);
+ void dump(TInfoSink &infoSink) const;
+ TSymbolTableLevel* clone(TStructureMap& remapper);
+
+protected:
+ tLevel level;
+};
+
+class TSymbolTable {
+public:
+ TSymbolTable() : uniqueId(0)
+ {
+ //
+ // The symbol table cannot be used until push() is called, but
+ // the lack of an initial call to push() can be used to detect
+ // that the symbol table has not been preloaded with built-ins.
+ //
+ }
+
+ ~TSymbolTable()
+ {
+ // level 0 is always built In symbols, so we never pop that out
+ while (table.size() > 1)
+ pop();
+ }
+
+ //
+ // When the symbol table is initialized with the built-ins, there should
+ // 'push' calls, so that built-ins are at level 0 and the shader
+ // globals are at level 1.
+ //
+ bool isEmpty() { return table.size() == 0; }
+ bool atBuiltInLevel() { return table.size() == 1; }
+ bool atGlobalLevel() { return table.size() <= 2; }
+ void push()
+ {
+ table.push_back(new TSymbolTableLevel);
+ precisionStack.push_back( PrecisionStackLevel() );
+ }
+
+ void pop()
+ {
+ delete table[currentLevel()];
+ table.pop_back();
+ precisionStack.pop_back();
+ }
+
+ bool insert(TSymbol& symbol)
+ {
+ symbol.setUniqueId(++uniqueId);
+ return table[currentLevel()]->insert(symbol);
+ }
+
+ TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
+ {
+ int level = currentLevel();
+ TSymbol* symbol;
+ do {
+ symbol = table[level]->find(name);
+ --level;
+ } while (symbol == 0 && level >= 0);
+ level++;
+ if (builtIn)
+ *builtIn = level == 0;
+ if (sameScope)
+ *sameScope = level == currentLevel();
+ return symbol;
+ }
+
+ TSymbol *findBuiltIn(const TString &name)
+ {
+ return table[0]->find(name);
+ }
+
+ TSymbolTableLevel* getGlobalLevel() {
+ assert(table.size() >= 2);
+ return table[1];
+ }
+
+ TSymbolTableLevel* getOuterLevel() {
+ assert(table.size() >= 2);
+ return table[currentLevel() - 1];
+ }
+
+ void relateToOperator(const char* name, TOperator op) {
+ table[0]->relateToOperator(name, op);
+ }
+ void relateToExtension(const char* name, const TString& ext) {
+ table[0]->relateToExtension(name, ext);
+ }
+ int getMaxSymbolId() { return uniqueId; }
+ void dump(TInfoSink &infoSink) const;
+ void copyTable(const TSymbolTable& copyOf);
+
+ void setDefaultPrecision( TBasicType type, TPrecision prec ){
+ if( type != EbtFloat && type != EbtInt ) return; // Only set default precision for int/float
+ int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
+ precisionStack[indexOfLastElement][type] = prec; // Uses map operator [], overwrites the current value
+ }
+
+ // Searches down the precisionStack for a precision qualifier for the specified TBasicType
+ TPrecision getDefaultPrecision( TBasicType type){
+ if( type != EbtFloat && type != EbtInt ) return EbpUndefined;
+ int level = static_cast<int>(precisionStack.size()) - 1;
+ assert( level >= 0); // Just to be safe. Should not happen.
+ PrecisionStackLevel::iterator it;
+ TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
+ while( level >= 0 ){
+ it = precisionStack[level].find( type );
+ if( it != precisionStack[level].end() ){
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+ }
+
+protected:
+ int currentLevel() const { return static_cast<int>(table.size()) - 1; }
+
+ std::vector<TSymbolTableLevel*> table;
+ typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
+ std::vector< PrecisionStackLevel > precisionStack;
+ int uniqueId; // for unique identification in code generation
+};
+
+#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp
new file mode 100644
index 0000000000..e3a2c2a802
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorESSL.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorESSL.h"
+
+#include "compiler/OutputESSL.h"
+
+TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorESSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior();
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, getShaderType() == SH_FRAGMENT_SHADER);
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink);
+ root->traverse(&outputESSL);
+}
+
+void TranslatorESSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
+ iter != extensionBehavior.end(); ++iter) {
+ if (iter->second != EBhUndefined) {
+ sink << "#extension " << iter->first << " : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/TranslatorESSL.h
new file mode 100644
index 0000000000..a1196bd001
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorESSL.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORESSL_H_
+#define COMPILER_TRANSLATORESSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorESSL : public TCompiler {
+public:
+ TranslatorESSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATORESSL_H_
diff --git a/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp
new file mode 100644
index 0000000000..bb07a1eb4e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorGLSL.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorGLSL.h"
+
+#include "compiler/OutputGLSL.h"
+#include "compiler/VersionGLSL.h"
+
+static void writeVersion(ShShaderType type, TIntermNode* root,
+ TInfoSinkBase& sink) {
+ TVersionGLSL versionGLSL(type);
+ root->traverse(&versionGLSL);
+ int version = versionGLSL.getVersion();
+ // We need to write version directive only if it is greater than 110.
+ // If there is no version directive in the shader, 110 is implied.
+ if (version > 110) {
+ sink << "#version " << version << "\n";
+ }
+}
+
+TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorGLSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(getShaderType(), root, sink);
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, false);
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink);
+ root->traverse(&outputGLSL);
+}
diff --git a/src/3rdparty/angle/src/compiler/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/TranslatorGLSL.h
new file mode 100644
index 0000000000..c2ce06d192
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorGLSL.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORGLSL_H_
+#define COMPILER_TRANSLATORGLSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorGLSL : public TCompiler {
+public:
+ TranslatorGLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+};
+
+#endif // COMPILER_TRANSLATORGLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp
new file mode 100644
index 0000000000..f41decd48c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorHLSL.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+#include "compiler/InitializeParseContext.h"
+#include "compiler/OutputHLSL.h"
+
+TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec)
+{
+}
+
+void TranslatorHLSL::translate(TIntermNode *root)
+{
+ TParseContext& parseContext = *GetGlobalParseContext();
+ sh::OutputHLSL outputHLSL(parseContext);
+
+ outputHLSL.output();
+}
diff --git a/src/3rdparty/angle/src/compiler/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/TranslatorHLSL.h
new file mode 100644
index 0000000000..c3f672ba91
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/TranslatorHLSL.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATORHLSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorHLSL : public TCompiler {
+public:
+ TranslatorHLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+};
+
+#endif // COMPILER_TRANSLATORHLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/Types.h b/src/3rdparty/angle/src/compiler/Types.h
new file mode 100644
index 0000000000..d4576673b1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/Types.h
@@ -0,0 +1,318 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "compiler/BaseTypes.h"
+#include "compiler/Common.h"
+#include "compiler/debug.h"
+
+class TType;
+struct TPublicType;
+
+//
+// Need to have association of line numbers to types in a list for building structs.
+//
+struct TTypeLine {
+ TType* type;
+ int line;
+};
+typedef TVector<TTypeLine> TTypeList;
+
+inline TTypeList* NewPoolTTypeList()
+{
+ void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList));
+ return new(memory) TTypeList;
+}
+
+typedef TMap<TTypeList*, TTypeList*> TStructureMap;
+typedef TMap<TTypeList*, TTypeList*>::iterator TStructureMapIterator;
+
+//
+// Base class for things that have a type.
+//
+class TType
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TType() {}
+ TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
+ type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
+ maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
+ {
+ }
+ explicit TType(const TPublicType &p);
+ TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
+ type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
+ maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0)
+ {
+ typeName = NewPoolTString(n.c_str());
+ }
+
+ void copyType(const TType& copyOf, TStructureMap& remapper)
+ {
+ type = copyOf.type;
+ precision = copyOf.precision;
+ qualifier = copyOf.qualifier;
+ size = copyOf.size;
+ matrix = copyOf.matrix;
+ array = copyOf.array;
+ arraySize = copyOf.arraySize;
+
+ TStructureMapIterator iter;
+ if (copyOf.structure) {
+ if ((iter = remapper.find(structure)) == remapper.end()) {
+ // create the new structure here
+ structure = NewPoolTTypeList();
+ for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
+ TTypeLine typeLine;
+ typeLine.line = (*copyOf.structure)[i].line;
+ typeLine.type = (*copyOf.structure)[i].type->clone(remapper);
+ structure->push_back(typeLine);
+ }
+ } else {
+ structure = iter->second;
+ }
+ } else
+ structure = 0;
+
+ fieldName = 0;
+ if (copyOf.fieldName)
+ fieldName = NewPoolTString(copyOf.fieldName->c_str());
+ typeName = 0;
+ if (copyOf.typeName)
+ typeName = NewPoolTString(copyOf.typeName->c_str());
+
+ mangled = 0;
+ if (copyOf.mangled)
+ mangled = NewPoolTString(copyOf.mangled->c_str());
+
+ structureSize = copyOf.structureSize;
+ maxArraySize = copyOf.maxArraySize;
+ deepestStructNesting = copyOf.deepestStructNesting;
+ assert(copyOf.arrayInformationType == 0);
+ arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level
+ }
+
+ TType* clone(TStructureMap& remapper)
+ {
+ TType *newType = new TType();
+ newType->copyType(*this, remapper);
+
+ return newType;
+ }
+
+ TBasicType getBasicType() const { return type; }
+ void setBasicType(TBasicType t) { type = t; }
+
+ TPrecision getPrecision() const { return precision; }
+ void setPrecision(TPrecision p) { precision = p; }
+
+ TQualifier getQualifier() const { return qualifier; }
+ void setQualifier(TQualifier q) { qualifier = q; }
+
+ // One-dimensional size of single instance type
+ int getNominalSize() const { return size; }
+ void setNominalSize(int s) { size = s; }
+ // Full size of single instance of type
+ int getObjectSize() const
+ {
+ int totalSize;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = getStructSize();
+ else if (matrix)
+ totalSize = size * size;
+ else
+ totalSize = size;
+
+ if (isArray())
+ totalSize *= std::max(getArraySize(), getMaxArraySize());
+
+ return totalSize;
+ }
+
+ bool isMatrix() const { return matrix ? true : false; }
+ void setMatrix(bool m) { matrix = m; }
+
+ bool isArray() const { return array ? true : false; }
+ int getArraySize() const { return arraySize; }
+ void setArraySize(int s) { array = true; arraySize = s; }
+ int getMaxArraySize () const { return maxArraySize; }
+ void setMaxArraySize (int s) { maxArraySize = s; }
+ void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
+ void setArrayInformationType(TType* t) { arrayInformationType = t; }
+ TType* getArrayInformationType() const { return arrayInformationType; }
+
+ bool isVector() const { return size > 1 && !matrix; }
+ bool isScalar() const { return size == 1 && !matrix && !structure; }
+
+ TTypeList* getStruct() const { return structure; }
+ void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); }
+
+ const TString& getTypeName() const
+ {
+ assert(typeName);
+ return *typeName;
+ }
+ void setTypeName(const TString& n)
+ {
+ typeName = NewPoolTString(n.c_str());
+ }
+
+ bool isField() const { return fieldName != 0; }
+ const TString& getFieldName() const
+ {
+ assert(fieldName);
+ return *fieldName;
+ }
+ void setFieldName(const TString& n)
+ {
+ fieldName = NewPoolTString(n.c_str());
+ }
+
+ TString& getMangledName() {
+ if (!mangled) {
+ mangled = NewPoolTString("");
+ buildMangledName(*mangled);
+ *mangled += ';' ;
+ }
+
+ return *mangled;
+ }
+
+ bool sameElementType(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ structure == right.structure;
+ }
+ bool operator==(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ array == right.array && (!array || arraySize == right.arraySize) &&
+ structure == right.structure;
+ // don't check the qualifier, it's not ever what's being sought after
+ }
+ bool operator!=(const TType& right) const {
+ return !operator==(right);
+ }
+ bool operator<(const TType& right) const {
+ if (type != right.type) return type < right.type;
+ if (size != right.size) return size < right.size;
+ if (matrix != right.matrix) return matrix < right.matrix;
+ if (array != right.array) return array < right.array;
+ if (arraySize != right.arraySize) return arraySize < right.arraySize;
+ if (structure != right.structure) return structure < right.structure;
+
+ return false;
+ }
+
+ const char* getBasicString() const { return ::getBasicString(type); }
+ const char* getPrecisionString() const { return ::getPrecisionString(precision); }
+ const char* getQualifierString() const { return ::getQualifierString(qualifier); }
+ TString getCompleteString() const;
+
+ // If this type is a struct, returns the deepest struct nesting of
+ // any field in the struct. For example:
+ // struct nesting1 {
+ // vec4 position;
+ // };
+ // struct nesting2 {
+ // nesting1 field1;
+ // vec4 field2;
+ // };
+ // For type "nesting2", this method would return 2 -- the number
+ // of structures through which indirection must occur to reach the
+ // deepest field (nesting2.field1.position).
+ int getDeepestStructNesting() const { return deepestStructNesting; }
+
+ bool isStructureContainingArrays() const;
+
+protected:
+ void buildMangledName(TString&);
+ int getStructSize() const;
+ void computeDeepestStructNesting();
+
+ TBasicType type : 6;
+ TPrecision precision;
+ TQualifier qualifier : 7;
+ int size : 8; // size of vector or matrix, not size of array
+ unsigned int matrix : 1;
+ unsigned int array : 1;
+ int arraySize;
+ int maxArraySize;
+ TType* arrayInformationType;
+
+ TTypeList* structure; // 0 unless this is a struct
+ mutable int structureSize;
+ int deepestStructNesting;
+
+ TString *fieldName; // for structure field names
+ TString *mangled;
+ TString *typeName; // for structure field type name
+};
+
+//
+// This is a workaround for a problem with the yacc stack, It can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else. Pointers
+// could be used, but also trying to avoid lots of memory management overhead.
+//
+// Not as bad as it looks, there is no actual assumption that the fields
+// match up or are name the same or anything like that.
+//
+struct TPublicType
+{
+ TBasicType type;
+ TQualifier qualifier;
+ TPrecision precision;
+ int size; // size of vector or matrix, not size of array
+ bool matrix;
+ bool array;
+ int arraySize;
+ TType* userDef;
+ int line;
+
+ void setBasic(TBasicType bt, TQualifier q, int ln = 0)
+ {
+ type = bt;
+ qualifier = q;
+ precision = EbpUndefined;
+ size = 1;
+ matrix = false;
+ array = false;
+ arraySize = 0;
+ userDef = 0;
+ line = ln;
+ }
+
+ void setAggregate(int s, bool m = false)
+ {
+ size = s;
+ matrix = m;
+ }
+
+ void setArray(bool a, int s = 0)
+ {
+ array = a;
+ arraySize = s;
+ }
+
+ bool isStructureContainingArrays() const
+ {
+ if (!userDef)
+ {
+ return false;
+ }
+
+ return userDef->isStructureContainingArrays();
+ }
+};
+
+#endif // _TYPES_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp
new file mode 100644
index 0000000000..1782ebc90c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.cpp
@@ -0,0 +1,172 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#include "compiler/UnfoldShortCircuit.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
+{
+ mTemporaryIndex = 0;
+}
+
+void UnfoldShortCircuit::traverse(TIntermNode *node)
+{
+ int rewindIndex = mTemporaryIndex;
+ node->traverse(this);
+ mTemporaryIndex = rewindIndex;
+}
+
+bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;",
+ // and then further simplifies down to "bool s = x; if(!s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if(!s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ case EOpLogicalAnd:
+ // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;",
+ // and then further simplifies down to "bool s = x; if(s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if(s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ if (node->usesTernaryOperator())
+ {
+ int i = mTemporaryIndex;
+
+ out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n";
+
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(this);
+ out << "if(";
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(mOutputHLSL);
+ out << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n"
+ "else\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+
+ return false;
+}
+
+bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
+{
+ int rewindIndex = mTemporaryIndex;
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ mTemporaryIndex = rewindIndex;
+
+ return false;
+}
+
+int UnfoldShortCircuit::getNextTemporaryIndex()
+{
+ return mTemporaryIndex++;
+}
+}
diff --git a/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h
new file mode 100644
index 0000000000..cb176a5f1c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/UnfoldShortCircuit.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements
+//
+
+#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_UNFOLDSHORTCIRCUIT_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class OutputHLSL;
+
+class UnfoldShortCircuit : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL);
+
+ void traverse(TIntermNode *node);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitSelection(Visit visit, TIntermSelection *node);
+ bool visitLoop(Visit visit, TIntermLoop *node);
+
+ int getNextTemporaryIndex();
+
+ protected:
+ TParseContext &mContext;
+ OutputHLSL *const mOutputHLSL;
+
+ int mTemporaryIndex;
+};
+}
+
+#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_
diff --git a/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp
new file mode 100644
index 0000000000..d69ec6bbaa
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ValidateLimitations.cpp
@@ -0,0 +1,512 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ValidateLimitations.h"
+#include "compiler/InfoSink.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/ParseHelper.h"
+
+namespace {
+bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) {
+ for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
+ for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId()) {
+ ASSERT(i->loop != NULL);
+ i->loop->setUnrollFlag(true);
+ return;
+ }
+ }
+ UNREACHABLE();
+}
+
+// Traverses a node to check if it represents a constant index expression.
+// Definition:
+// constant-index-expressions are a superset of constant-expressions.
+// Constant-index-expressions can include loop indices as defined in
+// GLSL ES 1.0 spec, Appendix A, section 4.
+// The following are constant-index-expressions:
+// - Constant expressions
+// - Loop indices as defined in section 4
+// - Expressions composed of both of the above
+class ValidateConstIndexExpr : public TIntermTraverser {
+public:
+ ValidateConstIndexExpr(const TLoopStack& stack)
+ : mValid(true), mLoopStack(stack) {}
+
+ // Returns true if the parsed node represents a constant index expression.
+ bool isValid() const { return mValid; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ // Only constants and loop indices are allowed in a
+ // constant index expression.
+ if (mValid) {
+ mValid = (symbol->getQualifier() == EvqConst) ||
+ IsLoopIndex(symbol, mLoopStack);
+ }
+ }
+
+private:
+ bool mValid;
+ const TLoopStack& mLoopStack;
+};
+
+// Traverses a node to check if it uses a loop index.
+// If an int loop index is used in its body as a sampler array index,
+// mark the loop for unroll.
+class ValidateLoopIndexExpr : public TIntermTraverser {
+public:
+ ValidateLoopIndexExpr(TLoopStack& stack)
+ : mUsesFloatLoopIndex(false),
+ mUsesIntLoopIndex(false),
+ mLoopStack(stack) {}
+
+ bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
+ bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ if (IsLoopIndex(symbol, mLoopStack)) {
+ switch (symbol->getBasicType()) {
+ case EbtFloat:
+ mUsesFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ mUsesIntLoopIndex = true;
+ MarkLoopForUnroll(symbol, mLoopStack);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+
+private:
+ bool mUsesFloatLoopIndex;
+ bool mUsesIntLoopIndex;
+ TLoopStack& mLoopStack;
+};
+} // namespace
+
+ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
+ TInfoSinkBase& sink)
+ : mShaderType(shaderType),
+ mSink(sink),
+ mNumErrors(0)
+{
+}
+
+bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getLeft());
+
+ // Check indexing.
+ switch (node->getOp()) {
+ case EOpIndexDirect:
+ validateIndexing(node);
+ break;
+ case EOpIndexIndirect:
+#if defined(__APPLE__)
+ // Loop unrolling is a work-around for a Mac Cg compiler bug where it
+ // crashes when a sampler array's index is also the loop index.
+ // Once Apple fixes this bug, we should remove the code in this CL.
+ // See http://codereview.appspot.com/4331048/.
+ if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
+ (node->getLeft()->getAsSymbolNode())) {
+ TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
+ ValidateLoopIndexExpr validate(mLoopStack);
+ node->getRight()->traverse(&validate);
+ if (validate.usesFloatLoopIndex()) {
+ error(node->getLine(),
+ "sampler array index is float loop index",
+ "for");
+ }
+ }
+ }
+#endif
+ validateIndexing(node);
+ break;
+ default: break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getOperand());
+
+ return true;
+}
+
+bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node)
+{
+ switch (node->getOp()) {
+ case EOpFunctionCall:
+ validateFunctionCall(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node)
+{
+ if (!validateLoopType(node))
+ return false;
+
+ TLoopInfo info;
+ memset(&info, 0, sizeof(TLoopInfo));
+ info.loop = node;
+ if (!validateForLoopHeader(node, &info))
+ return false;
+
+ TIntermNode* body = node->getBody();
+ if (body != NULL) {
+ mLoopStack.push_back(info);
+ body->traverse(this);
+ mLoopStack.pop_back();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ValidateLimitations::error(TSourceLoc loc,
+ const char *reason, const char* token)
+{
+ mSink.prefix(EPrefixError);
+ mSink.location(loc);
+ mSink << "'" << token << "' : " << reason << "\n";
+ ++mNumErrors;
+}
+
+bool ValidateLimitations::withinLoopBody() const
+{
+ return !mLoopStack.empty();
+}
+
+bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const
+{
+ return IsLoopIndex(symbol, mLoopStack);
+}
+
+bool ValidateLimitations::validateLoopType(TIntermLoop* node) {
+ TLoopType type = node->getType();
+ if (type == ELoopFor)
+ return true;
+
+ // Reject while and do-while loops.
+ error(node->getLine(),
+ "This type of loop is not allowed",
+ type == ELoopWhile ? "while" : "do");
+ return false;
+}
+
+bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ ASSERT(node->getType() == ELoopFor);
+
+ //
+ // The for statement has the form:
+ // for ( init-declaration ; condition ; expression ) statement
+ //
+ if (!validateForLoopInit(node, info))
+ return false;
+ if (!validateForLoopCond(node, info))
+ return false;
+ if (!validateForLoopExpr(node, info))
+ return false;
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopInit(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* init = node->getInit();
+ if (init == NULL) {
+ error(node->getLine(), "Missing init declaration", "for");
+ return false;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermAggregate* decl = init->getAsAggregate();
+ if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) {
+ error(init->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // To keep things simple do not allow declaration list.
+ TIntermSequence& declSeq = decl->getSequence();
+ if (declSeq.size() != 1) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(declInit->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // The loop index has type int or float.
+ TBasicType type = symbol->getBasicType();
+ if ((type != EbtInt) && (type != EbtFloat)) {
+ error(symbol->getLine(),
+ "Invalid type for loop index", getBasicString(type));
+ return false;
+ }
+ // The loop index is initialized with constant expression.
+ if (!isConstExpr(declInit->getRight())) {
+ error(declInit->getLine(),
+ "Loop index cannot be initialized with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ info->index.id = symbol->getId();
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopCond(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* cond = node->getCondition();
+ if (cond == NULL) {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ if (binOp == NULL) {
+ error(node->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ // Loop index should be to the left of relational operator.
+ TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (binOp->getOp()) {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(),
+ "Invalid relational operator",
+ getOperatorString(binOp->getOp()));
+ break;
+ }
+ // Loop index must be compared with a constant.
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be compared with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* expr = node->getExpression();
+ if (expr == NULL) {
+ error(node->getLine(), "Missing expression", "for");
+ return false;
+ }
+
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol* symbol = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == NULL) {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", getOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != NULL) {
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be modified by non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
+{
+ ASSERT(node->getOp() == EOpFunctionCall);
+
+ // If not within loop body, there is nothing to check.
+ if (!withinLoopBody())
+ return true;
+
+ // List of param indices for which loop indices are used as argument.
+ typedef std::vector<int> ParamIndex;
+ ParamIndex pIndex;
+ TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::size_type i = 0; i < params.size(); ++i) {
+ TIntermSymbol* symbol = params[i]->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ pIndex.push_back(i);
+ }
+ // If none of the loop indices are used as arguments,
+ // there is nothing to check.
+ if (pIndex.empty())
+ return true;
+
+ bool valid = true;
+ TSymbolTable& symbolTable = GlobalParseContext->symbolTable;
+ TSymbol* symbol = symbolTable.find(node->getName());
+ ASSERT(symbol && symbol->isFunction());
+ TFunction* function = static_cast<TFunction*>(symbol);
+ for (ParamIndex::const_iterator i = pIndex.begin();
+ i != pIndex.end(); ++i) {
+ const TParameter& param = function->getParam(*i);
+ TQualifier qual = param.type->getQualifier();
+ if ((qual == EvqOut) || (qual == EvqInOut)) {
+ error(params[*i]->getLine(),
+ "Loop index cannot be used as argument to a function out or inout parameter",
+ params[*i]->getAsSymbolNode()->getSymbol().c_str());
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+bool ValidateLimitations::validateOperation(TIntermOperator* node,
+ TIntermNode* operand) {
+ // Check if loop index is modified in the loop body.
+ if (!withinLoopBody() || !node->modifiesState())
+ return true;
+
+ const TIntermSymbol* symbol = operand->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol)) {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ symbol->getSymbol().c_str());
+ }
+ return true;
+}
+
+bool ValidateLimitations::isConstExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+ return node->getAsConstantUnion() != NULL;
+}
+
+bool ValidateLimitations::isConstIndexExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+
+ ValidateConstIndexExpr validate(mLoopStack);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitations::validateIndexing(TIntermBinary* node)
+{
+ ASSERT((node->getOp() == EOpIndexDirect) ||
+ (node->getOp() == EOpIndexIndirect));
+
+ bool valid = true;
+ TIntermTyped* index = node->getRight();
+ // The index expression must have integral type.
+ if (!index->isScalar() || (index->getBasicType() != EbtInt)) {
+ error(index->getLine(),
+ "Index expression must have integral type",
+ index->getCompleteString().c_str());
+ valid = false;
+ }
+ // The index expession must be a constant-index-expression unless
+ // the operand is a uniform in a vertex shader.
+ TIntermTyped* operand = node->getLeft();
+ bool skip = (mShaderType == SH_VERTEX_SHADER) &&
+ (operand->getQualifier() == EvqUniform);
+ if (!skip && !isConstIndexExpr(index)) {
+ error(index->getLine(), "Index expression must be constant", "[]");
+ valid = false;
+ }
+ return valid;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/ValidateLimitations.h
new file mode 100644
index 0000000000..a835cb3c22
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ValidateLimitations.h
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+class TInfoSinkBase;
+
+struct TLoopInfo {
+ struct TIndex {
+ int id; // symbol id.
+ } index;
+ TIntermLoop* loop;
+};
+typedef TVector<TLoopInfo> TLoopStack;
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitations : public TIntermTraverser {
+public:
+ ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink);
+
+ int numErrors() const { return mNumErrors; }
+
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+
+private:
+ void error(TSourceLoc loc, const char *reason, const char* token);
+
+ bool withinLoopBody() const;
+ bool isLoopIndex(const TIntermSymbol* symbol) const;
+ bool validateLoopType(TIntermLoop* node);
+ bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info);
+ // Returns true if none of the loop indices is used as the argument to
+ // the given function out or inout parameter.
+ bool validateFunctionCall(TIntermAggregate* node);
+ bool validateOperation(TIntermOperator* node, TIntermNode* operand);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode* node);
+ bool isConstIndexExpr(TIntermNode* node);
+ bool validateIndexing(TIntermBinary* node);
+
+ ShShaderType mShaderType;
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+ TLoopStack mLoopStack;
+};
+
diff --git a/src/3rdparty/angle/src/compiler/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/VariableInfo.cpp
new file mode 100644
index 0000000000..3ff283627b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VariableInfo.cpp
@@ -0,0 +1,232 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/VariableInfo.h"
+
+static TString arrayBrackets(int index)
+{
+ TStringStream stream;
+ stream << "[" << index << "]";
+ return stream.str();
+}
+
+// Returns the data type for an attribute or uniform.
+static ShDataType getVariableDataType(const TType& type)
+{
+ switch (type.getBasicType()) {
+ case EbtFloat:
+ if (type.isMatrix()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_MAT2;
+ case 3: return SH_FLOAT_MAT3;
+ case 4: return SH_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_VEC2;
+ case 3: return SH_FLOAT_VEC3;
+ case 4: return SH_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_FLOAT;
+ }
+ case EbtInt:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_INT_VEC2;
+ case 3: return SH_INT_VEC3;
+ case 4: return SH_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_INT;
+ }
+ case EbtBool:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_BOOL_VEC2;
+ case 3: return SH_BOOL_VEC3;
+ case 4: return SH_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_BOOL;
+ }
+ case EbtSampler2D: return SH_SAMPLER_2D;
+ case EbtSamplerCube: return SH_SAMPLER_CUBE;
+ case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES;
+ case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB;
+ default: UNREACHABLE();
+ }
+ return SH_NONE;
+}
+
+static void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+static void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+
+// Returns info for an attribute or uniform.
+static void getVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ if (type.getBasicType() == EbtStruct) {
+ if (type.isArray()) {
+ for (int i = 0; i < type.getArraySize(); ++i) {
+ TString lname = name + arrayBrackets(i);
+ TString lmappedName = mappedName + arrayBrackets(i);
+ getUserDefinedVariableInfo(type, lname, lmappedName, infoList);
+ }
+ } else {
+ getUserDefinedVariableInfo(type, name, mappedName, infoList);
+ }
+ } else {
+ getBuiltInVariableInfo(type, name, mappedName, infoList);
+ }
+}
+
+void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() != EbtStruct);
+
+ TVariableInfo varInfo;
+ if (type.isArray()) {
+ varInfo.name = (name + "[0]").c_str();
+ varInfo.mappedName = (mappedName + "[0]").c_str();
+ varInfo.size = type.getArraySize();
+ } else {
+ varInfo.name = name.c_str();
+ varInfo.mappedName = mappedName.c_str();
+ varInfo.size = 1;
+ }
+ varInfo.type = getVariableDataType(type);
+ infoList.push_back(varInfo);
+}
+
+void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ const TTypeList* structure = type.getStruct();
+ for (size_t i = 0; i < structure->size(); ++i) {
+ const TType* fieldType = (*structure)[i].type;
+ getVariableInfo(*fieldType,
+ name + "." + fieldType->getFieldName(),
+ mappedName + "." + fieldType->getFieldName(),
+ infoList);
+ }
+}
+
+TVariableInfo::TVariableInfo()
+{
+}
+
+TVariableInfo::TVariableInfo(ShDataType type, int size)
+ : type(type),
+ size(size)
+{
+}
+
+CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms)
+ : mAttribs(attribs),
+ mUniforms(uniforms)
+{
+}
+
+// We are only interested in attribute and uniform variable declaration.
+void CollectAttribsUniforms::visitSymbol(TIntermSymbol*)
+{
+}
+
+void CollectAttribsUniforms::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool CollectAttribsUniforms::visitBinary(Visit, TIntermBinary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitUnary(Visit, TIntermUnary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitSelection(Visit, TIntermSelection*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = false;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ // We need to visit sequence children to get to variable declarations.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if (qualifier == EvqAttribute || qualifier == EvqUniform)
+ {
+ TVariableInfoList& infoList = qualifier == EvqAttribute ?
+ mAttribs : mUniforms;
+ for (TIntermSequence::const_iterator i = sequence.begin();
+ i != sequence.end(); ++i)
+ {
+ const TIntermSymbol* variable = (*i)->getAsSymbolNode();
+ // The only case in which the sequence will not contain a
+ // TIntermSymbol node is initialization. It will contain a
+ // TInterBinary node in that case. Since attributes and unifroms
+ // cannot be initialized in a shader, we must have only
+ // TIntermSymbol nodes in the sequence.
+ ASSERT(variable != NULL);
+ getVariableInfo(variable->getType(),
+ variable->getOriginalSymbol(),
+ variable->getSymbol(),
+ infoList);
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool CollectAttribsUniforms::visitLoop(Visit, TIntermLoop*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitBranch(Visit, TIntermBranch*)
+{
+ return false;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/VariableInfo.h b/src/3rdparty/angle/src/compiler/VariableInfo.h
new file mode 100644
index 0000000000..fdcc08f5b5
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VariableInfo.h
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VARIABLE_INFO_H_
+#define COMPILER_VARIABLE_INFO_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Provides information about a variable.
+// It is currently being used to store info about active attribs and uniforms.
+struct TVariableInfo {
+ TVariableInfo(ShDataType type, int size);
+ TVariableInfo();
+
+ TPersistString name;
+ TPersistString mappedName;
+ ShDataType type;
+ int size;
+};
+typedef std::vector<TVariableInfo> TVariableInfoList;
+
+// Traverses intermediate tree to collect all attributes and uniforms.
+class CollectAttribsUniforms : public TIntermTraverser {
+public:
+ CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+private:
+ TVariableInfoList& mAttribs;
+ TVariableInfoList& mUniforms;
+};
+
+#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/src/3rdparty/angle/src/compiler/VariablePacker.cpp b/src/3rdparty/angle/src/compiler/VariablePacker.cpp
new file mode 100644
index 0000000000..2f0c4bc2a2
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VariablePacker.cpp
@@ -0,0 +1,297 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "compiler/VariablePacker.h"
+
+#include <algorithm>
+#include "compiler/ShHandle.h"
+
+namespace {
+int GetSortOrder(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ return 0;
+ case SH_FLOAT_MAT2:
+ return 1;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 2;
+ case SH_FLOAT_MAT3:
+ return 3;
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 4;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 5;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 6;
+ default:
+ ASSERT(false);
+ return 7;
+ }
+}
+} // namespace
+
+int VariablePacker::GetNumComponentsPerRow(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ case SH_FLOAT_MAT2:
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 4;
+ case SH_FLOAT_MAT3:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 3;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 2;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 5;
+ }
+}
+
+int VariablePacker::GetNumRows(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ return 4;
+ case SH_FLOAT_MAT3:
+ return 3;
+ case SH_FLOAT_MAT2:
+ return 1;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 100000;
+ }
+}
+
+struct TVariableInfoComparer {
+ bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const
+ {
+ int lhsSortOrder = GetSortOrder(lhs.type);
+ int rhsSortOrder = GetSortOrder(rhs.type);
+ if (lhsSortOrder != rhsSortOrder) {
+ return lhsSortOrder < rhsSortOrder;
+ }
+ // Sort by largest first.
+ return lhs.size > rhs.size;
+ }
+};
+
+unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
+{
+ return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
+ kColumnMask) >> column;
+}
+
+void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
+{
+ unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
+ for (int r = 0; r < numRows; ++r) {
+ int row = topRow + r;
+ ASSERT((rows_[row] & columnFlags) == 0);
+ rows_[row] |= columnFlags;
+ }
+}
+
+bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
+{
+ ASSERT(destRow);
+
+ for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
+ ++topNonFullRow_) {
+ }
+
+ for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
+ --bottomNonFullRow_) {
+ }
+
+ if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
+ return false;
+ }
+
+ unsigned columnFlags = makeColumnFlags(column, 1);
+ int topGoodRow = 0;
+ int smallestGoodTop = -1;
+ int smallestGoodSize = maxRows_ + 1;
+ int bottomRow = bottomNonFullRow_ + 1;
+ bool found = false;
+ for (int row = topNonFullRow_; row <= bottomRow; ++row) {
+ bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
+ if (rowEmpty) {
+ if (!found) {
+ topGoodRow = row;
+ found = true;
+ }
+ } else {
+ if (found) {
+ int size = row - topGoodRow;
+ if (size >= numRows && size < smallestGoodSize) {
+ smallestGoodSize = size;
+ smallestGoodTop = topGoodRow;
+ }
+ }
+ found = false;
+ }
+ }
+ if (smallestGoodTop < 0) {
+ return false;
+ }
+
+ *destRow = smallestGoodTop;
+ if (destSize) {
+ *destSize = smallestGoodSize;
+ }
+ return true;
+}
+
+bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables)
+{
+ ASSERT(maxVectors > 0);
+ maxRows_ = maxVectors;
+ topNonFullRow_ = 0;
+ bottomNonFullRow_ = maxRows_ - 1;
+ TVariableInfoList variables(in_variables);
+
+ // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
+ // order by type, then by size of array, largest first.
+ std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
+ rows_.clear();
+ rows_.resize(maxVectors, 0);
+
+ // Packs the 4 column variables.
+ size_t ii = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 4) {
+ break;
+ }
+ topNonFullRow_ += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ > maxRows_) {
+ return false;
+ }
+
+ // Packs the 3 column variables.
+ int num3ColumnRows = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 3) {
+ break;
+ }
+ num3ColumnRows += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ + num3ColumnRows > maxRows_) {
+ return false;
+ }
+
+ fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
+
+ // Packs the 2 column variables.
+ int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
+ int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
+ int rowsAvailableInColumns01 = twoColumnRowsAvailable;
+ int rowsAvailableInColumns23 = twoColumnRowsAvailable;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 2) {
+ break;
+ }
+ int numRows = GetNumRows(variable.type) * variable.size;
+ if (numRows <= rowsAvailableInColumns01) {
+ rowsAvailableInColumns01 -= numRows;
+ } else if (numRows <= rowsAvailableInColumns23) {
+ rowsAvailableInColumns23 -= numRows;
+ } else {
+ return false;
+ }
+ }
+
+ int numRowsUsedInColumns01 =
+ twoColumnRowsAvailable - rowsAvailableInColumns01;
+ int numRowsUsedInColumns23 =
+ twoColumnRowsAvailable - rowsAvailableInColumns23;
+ fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
+ fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
+ 2, 2);
+
+ // Packs the 1 column variables.
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ ASSERT(1 == GetNumComponentsPerRow(variable.type));
+ int numRows = GetNumRows(variable.type) * variable.size;
+ int smallestColumn = -1;
+ int smallestSize = maxRows_ + 1;
+ int topRow = -1;
+ for (int column = 0; column < kNumColumns; ++column) {
+ int row = 0;
+ int size = 0;
+ if (searchColumn(column, numRows, &row, &size)) {
+ if (size < smallestSize) {
+ smallestSize = size;
+ smallestColumn = column;
+ topRow = row;
+ }
+ }
+ }
+
+ if (smallestColumn < 0) {
+ return false;
+ }
+
+ fillColumns(topRow, numRows, smallestColumn, 1);
+ }
+
+ ASSERT(variables.size() == ii);
+
+ return true;
+}
+
+
+
diff --git a/src/3rdparty/angle/src/compiler/VariablePacker.h b/src/3rdparty/angle/src/compiler/VariablePacker.h
new file mode 100644
index 0000000000..8987066cc3
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VariablePacker.h
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _VARIABLEPACKER_INCLUDED_
+#define _VARIABLEPACKER_INCLUDED_
+
+#include <vector>
+#include "compiler/ShHandle.h"
+
+class VariablePacker {
+ public:
+ // Returns true if the passed in variables pack in maxVectors following
+ // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+ bool CheckVariablesWithinPackingLimits(
+ int maxVectors,
+ const TVariableInfoList& in_variables);
+
+ // Gets how many components in a row a data type takes.
+ static int GetNumComponentsPerRow(ShDataType type);
+
+ // Gets how many rows a data type takes.
+ static int GetNumRows(ShDataType type);
+
+ private:
+ static const int kNumColumns = 4;
+ static const unsigned kColumnMask = (1 << kNumColumns) - 1;
+
+ unsigned makeColumnFlags(int column, int numComponentsPerRow);
+ void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
+ bool searchColumn(int column, int numRows, int* destRow, int* destSize);
+
+ int topNonFullRow_;
+ int bottomNonFullRow_;
+ int maxRows_;
+ std::vector<unsigned> rows_;
+};
+
+#endif // _VARIABLEPACKER_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/VersionGLSL.cpp
new file mode 100644
index 0000000000..7a82bb4dc1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VersionGLSL.cpp
@@ -0,0 +1,140 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/VersionGLSL.h"
+
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+
+// We need to scan for the following:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+// but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+// but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+// (These constructors were reserved in GLSL version 1.10.)
+// 4. Arrays as "out" function parameters.
+// GLSL spec section 6.1.1: "When calling a function, expressions that do
+// not evaluate to l-values cannot be passed to parameters declared as
+// out or inout."
+// GLSL 1.1 section 5.8: "Other binary or unary expressions,
+// non-dereferenced arrays, function names, swizzles with repeated fields,
+// and constants cannot be l-values."
+// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
+// are built-in types, entire structures or arrays... are all l-values."
+//
+// TODO(alokp): The following two cases of invariant decalaration get lost
+// during parsing - they do not get carried over to the intermediate tree.
+// Handle these cases:
+// 1. When a pragma is used to force all output variables to be invariant:
+// - #pragma STDGL invariant(all)
+// 2. When a previously decalared or built-in variable is marked invariant:
+// - invariant gl_Position;
+// - varying vec3 color; invariant color;
+//
+TVersionGLSL::TVersionGLSL(ShShaderType type)
+ : mShaderType(type),
+ mVersion(GLSL_VERSION_110)
+{
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol* node)
+{
+ if (node->getSymbol() == "gl_PointCoord")
+ updateVersion(GLSL_VERSION_120);
+}
+
+void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool TVersionGLSL::visitBinary(Visit, TIntermBinary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitUnary(Visit, TIntermUnary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp()) {
+ case EOpSequence:
+ // We need to visit sequence children to get to global or inner scope.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if ((qualifier == EvqInvariantVaryingIn) ||
+ (qualifier == EvqInvariantVaryingOut)) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ break;
+ }
+ case EOpParameters: {
+ const TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::const_iterator iter = params.begin();
+ iter != params.end(); ++iter)
+ {
+ const TIntermTyped* param = (*iter)->getAsTyped();
+ if (param->isArray())
+ {
+ TQualifier qualifier = param->getQualifier();
+ if ((qualifier == EvqOut) || (qualifier == EvqInOut))
+ {
+ updateVersion(GLSL_VERSION_120);
+ break;
+ }
+ }
+ }
+ // Fully processed. No need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4: {
+ const TIntermSequence& sequence = node->getSequence();
+ if (sequence.size() == 1) {
+ TIntermTyped* typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix()) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool TVersionGLSL::visitLoop(Visit, TIntermLoop*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+void TVersionGLSL::updateVersion(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
diff --git a/src/3rdparty/angle/src/compiler/VersionGLSL.h b/src/3rdparty/angle/src/compiler/VersionGLSL.h
new file mode 100644
index 0000000000..1c1cb1ab97
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/VersionGLSL.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VERSIONGLSL_H_
+#define COMPILER_VERSIONGLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+// - #version and #extension to declare version and extensions.
+// - built-in functions refract, exp, and log.
+// - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+// - many changes to reduce differences when compared to the ES specification.
+// - invariant keyword and its support.
+// - c++ style name hiding rules.
+// - built-in variable gl_PointCoord for fragment shaders.
+// - matrix constructors taking matrix as argument.
+// - array as "out" function parameters
+//
+class TVersionGLSL : public TIntermTraverser {
+public:
+ TVersionGLSL(ShShaderType type);
+
+ // Returns 120 if the following is used the shader:
+ // - "invariant",
+ // - "gl_PointCoord",
+ // - matrix/matrix constructors
+ // - array "out" parameters
+ // Else 110 is returned.
+ int getVersion() { return mVersion; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+protected:
+ void updateVersion(int version);
+
+private:
+ ShShaderType mShaderType;
+ int mVersion;
+};
+
+#endif // COMPILER_VERSIONGLSL_H_
diff --git a/src/3rdparty/angle/src/compiler/debug.cpp b/src/3rdparty/angle/src/compiler/debug.cpp
new file mode 100644
index 0000000000..53778bd3eb
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/debug.cpp
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "compiler/debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/InitializeParseContext.h"
+#include "compiler/ParseHelper.h"
+
+static const int kTraceBufferLen = 1024;
+
+#ifdef TRACE_ENABLED
+extern "C" {
+void Trace(const char *format, ...) {
+ if (!format) return;
+
+ TParseContext* parseContext = GetGlobalParseContext();
+ if (parseContext) {
+ char buf[kTraceBufferLen];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, kTraceBufferLen, format, args);
+ va_end(args);
+
+ parseContext->trace(buf);
+ }
+}
+} // extern "C"
+#endif // TRACE_ENABLED
+
diff --git a/src/3rdparty/angle/src/compiler/debug.h b/src/3rdparty/angle/src/compiler/debug.h
new file mode 100644
index 0000000000..7a371516af
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/debug.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMPILER_DEBUG_H_
+#define COMPILER_DEBUG_H_
+
+#include <assert.h>
+
+#ifdef _DEBUG
+#define TRACE_ENABLED // define to enable debug message tracing
+#endif // _DEBUG
+
+// Outputs text to the debug log
+#ifdef TRACE_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+void Trace(const char* format, ...);
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#else // TRACE_ENABLED
+
+#define Trace(...) ((void)0)
+
+#endif // TRACE_ENABLED
+
+// A macro asserting a condition and outputting failures to the debug log
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+} while(0)
+
+#define UNIMPLEMENTED() do { \
+ Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#define UNREACHABLE() do { \
+ Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#endif // COMPILER_DEBUG_H_
+
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp
new file mode 100644
index 0000000000..ca661d6767
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#pragma warning(disable: 4718)
+
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/depgraph/DependencyGraphBuilder.h"
+
+TDependencyGraph::TDependencyGraph(TIntermNode* intermNode)
+{
+ TDependencyGraphBuilder::build(intermNode, this);
+}
+
+TDependencyGraph::~TDependencyGraph()
+{
+ for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter)
+ {
+ TGraphNode* node = *iter;
+ delete node;
+ }
+}
+
+TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall,
+ int argumentNumber)
+{
+ TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber);
+ mAllNodes.push_back(argument);
+ return argument;
+}
+
+TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall);
+ mAllNodes.push_back(functionCall);
+ if (functionCall->getIntermFunctionCall()->isUserDefined())
+ mUserDefinedFunctionCalls.push_back(functionCall);
+ return functionCall;
+}
+
+TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol)
+{
+ TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId());
+
+ TGraphSymbol* symbol = NULL;
+
+ if (iter != mSymbolIdMap.end()) {
+ TSymbolIdPair pair = *iter;
+ symbol = pair.second;
+ } else {
+ symbol = new TGraphSymbol(intermSymbol);
+ mAllNodes.push_back(symbol);
+
+ TSymbolIdPair pair(intermSymbol->getId(), symbol);
+ mSymbolIdMap.insert(pair);
+
+ // We save all sampler symbols in a collection, so we can start graph traversals from them quickly.
+ if (IsSampler(intermSymbol->getBasicType()))
+ mSamplerSymbols.push_back(symbol);
+ }
+
+ return symbol;
+}
+
+TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection)
+{
+ TGraphSelection* selection = new TGraphSelection(intermSelection);
+ mAllNodes.push_back(selection);
+ return selection;
+}
+
+TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop)
+{
+ TGraphLoop* loop = new TGraphLoop(intermLoop);
+ mAllNodes.push_back(loop);
+ return loop;
+}
+
+TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp);
+ mAllNodes.push_back(logicalOp);
+ return logicalOp;
+}
+
+const char* TGraphLogicalOp::getOpString() const
+{
+ const char* opString = NULL;
+ switch (getIntermLogicalOp()->getOp()) {
+ case EOpLogicalAnd: opString = "and"; break;
+ case EOpLogicalOr: opString = "or"; break;
+ default: opString = "unknown"; break;
+ }
+ return opString;
+}
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h
new file mode 100644
index 0000000000..5a9c35d00b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraph.h
@@ -0,0 +1,212 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+
+#include "compiler/intermediate.h"
+
+#include <set>
+#include <stack>
+
+class TGraphNode;
+class TGraphParentNode;
+class TGraphArgument;
+class TGraphFunctionCall;
+class TGraphSymbol;
+class TGraphSelection;
+class TGraphLoop;
+class TGraphLogicalOp;
+class TDependencyGraphTraverser;
+class TDependencyGraphOutput;
+
+typedef std::set<TGraphNode*> TGraphNodeSet;
+typedef std::vector<TGraphNode*> TGraphNodeVector;
+typedef std::vector<TGraphSymbol*> TGraphSymbolVector;
+typedef std::vector<TGraphFunctionCall*> TFunctionCallVector;
+
+//
+// Base class for all dependency graph nodes.
+//
+class TGraphNode {
+public:
+ TGraphNode(TIntermNode* node) : intermNode(node) {}
+ virtual ~TGraphNode() {}
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+protected:
+ TIntermNode* intermNode;
+};
+
+//
+// Base class for dependency graph nodes that may have children.
+//
+class TGraphParentNode : public TGraphNode {
+public:
+ TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
+ virtual ~TGraphParentNode() {}
+ void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ TGraphNodeSet mDependentNodes;
+};
+
+//
+// Handle function call arguments.
+//
+class TGraphArgument : public TGraphParentNode {
+public:
+ TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
+ : TGraphParentNode(intermFunctionCall)
+ , mArgumentNumber(argumentNumber) {}
+ virtual ~TGraphArgument() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ int getArgumentNumber() const { return mArgumentNumber; }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ int mArgumentNumber;
+};
+
+//
+// Handle function calls.
+//
+class TGraphFunctionCall : public TGraphParentNode {
+public:
+ TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
+ : TGraphParentNode(intermFunctionCall) {}
+ virtual ~TGraphFunctionCall() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle symbols.
+//
+class TGraphSymbol : public TGraphParentNode {
+public:
+ TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
+ virtual ~TGraphSymbol() {}
+ const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle if statements and ternary operators.
+//
+class TGraphSelection : public TGraphNode {
+public:
+ TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
+ virtual ~TGraphSelection() {}
+ const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+class TGraphLoop : public TGraphNode {
+public:
+ TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
+ virtual ~TGraphLoop() {}
+ const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle logical and, or.
+//
+class TGraphLogicalOp : public TGraphNode {
+public:
+ TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
+ virtual ~TGraphLogicalOp() {}
+ const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
+ const char* getOpString() const;
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// A dependency graph of symbols, function calls, conditions etc.
+//
+// This class provides an interface to the entry points of the dependency graph.
+//
+// Dependency graph nodes should be created by using one of the provided "create..." methods.
+// This class (and nobody else) manages the memory of the created nodes.
+// Nodes may not be removed after being added, so all created nodes will exist while the
+// TDependencyGraph instance exists.
+//
+class TDependencyGraph {
+public:
+ TDependencyGraph(TIntermNode* intermNode);
+ ~TDependencyGraph();
+ TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); }
+ TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); }
+
+ TGraphSymbolVector::const_iterator beginSamplerSymbols() const
+ {
+ return mSamplerSymbols.begin();
+ }
+
+ TGraphSymbolVector::const_iterator endSamplerSymbols() const
+ {
+ return mSamplerSymbols.end();
+ }
+
+ TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.begin();
+ }
+
+ TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.end();
+ }
+
+ TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
+ TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall);
+ TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol);
+ TGraphSelection* createSelection(TIntermSelection* intermSelection);
+ TGraphLoop* createLoop(TIntermLoop* intermLoop);
+ TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp);
+private:
+ typedef TMap<int, TGraphSymbol*> TSymbolIdMap;
+ typedef std::pair<int, TGraphSymbol*> TSymbolIdPair;
+
+ TGraphNodeVector mAllNodes;
+ TGraphSymbolVector mSamplerSymbols;
+ TFunctionCallVector mUserDefinedFunctionCalls;
+ TSymbolIdMap mSymbolIdMap;
+};
+
+//
+// For traversing the dependency graph. Users should derive from this,
+// put their traversal specific data in it, and then pass it to a
+// traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+//
+class TDependencyGraphTraverser {
+public:
+ TDependencyGraphTraverser() : mDepth(0) {}
+
+ virtual void visitSymbol(TGraphSymbol* symbol) {};
+ virtual void visitArgument(TGraphArgument* selection) {};
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {};
+ virtual void visitSelection(TGraphSelection* selection) {};
+ virtual void visitLoop(TGraphLoop* loop) {};
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {};
+
+ int getDepth() const { return mDepth; }
+ void incrementDepth() { ++mDepth; }
+ void decrementDepth() { --mDepth; }
+
+ void clearVisited() { mVisited.clear(); }
+ void markVisited(TGraphNode* node) { mVisited.insert(node); }
+ bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); }
+private:
+ int mDepth;
+ TGraphNodeSet mVisited;
+};
+
+#endif
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp
new file mode 100644
index 0000000000..d586cfd03c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.cpp
@@ -0,0 +1,227 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraphBuilder.h"
+
+void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph)
+{
+ TDependencyGraphBuilder builder(graph);
+ builder.build(node);
+}
+
+bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate)
+{
+ switch (intermAggregate->getOp()) {
+ case EOpFunction: visitFunctionDefinition(intermAggregate); break;
+ case EOpFunctionCall: visitFunctionCall(intermAggregate); break;
+ default: visitAggregateChildren(intermAggregate); break;
+ }
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate)
+{
+ // Currently, we do not support user defined functions.
+ if (intermAggregate->getName() != "main(")
+ return;
+
+ visitAggregateChildren(intermAggregate);
+}
+
+// Takes an expression like "f(x)" and creates a dependency graph like
+// "x -> argument 0 -> function call".
+void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall);
+
+ // Run through the function call arguments.
+ int argumentNumber = 0;
+ TIntermSequence& intermArguments = intermFunctionCall->getSequence();
+ for (TIntermSequence::const_iterator iter = intermArguments.begin();
+ iter != intermArguments.end();
+ ++iter, ++argumentNumber)
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ TIntermNode* intermArgument = *iter;
+ intermArgument->traverse(this);
+
+ if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) {
+ TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber);
+ connectMultipleNodesToSingleNode(argumentNodes, argument);
+ argument->addDependentNode(functionCall);
+ }
+ }
+
+ // Push the leftmost symbol of this function call into the current set of dependent symbols to
+ // represent the result of this function call.
+ // Thus, an expression like "y = f(x)" will yield a dependency graph like
+ // "x -> argument 0 -> function call -> y".
+ // This line essentially passes the function call node back up to an earlier visitAssignment
+ // call, which will create the connection "function call -> y".
+ mNodeSets.insertIntoTopSet(functionCall);
+}
+
+void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate)
+{
+ TIntermSequence& sequence = intermAggregate->getSequence();
+ for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
+ {
+ TIntermNode* intermChild = *iter;
+ intermChild->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
+{
+ // Push this symbol into the set of dependent symbols for the current assignment or condition
+ // that we are traversing.
+ TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol);
+ mNodeSets.insertIntoTopSet(symbol);
+
+ // If this symbol is the current leftmost symbol under an assignment, replace the previous
+ // leftmost symbol with this symbol.
+ if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) {
+ mLeftmostSymbols.pop();
+ mLeftmostSymbols.push(symbol);
+ }
+}
+
+bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
+{
+ TOperator op = intermBinary->getOp();
+ if (op == EOpInitialize || intermBinary->modifiesState())
+ visitAssignment(intermBinary);
+ else if (op == EOpLogicalAnd || op == EOpLogicalOr)
+ visitLogicalOp(intermBinary);
+ else
+ visitBinaryChildren(intermBinary);
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment)
+{
+ TIntermTyped* intermLeft = intermAssignment->getLeft();
+ if (!intermLeft)
+ return;
+
+ TGraphSymbol* leftmostSymbol = NULL;
+
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree);
+ intermLeft->traverse(this);
+ leftmostSymbol = mLeftmostSymbols.top();
+
+ // After traversing the left subtree of this assignment, we should have found a real
+ // leftmost symbol, and the leftmost symbol should not be a placeholder.
+ ASSERT(leftmostSymbol != &mLeftSubtree);
+ ASSERT(leftmostSymbol != &mRightSubtree);
+ }
+
+ if (TIntermTyped* intermRight = intermAssignment->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+
+ if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet())
+ connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
+ }
+
+ // Push the leftmost symbol of this assignment into the current set of dependent symbols to
+ // represent the result of this assignment.
+ // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a".
+ // This line essentially passes the leftmost symbol of the nested assignment ("b" in this
+ // example) back up to the earlier visitAssignment call for the outer assignment, which will
+ // create the connection "b -> a".
+ mNodeSets.insertIntoTopSet(leftmostSymbol);
+}
+
+void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) {
+ TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
+
+ intermLeft->traverse(this);
+ if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) {
+ TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp);
+ connectMultipleNodesToSingleNode(leftNodes, logicalOp);
+ }
+ }
+
+ if (TIntermTyped* intermRight = intermLogicalOp->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary)
+{
+ if (TIntermTyped* intermLeft = intermBinary->getLeft())
+ intermLeft->traverse(this);
+
+ if (TIntermTyped* intermRight = intermBinary->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection)
+{
+ if (TIntermNode* intermCondition = intermSelection->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphSelection* selection = mGraph->createSelection(intermSelection);
+ connectMultipleNodesToSingleNode(conditionNodes, selection);
+ }
+ }
+
+ if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock())
+ intermTrueBlock->traverse(this);
+
+ if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock())
+ intermFalseBlock->traverse(this);
+
+ return false;
+}
+
+bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop)
+{
+ if (TIntermTyped* intermCondition = intermLoop->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphLoop* loop = mGraph->createLoop(intermLoop);
+ connectMultipleNodesToSingleNode(conditionNodes, loop);
+ }
+ }
+
+ if (TIntermNode* intermBody = intermLoop->getBody())
+ intermBody->traverse(this);
+
+ if (TIntermTyped* intermExpression = intermLoop->getExpression())
+ intermExpression->traverse(this);
+
+ return false;
+}
+
+
+void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes,
+ TGraphNode* node) const
+{
+ for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter)
+ {
+ TGraphParentNode* currentNode = *iter;
+ currentNode->addDependentNode(node);
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h
new file mode 100644
index 0000000000..c5f232cb21
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphBuilder.h
@@ -0,0 +1,181 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+
+#include "compiler/depgraph/DependencyGraph.h"
+
+//
+// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a
+// intermediate tree.
+//
+class TDependencyGraphBuilder : public TIntermTraverser {
+public:
+ static void build(TIntermNode* node, TDependencyGraph* graph);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitBinary(Visit visit, TIntermBinary*);
+ virtual bool visitSelection(Visit visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit visit, TIntermLoop*);
+
+private:
+ typedef std::stack<TGraphSymbol*> TSymbolStack;
+ typedef std::set<TGraphParentNode*> TParentNodeSet;
+
+ //
+ // For collecting the dependent nodes of assignments, conditions, etc.
+ // while traversing the intermediate tree.
+ //
+ // This data structure is stack of sets. Each set contains dependency graph parent nodes.
+ //
+ class TNodeSetStack {
+ public:
+ TNodeSetStack() {};
+ ~TNodeSetStack() { clear(); }
+
+ // This should only be called after a pushSet.
+ // Returns NULL if the top set is empty.
+ TParentNodeSet* getTopSet() const
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* topSet = nodeSets.top();
+ return !topSet->empty() ? topSet : NULL;
+ }
+
+ void pushSet() { nodeSets.push(new TParentNodeSet()); }
+ void popSet()
+ {
+ ASSERT(!nodeSets.empty());
+ delete nodeSets.top();
+ nodeSets.pop();
+ }
+
+ // Pops the top set and adds its contents to the new top set.
+ // This should only be called after a pushSet.
+ // If there is no set below the top set, the top set is just deleted.
+ void popSetIntoNext()
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* oldTopSet = nodeSets.top();
+ nodeSets.pop();
+
+ if (!nodeSets.empty()) {
+ TParentNodeSet* newTopSet = nodeSets.top();
+ newTopSet->insert(oldTopSet->begin(), oldTopSet->end());
+ }
+
+ delete oldTopSet;
+ }
+
+ // Does nothing if there is no top set.
+ // This can be called when there is no top set if we are visiting
+ // symbols that are not under an assignment or condition.
+ // We don't need to track those symbols.
+ void insertIntoTopSet(TGraphParentNode* node)
+ {
+ if (nodeSets.empty())
+ return;
+
+ nodeSets.top()->insert(node);
+ }
+
+ void clear()
+ {
+ while (!nodeSets.empty())
+ popSet();
+ }
+
+ private:
+ typedef std::stack<TParentNodeSet*> TParentNodeSetStack;
+
+ TParentNodeSetStack nodeSets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the node set.
+ //
+ class TNodeSetMaintainer {
+ public:
+ TNodeSetMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetMaintainer() { sets.popSet(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the top node set and adds its contents to
+ // the new top node set.
+ //
+ class TNodeSetPropagatingMaintainer {
+ public:
+ TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class keeps track of the leftmost symbol while we're exploring an
+ // assignment.
+ // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree,
+ // and kRightSubtree under a right subtree.
+ // When it goes out of scope, it will pop the leftmost symbol at the top of the scope.
+ // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol.
+ // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost
+ // symbol.
+ //
+ class TLeftmostSymbolMaintainer {
+ public:
+ TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree)
+ : leftmostSymbols(factory->mLeftmostSymbols)
+ {
+ needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree;
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.push(&subtree);
+ }
+
+ ~TLeftmostSymbolMaintainer()
+ {
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.pop();
+ }
+
+ protected:
+ TSymbolStack& leftmostSymbols;
+ bool needsPlaceholderSymbol;
+ };
+
+ TDependencyGraphBuilder(TDependencyGraph* graph)
+ : TIntermTraverser(true, false, false)
+ , mLeftSubtree(NULL)
+ , mRightSubtree(NULL)
+ , mGraph(graph) {}
+ void build(TIntermNode* intermNode) { intermNode->traverse(this); }
+
+ void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const;
+
+ void visitAssignment(TIntermBinary*);
+ void visitLogicalOp(TIntermBinary*);
+ void visitBinaryChildren(TIntermBinary*);
+ void visitFunctionDefinition(TIntermAggregate*);
+ void visitFunctionCall(TIntermAggregate* intermFunctionCall);
+ void visitAggregateChildren(TIntermAggregate*);
+
+ TGraphSymbol mLeftSubtree;
+ TGraphSymbol mRightSubtree;
+
+ TDependencyGraph* mGraph;
+ TNodeSetStack mNodeSets;
+ TSymbolStack mLeftmostSymbols;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp
new file mode 100644
index 0000000000..6fc489e7b6
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraphOutput.h"
+
+void TDependencyGraphOutput::outputIndentation()
+{
+ for (int i = 0; i < getDepth(); ++i)
+ mSink << " ";
+}
+
+void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter)
+{
+ outputIndentation();
+ mSink << "argument " << parameter->getArgumentNumber() << " of call to "
+ << parameter->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall)
+{
+ outputIndentation();
+ mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol)
+{
+ outputIndentation();
+ mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: "
+ << symbol->getIntermSymbol()->getId() << ")\n";
+}
+
+void TDependencyGraphOutput::visitSelection(TGraphSelection* selection)
+{
+ outputIndentation();
+ mSink << "selection\n";
+}
+
+void TDependencyGraphOutput::visitLoop(TGraphLoop* loop)
+{
+ outputIndentation();
+ mSink << "loop condition\n";
+}
+
+void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ outputIndentation();
+ mSink << "logical " << logicalOp->getOpString() << "\n";
+}
+
+void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
+{
+ mSink << "\n";
+
+ for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter)
+ {
+ TGraphNode* symbol = *iter;
+ mSink << "--- Dependency graph spanning tree ---\n";
+ clearVisited();
+ symbol->traverse(this);
+ mSink << "\n";
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h
new file mode 100644
index 0000000000..01447da987
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphOutput.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/InfoSink.h"
+
+class TDependencyGraphOutput : public TDependencyGraphTraverser {
+public:
+ TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
+ virtual void visitSymbol(TGraphSymbol* symbol);
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+ void outputAllSpanningTrees(TDependencyGraph& graph);
+private:
+ void outputIndentation();
+
+ TInfoSinkBase& mSink;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
diff --git a/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp
new file mode 100644
index 0000000000..b158575cec
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/depgraph/DependencyGraphTraverse.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraph.h"
+
+// These methods do a breadth-first traversal through the graph and mark visited nodes.
+
+void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->markVisited(this);
+}
+
+void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ TGraphNode::traverse(graphTraverser);
+
+ graphTraverser->incrementDepth();
+
+ // Visit the parent node's children.
+ for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin();
+ iter != mDependentNodes.end();
+ ++iter)
+ {
+ TGraphNode* node = *iter;
+ if (!graphTraverser->isVisited(node))
+ node->traverse(graphTraverser);
+ }
+
+ graphTraverser->decrementDepth();
+}
+
+void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitArgument(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitFunctionCall(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSymbol(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSelection(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLoop(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLogicalOp(this);
+ TGraphNode::traverse(graphTraverser);
+}
diff --git a/src/3rdparty/angle/src/compiler/glslang.h b/src/3rdparty/angle/src/compiler/glslang.h
new file mode 100644
index 0000000000..3a45daf3a4
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/glslang.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+struct TParseContext;
+extern int glslang_initialize(TParseContext* context);
+extern int glslang_finalize(TParseContext* context);
+
+extern int glslang_scan(int count,
+ const char* const string[],
+ const int length[],
+ TParseContext* context);
+extern int glslang_parse(TParseContext* context);
+
diff --git a/src/3rdparty/angle/src/compiler/glslang.l b/src/3rdparty/angle/src/compiler/glslang.l
new file mode 100644
index 0000000000..e0483e2ea9
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/glslang.l
@@ -0,0 +1,511 @@
+/*
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+%top{
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+}
+
+%{
+#include "compiler/glslang.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/preprocessor/new/Token.h"
+#include "compiler/util.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION yylval->lex.line = yylineno;
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static int string_input(char* buf, int max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+%}
+
+%option noyywrap nounput never-interactive
+%option yylineno reentrant bison-bridge
+%option stack
+%option extra-type="TParseContext*"
+%x COMMENT FIELDS
+
+D [0-9]
+L [a-zA-Z_]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+O [0-7]
+
+%%
+
+%{
+ TParseContext* context = yyextra;
+%}
+
+ /* Single-line comments */
+"//"[^\n]* ;
+
+ /* Multi-line comments */
+"/*" { yy_push_state(COMMENT, yyscanner); }
+<COMMENT>. |
+<COMMENT>\n ;
+<COMMENT>"*/" { yy_pop_state(yyscanner); }
+
+"invariant" { return(INVARIANT); }
+"highp" { return(HIGH_PRECISION); }
+"mediump" { return(MEDIUM_PRECISION); }
+"lowp" { return(LOW_PRECISION); }
+"precision" { return(PRECISION); }
+
+"attribute" { return(ATTRIBUTE); }
+"const" { return(CONST_QUAL); }
+"uniform" { return(UNIFORM); }
+"varying" { return(VARYING); }
+
+"break" { return(BREAK); }
+"continue" { return(CONTINUE); }
+"do" { return(DO); }
+"for" { return(FOR); }
+"while" { return(WHILE); }
+
+"if" { return(IF); }
+"else" { return(ELSE); }
+
+"in" { return(IN_QUAL); }
+"out" { return(OUT_QUAL); }
+"inout" { return(INOUT_QUAL); }
+
+"float" { context->lexAfterType = true; return(FLOAT_TYPE); }
+"int" { context->lexAfterType = true; return(INT_TYPE); }
+"void" { context->lexAfterType = true; return(VOID_TYPE); }
+"bool" { context->lexAfterType = true; return(BOOL_TYPE); }
+"true" { yylval->lex.b = true; return(BOOLCONSTANT); }
+"false" { yylval->lex.b = false; return(BOOLCONSTANT); }
+
+"discard" { return(DISCARD); }
+"return" { return(RETURN); }
+
+"mat2" { context->lexAfterType = true; return(MATRIX2); }
+"mat3" { context->lexAfterType = true; return(MATRIX3); }
+"mat4" { context->lexAfterType = true; return(MATRIX4); }
+
+"vec2" { context->lexAfterType = true; return (VEC2); }
+"vec3" { context->lexAfterType = true; return (VEC3); }
+"vec4" { context->lexAfterType = true; return (VEC4); }
+"ivec2" { context->lexAfterType = true; return (IVEC2); }
+"ivec3" { context->lexAfterType = true; return (IVEC3); }
+"ivec4" { context->lexAfterType = true; return (IVEC4); }
+"bvec2" { context->lexAfterType = true; return (BVEC2); }
+"bvec3" { context->lexAfterType = true; return (BVEC3); }
+"bvec4" { context->lexAfterType = true; return (BVEC4); }
+
+"sampler2D" { context->lexAfterType = true; return SAMPLER2D; }
+"samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; }
+"samplerExternalOES" { context->lexAfterType = true; return SAMPLER_EXTERNAL_OES; }
+"sampler2DRect" { context->lexAfterType = true; return SAMPLER2DRECT; }
+
+"struct" { context->lexAfterType = true; return(STRUCT); }
+
+"asm" { return reserved_word(yyscanner); }
+
+"class" { return reserved_word(yyscanner); }
+"union" { return reserved_word(yyscanner); }
+"enum" { return reserved_word(yyscanner); }
+"typedef" { return reserved_word(yyscanner); }
+"template" { return reserved_word(yyscanner); }
+"this" { return reserved_word(yyscanner); }
+"packed" { return reserved_word(yyscanner); }
+
+"goto" { return reserved_word(yyscanner); }
+"switch" { return reserved_word(yyscanner); }
+"default" { return reserved_word(yyscanner); }
+
+"inline" { return reserved_word(yyscanner); }
+"noinline" { return reserved_word(yyscanner); }
+"volatile" { return reserved_word(yyscanner); }
+"public" { return reserved_word(yyscanner); }
+"static" { return reserved_word(yyscanner); }
+"extern" { return reserved_word(yyscanner); }
+"external" { return reserved_word(yyscanner); }
+"interface" { return reserved_word(yyscanner); }
+"flat" { return reserved_word(yyscanner); }
+
+"long" { return reserved_word(yyscanner); }
+"short" { return reserved_word(yyscanner); }
+"double" { return reserved_word(yyscanner); }
+"half" { return reserved_word(yyscanner); }
+"fixed" { return reserved_word(yyscanner); }
+"unsigned" { return reserved_word(yyscanner); }
+"superp" { return reserved_word(yyscanner); }
+
+"input" { return reserved_word(yyscanner); }
+"output" { return reserved_word(yyscanner); }
+
+"hvec2" { return reserved_word(yyscanner); }
+"hvec3" { return reserved_word(yyscanner); }
+"hvec4" { return reserved_word(yyscanner); }
+"dvec2" { return reserved_word(yyscanner); }
+"dvec3" { return reserved_word(yyscanner); }
+"dvec4" { return reserved_word(yyscanner); }
+"fvec2" { return reserved_word(yyscanner); }
+"fvec3" { return reserved_word(yyscanner); }
+"fvec4" { return reserved_word(yyscanner); }
+
+"sampler1D" { return reserved_word(yyscanner); }
+"sampler3D" { return reserved_word(yyscanner); }
+
+"sampler1DShadow" { return reserved_word(yyscanner); }
+"sampler2DShadow" { return reserved_word(yyscanner); }
+
+"sampler3DRect" { return reserved_word(yyscanner); }
+"sampler2DRectShadow" { return reserved_word(yyscanner); }
+
+"sizeof" { return reserved_word(yyscanner); }
+"cast" { return reserved_word(yyscanner); }
+
+"namespace" { return reserved_word(yyscanner); }
+"using" { return reserved_word(yyscanner); }
+
+{L}({L}|{D})* {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+
+0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext); context->recover(); return 0;}
+{D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+
+{D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+{D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+"."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+
+"+=" { return(ADD_ASSIGN); }
+"-=" { return(SUB_ASSIGN); }
+"*=" { return(MUL_ASSIGN); }
+"/=" { return(DIV_ASSIGN); }
+"%=" { return(MOD_ASSIGN); }
+"<<=" { return(LEFT_ASSIGN); }
+">>=" { return(RIGHT_ASSIGN); }
+"&=" { return(AND_ASSIGN); }
+"^=" { return(XOR_ASSIGN); }
+"|=" { return(OR_ASSIGN); }
+
+"++" { return(INC_OP); }
+"--" { return(DEC_OP); }
+"&&" { return(AND_OP); }
+"||" { return(OR_OP); }
+"^^" { return(XOR_OP); }
+"<=" { return(LE_OP); }
+">=" { return(GE_OP); }
+"==" { return(EQ_OP); }
+"!=" { return(NE_OP); }
+"<<" { return(LEFT_OP); }
+">>" { return(RIGHT_OP); }
+";" { context->lexAfterType = false; return(SEMICOLON); }
+("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); }
+("}"|"%>") { return(RIGHT_BRACE); }
+"," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); }
+":" { return(COLON); }
+"=" { context->lexAfterType = false; return(EQUAL); }
+"(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); }
+")" { context->inTypeParen = false; return(RIGHT_PAREN); }
+("["|"<:") { return(LEFT_BRACKET); }
+("]"|":>") { return(RIGHT_BRACKET); }
+"." { BEGIN(FIELDS); return(DOT); }
+"!" { return(BANG); }
+"-" { return(DASH); }
+"~" { return(TILDE); }
+"+" { return(PLUS); }
+"*" { return(STAR); }
+"/" { return(SLASH); }
+"%" { return(PERCENT); }
+"<" { return(LEFT_ANGLE); }
+">" { return(RIGHT_ANGLE); }
+"|" { return(VERTICAL_BAR); }
+"^" { return(CARET); }
+"&" { return(AMPERSAND); }
+"?" { return(QUESTION); }
+
+<FIELDS>{L}({L}|{D})* {
+ BEGIN(INITIAL);
+ yylval->lex.string = NewPoolTString(yytext);
+ return FIELD_SELECTION;
+}
+<FIELDS>[ \t\v\f\r] {}
+
+[ \t\v\n\f\r] { }
+<*><<EOF>> { context->AfterEOF = true; yyterminate(); }
+<*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; }
+
+%%
+
+// Old preprocessor interface.
+extern "C" {
+#include "compiler/preprocessor/preprocess.h"
+
+extern int InitPreprocessor();
+extern int FinalizePreprocessor();
+extern void PredefineIntMacro(const char *name, int value);
+
+#define SETUP_CONTEXT(pp) \
+ TParseContext* context = (TParseContext*) pp->pC; \
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+// Preprocessor callbacks.
+void CPPDebugLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->trace(msg);
+}
+
+void CPPWarningToInfoLog(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->warning(yylineno, msg, "");
+}
+
+void CPPShInfoLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "");
+ context->recover();
+}
+
+void CPPErrorToInfoLog(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "");
+ context->recover();
+}
+
+void SetLineNumber(int line)
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+void SetStringNumber(int string)
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+int GetStringNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ return string;
+}
+
+int GetLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ return line;
+}
+
+void IncLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, ++line);
+}
+
+void DecLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, --line);
+}
+
+void HandlePragma(const char **tokens, int numTokens)
+{
+ SETUP_CONTEXT(cpp);
+
+ if (numTokens != 4) return;
+ if (strcmp(tokens[1], "(") != 0) return;
+ if (strcmp(tokens[3], ")") != 0) return;
+
+ context->handlePragmaDirective(yylineno, tokens[0], tokens[2]);
+}
+
+void StoreStr(const char *string)
+{
+ SETUP_CONTEXT(cpp);
+ TString strSrc;
+ strSrc = TString(string);
+
+ context->HashErrMsg = context->HashErrMsg + " " + strSrc;
+}
+
+const char* GetStrfromTStr(void)
+{
+ SETUP_CONTEXT(cpp);
+ cpp->ErrMsg = context->HashErrMsg.c_str();
+ return cpp->ErrMsg;
+}
+
+void ResetTString(void)
+{
+ SETUP_CONTEXT(cpp);
+ context->HashErrMsg = "";
+}
+
+void updateExtensionBehavior(const char* extName, const char* behavior)
+{
+ SETUP_CONTEXT(cpp);
+ context->handleExtensionDirective(yylineno, extName, behavior);
+}
+} // extern "C"
+
+int string_input(char* buf, int max_size, yyscan_t yyscanner) {
+ int len = 0;
+
+#if ANGLE_USE_NEW_PREPROCESSOR
+ pp::Token token;
+ yyget_extra(yyscanner)->preprocessor.lex(&token);
+ len = token.type == pp::Token::LAST ? 0 : token.text.size();
+ if ((len > 0) && (len < max_size))
+ memcpy(buf, token.text.c_str(), len);
+ yyset_lineno(EncodeSourceLoc(token.location.file, token.location.line), yyscanner);
+#else
+ len = yylex_CPP(buf, max_size);
+#endif // ANGLE_USE_NEW_PREPROCESSOR
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext);
+ if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ yyextra->lexAfterType = true;
+ token = TYPE_NAME;
+ }
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(yylineno, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+void yyerror(TParseContext* context, const char* reason) {
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+ if (context->AfterEOF) {
+ context->error(yylineno, reason, "unexpected EOF");
+ } else {
+ context->error(yylineno, reason, yytext);
+ }
+ context->recover();
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context, &scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ yylex_destroy(scanner);
+
+#if !ANGLE_USE_NEW_PREPROCESSOR
+ FinalizePreprocessor();
+#endif
+ return 0;
+}
+
+int glslang_scan(int count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL, context->scanner);
+ yyset_lineno(EncodeSourceLoc(0, 1), context->scanner);
+ context->AfterEOF = false;
+
+ // Initialize preprocessor.
+#if ANGLE_USE_NEW_PREPROCESSOR
+ if (!context->preprocessor.init(count, string, length))
+ return 1;
+#else
+ if (InitPreprocessor())
+ return 1;
+ cpp->pC = context;
+ cpp->pastFirstStatement = 0;
+ if (InitScannerInput(cpp, count, string, length))
+ return 1;
+#endif // ANGLE_USE_NEW_PREPROCESSOR
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+#if ANGLE_USE_NEW_PREPROCESSOR
+ context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+#else
+ PredefineIntMacro(iter->first.c_str(), 1);
+#endif
+ }
+ return 0;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/glslang.y b/src/3rdparty/angle/src/compiler/glslang.y
new file mode 100644
index 0000000000..39c9cee26e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/glslang.y
@@ -0,0 +1,2142 @@
+/*
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Yacc grammar for GLSL ES.
+Based on ANSI C Yacc grammar:
+http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
+*/
+
+%{
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+#include "compiler/SymbolTable.h"
+#include "compiler/ParseHelper.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYLEX_PARAM context->scanner
+%}
+
+%expect 1 /* One shift reduce conflict because of if | else */
+%pure-parser
+%parse-param {TParseContext* context}
+
+%union {
+ struct {
+ TSourceLoc line;
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TSourceLoc line;
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TTypeLine typeLine;
+ TTypeList* typeList;
+ };
+ } interm;
+}
+
+%{
+extern int yylex(YYSTYPE* yylval_param, void* yyscanner);
+extern void yyerror(TParseContext* context, const char* reason);
+
+#define FRAG_VERT_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER && \
+ context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex/fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+%}
+
+%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
+%token <lex> STRUCT VOID_TYPE WHILE
+%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT
+
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT
+%token <lex> FIELD_SELECTION
+%token <lex> LEFT_OP RIGHT_OP
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token <lex> SUB_ASSIGN
+
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+%type <interm> assignment_operator unary_operator
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
+%type <interm.intermTypedNode> expression integer_expression assignment_expression
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
+%type <interm.intermTypedNode> relational_expression equality_expression
+%type <interm.intermTypedNode> conditional_expression constant_expression
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
+%type <interm.intermTypedNode> function_call initializer condition conditionopt
+
+%type <interm.intermNode> translation_unit function_definition
+%type <interm.intermNode> statement simple_statement
+%type <interm.intermAggregate> statement_list compound_statement
+%type <interm.intermNode> declaration_statement selection_statement expression_statement
+%type <interm.intermNode> declaration external_declaration
+%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
+%type <interm.nodePair> selection_rest_statement for_rest_statement
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
+%type <interm> single_declaration init_declarator_list
+
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
+%type <interm.qualifier> parameter_qualifier
+
+%type <interm.precision> precision_qualifier
+%type <interm.type> type_qualifier fully_specified_type type_specifier
+%type <interm.type> type_specifier_no_prec type_specifier_nonarray
+%type <interm.type> struct_specifier
+%type <interm.typeLine> struct_declarator
+%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list
+%type <interm.function> function_header function_declarator function_identifier
+%type <interm.function> function_header_with_parameters function_call_header
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
+%type <interm> function_call_or_method
+
+%start translation_unit
+%%
+
+variable_identifier
+ : IDENTIFIER {
+ // The symbol table search was done in the lexical phase
+ const TSymbol* symbol = $1.symbol;
+ const TVariable* variable;
+ if (symbol == 0) {
+ context->error($1.line, "undeclared identifier", $1.string->c_str());
+ context->recover();
+ TType type(EbtFloat, EbpUndefined);
+ TVariable* fakeVariable = new TVariable($1.string, type);
+ context->symbolTable.insert(*fakeVariable);
+ variable = fakeVariable;
+ } else {
+ // This identifier can only be a variable type symbol
+ if (! symbol->isVariable()) {
+ context->error($1.line, "variable expected", $1.string->c_str());
+ context->recover();
+ }
+ variable = static_cast<const TVariable*>(symbol);
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+
+ if (variable->getType().getQualifier() == EvqConst ) {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ $$ = context->intermediate.addConstantUnion(constArray, t, $1.line);
+ } else
+ $$ = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), $1.line);
+ }
+ ;
+
+primary_expression
+ : variable_identifier {
+ $$ = $1;
+ }
+ | INTCONSTANT {
+ //
+ // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders,
+ // check for overflow for constants
+ //
+ if (abs($1.i) >= (1 << 16)) {
+ context->error($1.line, " integer constant overflow", "");
+ context->recover();
+ }
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst($1.i);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $1.line);
+ }
+ | FLOATCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst($1.f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line);
+ }
+ | BOOLCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst($1.b);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $1.line);
+ }
+ | LEFT_PAREN expression RIGHT_PAREN {
+ $$ = $2;
+ }
+ ;
+
+postfix_expression
+ : primary_expression {
+ $$ = $1;
+ }
+ | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
+ if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {
+ if ($1->getAsSymbolNode())
+ context->error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str());
+ else
+ context->error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression");
+ context->recover();
+ }
+ if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) {
+ if ($1->isArray()) { // constant folding for arrays
+ $$ = context->addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
+ } else if ($1->isVector()) { // constant folding for vectors
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
+ $$ = context->addConstVectorNode(fields, $1, $2.line);
+ } else if ($1->isMatrix()) { // constant folding for matrices
+ $$ = context->addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
+ }
+ } else {
+ if ($3->getQualifier() == EvqConst) {
+ if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "field selection out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ context->error($2.line, "", "[", extraInfo.c_str());
+ context->recover();
+ } else {
+ if ($1->isArray()) {
+ if ($1->getType().getArraySize() == 0) {
+ if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) {
+ if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line))
+ context->recover();
+ } else {
+ if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line))
+ context->recover();
+ }
+ } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array index out of range '" << $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ context->error($2.line, "", "[", extraInfo.c_str());
+ context->recover();
+ }
+ }
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line);
+ }
+ } else {
+ if ($1->isArray() && $1->getType().getArraySize() == 0) {
+ context->error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable");
+ context->recover();
+ }
+
+ $$ = context->intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line);
+ }
+ }
+ if ($$ == 0) {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), $2.line);
+ } else if ($1->isArray()) {
+ if ($1->getType().getStruct())
+ $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName()));
+ else
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize(), $1->isMatrix()));
+
+ if ($1->getType().getQualifier() == EvqConst)
+ $$->getTypePointer()->setQualifier(EvqConst);
+ } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst)
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, $1->getNominalSize()));
+ else if ($1->isMatrix())
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize()));
+ else if ($1->isVector() && $1->getType().getQualifier() == EvqConst)
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst));
+ else if ($1->isVector())
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary));
+ else
+ $$->setType($1->getType());
+ }
+ | function_call {
+ $$ = $1;
+ }
+ | postfix_expression DOT FIELD_SELECTION {
+ if ($1->isArray()) {
+ context->error($3.line, "cannot apply dot operator to an array", ".");
+ context->recover();
+ }
+
+ if ($1->isVector()) {
+ TVectorFields fields;
+ if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ context->recover();
+ }
+
+ if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields
+ $$ = context->addConstVectorNode(fields, $1, $3.line);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size()));
+ } else {
+ TString vectorString = *$3.string;
+ TIntermTyped* index = context->intermediate.addSwizzle(fields, $3.line);
+ $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ } else if ($1->isMatrix()) {
+ TMatrixFields fields;
+ if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ context->recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol) {
+ context->error($2.line, " non-scalar fields not implemented yet", ".");
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize()));
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision()));
+ }
+ } else if ($1->getBasicType() == EbtStruct) {
+ bool fieldFound = false;
+ const TTypeList* fields = $1->getType().getStruct();
+ if (fields == 0) {
+ context->error($2.line, "structure has no fields", "Internal Error");
+ context->recover();
+ $$ = $1;
+ } else {
+ unsigned int i;
+ for (i = 0; i < fields->size(); ++i) {
+ if ((*fields)[i].type->getFieldName() == *$3.string) {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound) {
+ if ($1->getType().getQualifier() == EvqConst) {
+ $$ = context->addConstStruct(*$3.string, $1, $2.line);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else {
+ $$->setType(*(*fields)[i].type);
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ $$->getTypePointer()->setQualifier(EvqConst);
+ }
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line);
+ $$->setType(*(*fields)[i].type);
+ }
+ } else {
+ context->error($2.line, " no such field in structure", $3.string->c_str());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ } else {
+ context->error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str());
+ context->recover();
+ $$ = $1;
+ }
+ // don't delete $3.string, it's from the pool
+ }
+ | postfix_expression INC_OP {
+ if (context->lValueErrorCheck($2.line, "++", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($2.line, "++", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | postfix_expression DEC_OP {
+ if (context->lValueErrorCheck($2.line, "--", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($2.line, "--", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+integer_expression
+ : expression {
+ if (context->integerErrorCheck($1, "[]"))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+function_call
+ : function_call_or_method {
+ TFunction* fnCall = $1.function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) {
+ $$ = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ $$ = context->addConstructor($1.intermNode, &type, op, fnCall, $1.line);
+ }
+
+ if ($$ == 0) {
+ context->recover();
+ $$ = context->intermediate.setAggregateOperator(0, op, $1.line);
+ }
+ $$->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction($1.line, fnCall, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck($1.line, fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ $$ = context->intermediate.addUnaryMath(op, $1.intermNode, 0, context->symbolTable);
+ if ($$ == 0) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ YYERROR;
+ }
+ } else {
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, $1.line);
+ }
+ } else {
+ // This is a real function call
+
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line);
+ $$->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ $$->getAsAggregate()->setUserDefined();
+ $$->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ context->recover();
+ }
+ }
+ }
+ }
+ $$->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line);
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ ;
+
+function_call_or_method
+ : function_call_generic {
+ $$ = $1;
+ }
+ | postfix_expression DOT function_call_generic {
+ context->error($3.line, "methods are not supported", "");
+ context->recover();
+ $$ = $3;
+ }
+ ;
+
+function_call_generic
+ : function_call_header_with_parameters RIGHT_PAREN {
+ $$ = $1;
+ $$.line = $2.line;
+ }
+ | function_call_header_no_parameters RIGHT_PAREN {
+ $$ = $1;
+ $$.line = $2.line;
+ }
+ ;
+
+function_call_header_no_parameters
+ : function_call_header VOID_TYPE {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ | function_call_header {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ ;
+
+function_call_header_with_parameters
+ : function_call_header assignment_expression {
+ TParameter param = { 0, new TType($2->getType()) };
+ $1->addParameter(param);
+ $$.function = $1;
+ $$.intermNode = $2;
+ }
+ | function_call_header_with_parameters COMMA assignment_expression {
+ TParameter param = { 0, new TType($3->getType()) };
+ $1.function->addParameter(param);
+ $$.function = $1.function;
+ $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, $2.line);
+ }
+ ;
+
+function_call_header
+ : function_identifier LEFT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+// Grammar Note: Constructors look like functions, but are recognized as types.
+
+function_identifier
+ : type_specifier_nonarray {
+ //
+ // Constructor
+ //
+ TOperator op = EOpNull;
+ if ($1.userDef) {
+ op = EOpConstructStruct;
+ } else {
+ switch ($1.type) {
+ case EbtFloat:
+ if ($1.matrix) {
+ switch($1.size) {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ } else {
+ switch($1.size) {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+ case EbtInt:
+ switch($1.size) {
+ case 1: op = EOpConstructInt; break;
+ case 2: FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break;
+ case 3: FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break;
+ case 4: FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break;
+ }
+ break;
+ case EbtBool:
+ switch($1.size) {
+ case 1: op = EOpConstructBool; break;
+ case 2: FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break;
+ case 3: FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break;
+ case 4: FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break;
+ }
+ break;
+ default: break;
+ }
+ if (op == EOpNull) {
+ context->error($1.line, "cannot construct this type", getBasicString($1.type));
+ context->recover();
+ $1.type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+ TString tempString;
+ TType type($1);
+ TFunction *function = new TFunction(&tempString, type, op);
+ $$ = function;
+ }
+ | IDENTIFIER {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ | FIELD_SELECTION {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ ;
+
+unary_expression
+ : postfix_expression {
+ $$ = $1;
+ }
+ | INC_OP unary_expression {
+ if (context->lValueErrorCheck($1.line, "++", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($1.line, "++", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | DEC_OP unary_expression {
+ if (context->lValueErrorCheck($1.line, "--", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($1.line, "--", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | unary_operator unary_expression {
+ if ($1.op != EOpNull) {
+ $$ = context->intermediate.addUnaryMath($1.op, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ const char* errorOp = "";
+ switch($1.op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError($1.line, errorOp, $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ } else
+ $$ = $2;
+ }
+ ;
+// Grammar Note: No traditional style type casts.
+
+unary_operator
+ : PLUS { $$.line = $1.line; $$.op = EOpNull; }
+ | DASH { $$.line = $1.line; $$.op = EOpNegative; }
+ | BANG { $$.line = $1.line; $$.op = EOpLogicalNot; }
+ ;
+// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+
+multiplicative_expression
+ : unary_expression { $$ = $1; }
+ | multiplicative_expression STAR unary_expression {
+ FRAG_VERT_ONLY("*", $2.line);
+ $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | multiplicative_expression SLASH unary_expression {
+ FRAG_VERT_ONLY("/", $2.line);
+ $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression { $$ = $1; }
+ | additive_expression PLUS multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | additive_expression DASH multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+shift_expression
+ : additive_expression { $$ = $1; }
+ ;
+
+relational_expression
+ : shift_expression { $$ = $1; }
+ | relational_expression LEFT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression RIGHT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression LE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression GE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+equality_expression
+ : relational_expression { $$ = $1; }
+ | equality_expression EQ_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | equality_expression NE_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+and_expression
+ : equality_expression { $$ = $1; }
+ ;
+
+exclusive_or_expression
+ : and_expression { $$ = $1; }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression { $$ = $1; }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression { $$ = $1; }
+ | logical_and_expression AND_OP inclusive_or_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+logical_xor_expression
+ : logical_and_expression { $$ = $1; }
+ | logical_xor_expression XOR_OP logical_and_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+logical_or_expression
+ : logical_xor_expression { $$ = $1; }
+ | logical_or_expression OR_OP logical_xor_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression { $$ = $1; }
+ | logical_or_expression QUESTION expression COLON assignment_expression {
+ if (context->boolErrorCheck($2.line, $1))
+ context->recover();
+
+ $$ = context->intermediate.addSelection($1, $3, $5, $2.line);
+ if ($3->getType() != $5->getType())
+ $$ = 0;
+
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString());
+ context->recover();
+ $$ = $5;
+ }
+ }
+ ;
+
+assignment_expression
+ : conditional_expression { $$ = $1; }
+ | unary_expression assignment_operator assignment_expression {
+ if (context->lValueErrorCheck($2.line, "assign", $1))
+ context->recover();
+ $$ = context->intermediate.addAssign($2.op, $1, $3, $2.line);
+ if ($$ == 0) {
+ context->assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+assignment_operator
+ : EQUAL { $$.line = $1.line; $$.op = EOpAssign; }
+ | MUL_ASSIGN { FRAG_VERT_ONLY("*=", $1.line); $$.line = $1.line; $$.op = EOpMulAssign; }
+ | DIV_ASSIGN { FRAG_VERT_ONLY("/=", $1.line); $$.line = $1.line; $$.op = EOpDivAssign; }
+ | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; }
+ | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; }
+ ;
+
+expression
+ : assignment_expression {
+ $$ = $1;
+ }
+ | expression COMMA assignment_expression {
+ $$ = context->intermediate.addComma($1, $3, $2.line);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $3;
+ }
+ }
+ ;
+
+constant_expression
+ : conditional_expression {
+ if (context->constErrorCheck($1))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+declaration
+ : function_prototype SEMICOLON {
+ TFunction &function = *($1.function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (int i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable *variable = new TVariable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), $1.line), $1.line);
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ $$ = prototype;
+
+ context->symbolTable.pop();
+ }
+ | init_declarator_list SEMICOLON {
+ if ($1.intermAggregate)
+ $1.intermAggregate->setOp(EOpDeclaration);
+ $$ = $1.intermAggregate;
+ }
+ | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
+ context->symbolTable.setDefaultPrecision( $3.type, $2 );
+ $$ = 0;
+ }
+ ;
+
+function_prototype
+ : function_declarator RIGHT_PAREN {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName()));
+ if (prevDec) {
+ if (prevDec->getReturnType() != $1->getReturnType()) {
+ context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
+ context->recover();
+ }
+ for (int i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
+ context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ $$.function = $1;
+ $$.line = $2.line;
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ context->symbolTable.getOuterLevel()->insert(*$$.function);
+ }
+ ;
+
+function_declarator
+ : function_header {
+ $$ = $1;
+ }
+ | function_header_with_parameters {
+ $$ = $1;
+ }
+ ;
+
+
+function_header_with_parameters
+ : function_header parameter_declaration {
+ // Add the parameter
+ $$ = $1;
+ if ($2.param.type->getBasicType() != EbtVoid)
+ $1->addParameter($2.param);
+ else
+ delete $2.param.type;
+ }
+ | function_header_with_parameters COMMA parameter_declaration {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ($3.param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error($2.line, "cannot be an argument type except for '(void)'", "void");
+ context->recover();
+ delete $3.param.type;
+ } else {
+ // Add the parameter
+ $$ = $1;
+ $1->addParameter($3.param);
+ }
+ }
+ ;
+
+function_header
+ : fully_specified_type IDENTIFIER LEFT_PAREN {
+ if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
+ context->error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type($1);
+ function = new TFunction($2.string, type);
+ $$ = function;
+
+ context->symbolTable.push();
+ }
+ ;
+
+parameter_declarator
+ // Type + name
+ : type_specifier IDENTIFIER {
+ if ($1.type == EbtVoid) {
+ context->error($2.line, "illegal use of type 'void'", $2.string->c_str());
+ context->recover();
+ }
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+ TParameter param = {$2.string, new TType($1)};
+ $$.line = $2.line;
+ $$.param = param;
+ }
+ | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck($3.line, $1))
+ context->recover();
+
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck($3.line, $4, size))
+ context->recover();
+ $1.setArray(true, size);
+
+ TType* type = new TType($1);
+ TParameter param = { $2.string, type };
+ $$.line = $2.line;
+ $$.param = param;
+ }
+ ;
+
+parameter_declaration
+ //
+ // The only parameter qualifier a parameter can have are
+ // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
+ //
+
+ //
+ // Type + name
+ //
+ : type_qualifier parameter_qualifier parameter_declarator {
+ $$ = $3;
+ if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_declarator {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ //
+ // Only type
+ //
+ | type_qualifier parameter_qualifier parameter_type_specifier {
+ $$ = $3;
+ if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_type_specifier {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ ;
+
+parameter_qualifier
+ : /* empty */ {
+ $$ = EvqIn;
+ }
+ | IN_QUAL {
+ $$ = EvqIn;
+ }
+ | OUT_QUAL {
+ $$ = EvqOut;
+ }
+ | INOUT_QUAL {
+ $$ = EvqInOut;
+ }
+ ;
+
+parameter_type_specifier
+ : type_specifier {
+ TParameter param = { 0, new TType($1) };
+ $$.param = param;
+ }
+ ;
+
+init_declarator_list
+ : single_declaration {
+ $$ = $1;
+ }
+ | init_declarator_list COMMA IDENTIFIER {
+ if ($1.type.type == EbtInvariant && !$3.symbol)
+ {
+ context->error($3.line, "undeclared identifier declared as invariant", $3.string->c_str());
+ context->recover();
+ }
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, $3.line);
+
+ if (context->structQualifierErrorCheck($3.line, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $$.type, false))
+ context->recover();
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck($3.line, *$3.string, $$.type, variable))
+ context->recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+ }
+ | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
+ context->recover();
+ else {
+ $1.type.setArray(true);
+ TVariable* variable;
+ if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
+ context->recover();
+ }
+ }
+ | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type, true))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($4.line, $5, size))
+ context->recover();
+ $1.type.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
+ context->recover();
+ TType type = TType($1.type);
+ type.setArraySize(size);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, $3.line), $3.line);
+ }
+ }
+ | init_declarator_list COMMA IDENTIFIER EQUAL initializer {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ $$ = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, $4.line);
+ else
+ $$.intermAggregate = $1.intermAggregate;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ ;
+
+single_declaration
+ : fully_specified_type {
+ $$.type = $1;
+ $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), $1.line), $1.line);
+ }
+ | fully_specified_type IDENTIFIER {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+
+ if (context->structQualifierErrorCheck($2.line, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($2.line, *$2.string, $$.type, false))
+ context->recover();
+
+ $$.type = $1;
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck($2.line, *$2.string, $$.type, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
+ context->error($2.line, "unsized array declarations not supported", $2.string->c_str());
+ context->recover();
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+ $$.type = $1;
+ }
+ | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ TType type = TType($1);
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $4, size))
+ context->recover();
+ type.setArraySize(size);
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($2.line, *$2.string, $1, true))
+ context->recover();
+
+ $$.type = $1;
+
+ if (context->arrayTypeErrorCheck($3.line, $1) || context->arrayQualifierErrorCheck($3.line, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($3.line, $4, size))
+ context->recover();
+
+ $1.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck($3.line, *$2.string, $1, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ }
+ | fully_specified_type IDENTIFIER EQUAL initializer {
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ $$.type = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) {
+ //
+ // Build intermediate representation
+ //
+ if(intermNode)
+ $$.intermAggregate = context->intermediate.makeAggregate(intermNode, $3.line);
+ else
+ $$.intermAggregate = 0;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ | INVARIANT IDENTIFIER {
+ VERTEX_ONLY("invariant declaration", $1.line);
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, $2.line);
+ if (!$2.symbol)
+ {
+ context->error($2.line, "undeclared identifier declared as invariant", $2.string->c_str());
+ context->recover();
+
+ $$.intermAggregate = 0;
+ }
+ else
+ {
+ TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+ }
+ }
+
+//
+// Place holder for the pack/unpack languages.
+//
+// | buffer_specifier {
+// $$.intermAggregate = 0;
+// }
+ ;
+
+// Grammar Note: No 'enum', or 'typedef'.
+
+//
+// Place holder for the pack/unpack languages.
+//
+//%type <interm> buffer_declaration
+//%type <interm.type> buffer_specifier input_or_output buffer_declaration_list
+//buffer_specifier
+// : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE {
+// }
+// ;
+//
+//input_or_output
+// : INPUT {
+// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "input"))
+// context->recover();
+// UNPACK_ONLY("input", $1.line);
+// $$.qualifier = EvqInput;
+// }
+// | OUTPUT {
+// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "output"))
+// context->recover();
+// PACK_ONLY("output", $1.line);
+// $$.qualifier = EvqOutput;
+// }
+// ;
+
+//
+// Place holder for the pack/unpack languages.
+//
+//buffer_declaration_list
+// : buffer_declaration {
+// }
+// | buffer_declaration_list buffer_declaration {
+// }
+// ;
+
+//
+// Input/output semantics:
+// float must be 16 or 32 bits
+// float alignment restrictions?
+// check for only one input and only one output
+// sum of bitfields has to be multiple of 32
+//
+
+//
+// Place holder for the pack/unpack languages.
+//
+//buffer_declaration
+// : type_specifier IDENTIFIER COLON constant_expression SEMICOLON {
+// if (context->reservedErrorCheck($2.line, *$2.string, context))
+// context->recover();
+// $$.variable = new TVariable($2.string, $1);
+// if (! context->symbolTable.insert(*$$.variable)) {
+// context->error($2.line, "redefinition", $$.variable->getName().c_str());
+// context->recover();
+// // don't have to delete $$.variable, the pool pop will take care of it
+// }
+// }
+// ;
+
+fully_specified_type
+ : type_specifier {
+ $$ = $1;
+
+ if ($1.array) {
+ context->error($1.line, "not supported", "first-class array");
+ context->recover();
+ $1.setArray(false);
+ }
+ }
+ | type_qualifier type_specifier {
+ if ($2.array) {
+ context->error($2.line, "not supported", "first-class array");
+ context->recover();
+ $2.setArray(false);
+ }
+
+ if ($1.qualifier == EvqAttribute &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ $$ = $2;
+ $$.qualifier = $1.qualifier;
+ }
+ ;
+
+type_qualifier
+ : CONST_QUAL {
+ $$.setBasic(EbtVoid, EvqConst, $1.line);
+ }
+ | ATTRIBUTE {
+ VERTEX_ONLY("attribute", $1.line);
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqAttribute, $1.line);
+ }
+ | VARYING {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqVaryingOut, $1.line);
+ else
+ $$.setBasic(EbtVoid, EvqVaryingIn, $1.line);
+ }
+ | INVARIANT VARYING {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqInvariantVaryingOut, $1.line);
+ else
+ $$.setBasic(EbtVoid, EvqInvariantVaryingIn, $1.line);
+ }
+ | UNIFORM {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqUniform, $1.line);
+ }
+ ;
+
+type_specifier
+ : type_specifier_no_prec {
+ $$ = $1;
+
+ if ($$.precision == EbpUndefined) {
+ $$.precision = context->symbolTable.getDefaultPrecision($1.type);
+ if (context->precisionErrorCheck($1.line, $$.precision, $1.type)) {
+ context->recover();
+ }
+ }
+ }
+ | precision_qualifier type_specifier_no_prec {
+ $$ = $2;
+ $$.precision = $1;
+ }
+ ;
+
+precision_qualifier
+ : HIGH_PRECISION {
+ $$ = EbpHigh;
+ }
+ | MEDIUM_PRECISION {
+ $$ = EbpMedium;
+ }
+ | LOW_PRECISION {
+ $$ = EbpLow;
+ }
+ ;
+
+type_specifier_no_prec
+ : type_specifier_nonarray {
+ $$ = $1;
+ }
+ | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($2.line, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $3, size))
+ context->recover();
+ $$.setArray(true, size);
+ }
+ }
+ ;
+
+type_specifier_nonarray
+ : VOID_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtVoid, qual, $1.line);
+ }
+ | FLOAT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ }
+ | INT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ }
+ | BOOL_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ }
+// | UNSIGNED INT_TYPE {
+// PACK_UNPACK_ONLY("unsigned", $1.line);
+// TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+// $$.setBasic(EbtInt, qual, $1.line);
+// }
+ | VEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | VEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | VEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | BVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | BVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | BVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | IVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | IVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | IVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | MATRIX2 {
+ FRAG_VERT_ONLY("mat2", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(2, true);
+ }
+ | MATRIX3 {
+ FRAG_VERT_ONLY("mat3", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(3, true);
+ }
+ | MATRIX4 {
+ FRAG_VERT_ONLY("mat4", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(4, true);
+ }
+ | SAMPLER2D {
+ FRAG_VERT_ONLY("sampler2D", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2D, qual, $1.line);
+ }
+ | SAMPLERCUBE {
+ FRAG_VERT_ONLY("samplerCube", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerCube, qual, $1.line);
+ }
+ | SAMPLER_EXTERNAL_OES {
+ if (!context->supportsExtension("GL_OES_EGL_image_external")) {
+ context->error($1.line, "unsupported type", "samplerExternalOES");
+ context->recover();
+ }
+ FRAG_VERT_ONLY("samplerExternalOES", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerExternalOES, qual, $1.line);
+ }
+ | SAMPLER2DRECT {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error($1.line, "unsupported type", "sampler2DRect");
+ context->recover();
+ }
+ FRAG_VERT_ONLY("sampler2DRect", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DRect, qual, $1.line);
+ }
+ | struct_specifier {
+ FRAG_VERT_ONLY("struct", $1.line);
+ $$ = $1;
+ $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ | TYPE_NAME {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>($1.symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtStruct, qual, $1.line);
+ $$.userDef = &structure;
+ }
+ ;
+
+struct_specifier
+ : STRUCT IDENTIFIER LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+
+ TType* structure = new TType($5, *$2.string);
+ TVariable* userTypeDef = new TVariable($2.string, *structure, true);
+ if (! context->symbolTable.insert(*userTypeDef)) {
+ context->error($2.line, "redefinition", $2.string->c_str(), "struct");
+ context->recover();
+ }
+ $$.setBasic(EbtStruct, EvqTemporary, $1.line);
+ $$.userDef = structure;
+ context->exitStructDeclaration();
+ }
+ | STRUCT LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ TType* structure = new TType($4, TString(""));
+ $$.setBasic(EbtStruct, EvqTemporary, $1.line);
+ $$.userDef = structure;
+ context->exitStructDeclaration();
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration {
+ $$ = $1;
+ }
+ | struct_declaration_list struct_declaration {
+ $$ = $1;
+ for (unsigned int i = 0; i < $2->size(); ++i) {
+ for (unsigned int j = 0; j < $$->size(); ++j) {
+ if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) {
+ context->error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str());
+ context->recover();
+ }
+ }
+ $$->push_back((*$2)[i]);
+ }
+ }
+ ;
+
+struct_declaration
+ : type_specifier struct_declarator_list SEMICOLON {
+ $$ = $2;
+
+ if (context->voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) {
+ context->recover();
+ }
+ for (unsigned int i = 0; i < $$->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*$$)[i].type;
+ type->setBasicType($1.type);
+ type->setNominalSize($1.size);
+ type->setMatrix($1.matrix);
+ type->setPrecision($1.precision);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (context->arrayTypeErrorCheck($1.line, $1))
+ context->recover();
+ }
+ if ($1.array)
+ type->setArraySize($1.arraySize);
+ if ($1.userDef) {
+ type->setStruct($1.userDef->getStruct());
+ type->setTypeName($1.userDef->getTypeName());
+ }
+
+ if (context->structNestingErrorCheck($1.line, *type)) {
+ context->recover();
+ }
+ }
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator {
+ $$ = NewPoolTTypeList();
+ $$->push_back($1);
+ }
+ | struct_declarator_list COMMA struct_declarator {
+ $$->push_back($3);
+ }
+ ;
+
+struct_declarator
+ : IDENTIFIER {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+
+ $$.type = new TType(EbtVoid, EbpUndefined);
+ $$.line = $1.line;
+ $$.type->setFieldName(*$1.string);
+ }
+ | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+
+ $$.type = new TType(EbtVoid, EbpUndefined);
+ $$.line = $1.line;
+ $$.type->setFieldName(*$1.string);
+
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $3, size))
+ context->recover();
+ $$.type->setArraySize(size);
+ }
+ ;
+
+initializer
+ : assignment_expression { $$ = $1; }
+ ;
+
+declaration_statement
+ : declaration { $$ = $1; }
+ ;
+
+statement
+ : compound_statement { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+// Grammar Note: No labeled statements; 'goto' is not supported.
+
+simple_statement
+ : declaration_statement { $$ = $1; }
+ | expression_statement { $$ = $1; }
+ | selection_statement { $$ = $1; }
+ | iteration_statement { $$ = $1; }
+ | jump_statement { $$ = $1; }
+ ;
+
+compound_statement
+ : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
+ | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
+ if ($3 != 0) {
+ $3->setOp(EOpSequence);
+ $3->setEndLine($5.line);
+ }
+ $$ = $3;
+ }
+ ;
+
+statement_no_new_scope
+ : compound_statement_no_new_scope { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+statement_with_scope
+ : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; }
+ | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; }
+ ;
+
+compound_statement_no_new_scope
+ // Statement that doesn't create a new scope, for selection_statement, iteration_statement
+ : LEFT_BRACE RIGHT_BRACE {
+ $$ = 0;
+ }
+ | LEFT_BRACE statement_list RIGHT_BRACE {
+ if ($2) {
+ $2->setOp(EOpSequence);
+ $2->setEndLine($3.line);
+ }
+ $$ = $2;
+ }
+ ;
+
+statement_list
+ : statement {
+ $$ = context->intermediate.makeAggregate($1, 0);
+ }
+ | statement_list statement {
+ $$ = context->intermediate.growAggregate($1, $2, 0);
+ }
+ ;
+
+expression_statement
+ : SEMICOLON { $$ = 0; }
+ | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
+ ;
+
+selection_statement
+ : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
+ if (context->boolErrorCheck($1.line, $3))
+ context->recover();
+ $$ = context->intermediate.addSelection($3, $5, $1.line);
+ }
+ ;
+
+selection_rest_statement
+ : statement_with_scope ELSE statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ | statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ ;
+
+// Grammar Note: No 'switch'. Switch statements not supported.
+
+condition
+ // In 1996 c++ draft, conditions can include single declarations
+ : expression {
+ $$ = $1;
+ if (context->boolErrorCheck($1->getLine(), $1))
+ context->recover();
+ }
+ | fully_specified_type IDENTIFIER EQUAL initializer {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+ if (context->boolErrorCheck($2.line, $1))
+ context->recover();
+
+ if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode))
+ $$ = $4;
+ else {
+ context->recover();
+ $$ = 0;
+ }
+ }
+ ;
+
+iteration_statement
+ : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, $1.line);
+ --context->loopNestingLevel;
+ }
+ | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ if (context->boolErrorCheck($8.line, $6))
+ context->recover();
+
+ $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, $4.line);
+ --context->loopNestingLevel;
+ }
+ | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, $1.line);
+ --context->loopNestingLevel;
+ }
+ ;
+
+for_init_statement
+ : expression_statement {
+ $$ = $1;
+ }
+ | declaration_statement {
+ $$ = $1;
+ }
+ ;
+
+conditionopt
+ : condition {
+ $$ = $1;
+ }
+ | /* May be null */ {
+ $$ = 0;
+ }
+ ;
+
+for_rest_statement
+ : conditionopt SEMICOLON {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ | conditionopt SEMICOLON expression {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ ;
+
+jump_statement
+ : CONTINUE SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error($1.line, "continue statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpContinue, $1.line);
+ }
+ | BREAK SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error($1.line, "break statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpBreak, $1.line);
+ }
+ | RETURN SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $1.line);
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error($1.line, "non-void function must return a value", "return");
+ context->recover();
+ }
+ }
+ | RETURN expression SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $2, $1.line);
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error($1.line, "void function cannot return a value", "return");
+ context->recover();
+ } else if (*(context->currentFunctionType) != $2->getType()) {
+ context->error($1.line, "function return is not matching type:", "return");
+ context->recover();
+ }
+ }
+ | DISCARD SEMICOLON {
+ FRAG_ONLY("discard", $1.line);
+ $$ = context->intermediate.addBranch(EOpKill, $1.line);
+ }
+ ;
+
+// Grammar Note: No 'goto'. Gotos are not supported.
+
+translation_unit
+ : external_declaration {
+ $$ = $1;
+ context->treeRoot = $$;
+ }
+ | translation_unit external_declaration {
+ $$ = context->intermediate.growAggregate($1, $2, 0);
+ context->treeRoot = $$;
+ }
+ ;
+
+external_declaration
+ : function_definition {
+ $$ = $1;
+ }
+ | declaration {
+ $$ = $1;
+ }
+ ;
+
+function_definition
+ : function_prototype {
+ TFunction* function = $1.function;
+
+ const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName());
+
+ if (builtIn)
+ {
+ context->error($1.line, "built-in functions cannot be redefined", function->getName().c_str());
+ context->recover();
+ }
+
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error($1.line, "function already has a body", function->getName().c_str());
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error($1.line, "function cannot take any parameter(s)", function->getName().c_str());
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error($1.line, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (int i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.insert(*variable)) {
+ context->error($1.line, "redefinition", variable->getName().c_str());
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), $1.line),
+ $1.line);
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line);
+ $1.intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ compound_statement_no_new_scope {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error($1.line, "function does not return a value:", "", $1.function->getName().c_str());
+ context->recover();
+ }
+
+ $$ = context->intermediate.growAggregate($1.intermAggregate, $3, 0);
+ context->intermediate.setAggregateOperator($$, EOpFunction, $1.line);
+ $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
+ $$->getAsAggregate()->setType($1.function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ $$->getAsAggregate()->setOptimize(context->pragma().optimize);
+ $$->getAsAggregate()->setDebug(context->pragma().debug);
+
+ if ($3 && $3->getAsAggregate())
+ $$->getAsAggregate()->setEndLine($3->getAsAggregate()->getEndLine());
+
+ context->symbolTable.pop();
+ }
+ ;
+
+%%
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
+
diff --git a/src/3rdparty/angle/src/compiler/intermOut.cpp b/src/3rdparty/angle/src/compiler/intermOut.cpp
new file mode 100644
index 0000000000..e83c7b72f2
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/intermOut.cpp
@@ -0,0 +1,419 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/localintermediate.h"
+
+//
+// Two purposes:
+// 1. Show an example of how to iterate tree. Functions can
+// also directly call Traverse() on children themselves to
+// have finer grained control over the process than shown here.
+// See the last function for how to get started.
+// 2. Print out a text based description of the tree.
+//
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TOutputTraverser : public TIntermTraverser {
+public:
+ TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
+ TInfoSinkBase& sink;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+};
+
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " " << getPrecisionString() << " ";
+ if (array)
+ stream << "array of ";
+ if (matrix)
+ stream << size << "X" << size << " matrix of ";
+ else if (size > 1)
+ stream << size << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
+//
+// Helper functions for printing, not part of traversing.
+//
+
+void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
+{
+ int i;
+
+ sink.location(node->getLine());
+
+ for (i = 0; i < depth; ++i)
+ sink << " ";
+}
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol* node)
+{
+ OutputTreeText(sink, node, depth);
+
+ sink << "'" << node->getSymbol() << "' ";
+ sink << "(" << node->getCompleteString() << ")\n";
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpAssign: out << "move second child to first child"; break;
+ case EOpInitialize: out << "initialize first child with second child"; break;
+ case EOpAddAssign: out << "add second child into first child"; break;
+ case EOpSubAssign: out << "subtract second child into first child"; break;
+ case EOpMulAssign: out << "multiply second child into first child"; break;
+ case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break;
+ case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break;
+ case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpDivAssign: out << "divide second child into first child"; break;
+ case EOpIndexDirect: out << "direct index"; break;
+ case EOpIndexIndirect: out << "indirect index"; break;
+ case EOpIndexDirectStruct: out << "direct index for structure"; break;
+ case EOpVectorSwizzle: out << "vector swizzle"; break;
+
+ case EOpAdd: out << "add"; break;
+ case EOpSub: out << "subtract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+ case EOpDiv: out << "divide"; break;
+ case EOpEqual: out << "Compare Equal"; break;
+ case EOpNotEqual: out << "Compare Not Equal"; break;
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+
+ case EOpVectorTimesScalar: out << "vector-scale"; break;
+ case EOpVectorTimesMatrix: out << "vector-times-matrix"; break;
+ case EOpMatrixTimesVector: out << "matrix-times-vector"; break;
+ case EOpMatrixTimesScalar: out << "matrix-scale"; break;
+ case EOpMatrixTimesMatrix: out << "matrix-multiply"; break;
+
+ case EOpLogicalOr: out << "logical-or"; break;
+ case EOpLogicalXor: out << "logical-xor"; break;
+ case EOpLogicalAnd: out << "logical-and"; break;
+ default: out << "<unknown op>";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpNegative: out << "Negate value"; break;
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot: out << "Negate conditional"; break;
+
+ case EOpPostIncrement: out << "Post-Increment"; break;
+ case EOpPostDecrement: out << "Post-Decrement"; break;
+ case EOpPreIncrement: out << "Pre-Increment"; break;
+ case EOpPreDecrement: out << "Pre-Decrement"; break;
+
+ case EOpConvIntToBool: out << "Convert int to bool"; break;
+ case EOpConvFloatToBool:out << "Convert float to bool";break;
+ case EOpConvBoolToFloat:out << "Convert bool to float";break;
+ case EOpConvIntToFloat: out << "Convert int to float"; break;
+ case EOpConvFloatToInt: out << "Convert float to int"; break;
+ case EOpConvBoolToInt: out << "Convert bool to int"; break;
+
+ case EOpRadians: out << "radians"; break;
+ case EOpDegrees: out << "degrees"; break;
+ case EOpSin: out << "sine"; break;
+ case EOpCos: out << "cosine"; break;
+ case EOpTan: out << "tangent"; break;
+ case EOpAsin: out << "arc sine"; break;
+ case EOpAcos: out << "arc cosine"; break;
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpExp: out << "exp"; break;
+ case EOpLog: out << "log"; break;
+ case EOpExp2: out << "exp2"; break;
+ case EOpLog2: out << "log2"; break;
+ case EOpSqrt: out << "sqrt"; break;
+ case EOpInverseSqrt: out << "inverse sqrt"; break;
+
+ case EOpAbs: out << "Absolute value"; break;
+ case EOpSign: out << "Sign"; break;
+ case EOpFloor: out << "Floor"; break;
+ case EOpCeil: out << "Ceiling"; break;
+ case EOpFract: out << "Fraction"; break;
+
+ case EOpLength: out << "length"; break;
+ case EOpNormalize: out << "normalize"; break;
+ // case EOpDPdx: out << "dPdx"; break;
+ // case EOpDPdy: out << "dPdy"; break;
+ // case EOpFwidth: out << "fwidth"; break;
+
+ case EOpAny: out << "any"; break;
+ case EOpAll: out << "all"; break;
+
+ default: out.message(EPrefixError, "Bad unary op");
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ TInfoSinkBase& out = sink;
+
+ if (node->getOp() == EOpNull) {
+ out.message(EPrefixError, "node is still EOpNull!");
+ return true;
+ }
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpSequence: out << "Sequence\n"; return true;
+ case EOpComma: out << "Comma\n"; return true;
+ case EOpFunction: out << "Function Definition: " << node->getName(); break;
+ case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
+ case EOpParameters: out << "Function Parameters: "; break;
+
+ case EOpConstructFloat: out << "Construct float"; break;
+ case EOpConstructVec2: out << "Construct vec2"; break;
+ case EOpConstructVec3: out << "Construct vec3"; break;
+ case EOpConstructVec4: out << "Construct vec4"; break;
+ case EOpConstructBool: out << "Construct bool"; break;
+ case EOpConstructBVec2: out << "Construct bvec2"; break;
+ case EOpConstructBVec3: out << "Construct bvec3"; break;
+ case EOpConstructBVec4: out << "Construct bvec4"; break;
+ case EOpConstructInt: out << "Construct int"; break;
+ case EOpConstructIVec2: out << "Construct ivec2"; break;
+ case EOpConstructIVec3: out << "Construct ivec3"; break;
+ case EOpConstructIVec4: out << "Construct ivec4"; break;
+ case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat4: out << "Construct mat4"; break;
+ case EOpConstructStruct: out << "Construct structure"; break;
+
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+ case EOpVectorEqual: out << "Equal"; break;
+ case EOpVectorNotEqual: out << "NotEqual"; break;
+
+ case EOpMod: out << "mod"; break;
+ case EOpPow: out << "pow"; break;
+
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpMin: out << "min"; break;
+ case EOpMax: out << "max"; break;
+ case EOpClamp: out << "clamp"; break;
+ case EOpMix: out << "mix"; break;
+ case EOpStep: out << "step"; break;
+ case EOpSmoothStep: out << "smoothstep"; break;
+
+ case EOpDistance: out << "distance"; break;
+ case EOpDot: out << "dot-product"; break;
+ case EOpCross: out << "cross-product"; break;
+ case EOpFaceForward: out << "face-forward"; break;
+ case EOpReflect: out << "reflect"; break;
+ case EOpRefract: out << "refract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+
+ case EOpDeclaration: out << "Declaration: "; break;
+
+ default: out.message(EPrefixError, "Bad aggregation op");
+ }
+
+ if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Test condition and select";
+ out << " (" << node->getCompleteString() << ")\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, depth);
+ if (node->getTrueBlock()) {
+ out << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ } else
+ out << "true case is null\n";
+
+ if (node->getFalseBlock()) {
+ OutputTreeText(sink, node, depth);
+ out << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ TInfoSinkBase& out = sink;
+
+ int size = node->getType().getObjectSize();
+
+ for (int i = 0; i < size; i++) {
+ OutputTreeText(out, node, depth);
+ switch (node->getUnionArrayPointer()[i].getType()) {
+ case EbtBool:
+ if (node->getUnionArrayPointer()[i].getBConst())
+ out << "true";
+ else
+ out << "false";
+
+ out << " (" << "const bool" << ")";
+ out << "\n";
+ break;
+ case EbtFloat:
+ out << node->getUnionArrayPointer()[i].getFConst();
+ out << " (const float)\n";
+ break;
+ case EbtInt:
+ out << node->getUnionArrayPointer()[i].getIConst();
+ out << " (const int)\n";
+ break;
+ default:
+ out.message(EPrefixInternalError, "Unknown constant", node->getLine());
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ out << "not ";
+ out << "tested first\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ if (node->getCondition()) {
+ out << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ } else
+ out << "No loop condition\n";
+
+ OutputTreeText(sink, node, depth);
+ if (node->getBody()) {
+ out << "Loop Body\n";
+ node->getBody()->traverse(this);
+ } else
+ out << "No loop body\n";
+
+ if (node->getExpression()) {
+ OutputTreeText(sink, node, depth);
+ out << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getFlowOp()) {
+ case EOpKill: out << "Branch: Kill"; break;
+ case EOpBreak: out << "Branch: Break"; break;
+ case EOpContinue: out << "Branch: Continue"; break;
+ case EOpReturn: out << "Branch: Return"; break;
+ default: out << "Branch: Unknown Branch"; break;
+ }
+
+ if (node->getExpression()) {
+ out << " with expression\n";
+ ++depth;
+ node->getExpression()->traverse(this);
+ --depth;
+ } else
+ out << "\n";
+
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+void TIntermediate::outputTree(TIntermNode* root)
+{
+ if (root == 0)
+ return;
+
+ TOutputTraverser it(infoSink.info);
+
+ root->traverse(&it);
+}
diff --git a/src/3rdparty/angle/src/compiler/intermediate.h b/src/3rdparty/angle/src/compiler/intermediate.h
new file mode 100644
index 0000000000..af78fa00ef
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/intermediate.h
@@ -0,0 +1,557 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders. This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree. There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef __INTERMEDIATE_H
+#define __INTERMEDIATE_H
+
+#include "compiler/Common.h"
+#include "compiler/Types.h"
+#include "compiler/ConstantUnion.h"
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator {
+ EOpNull, // if in a node, should only mean a node is still being built
+ EOpSequence, // denotes a list of statements, or parameters, etc.
+ EOpFunctionCall,
+ EOpFunction, // For function definition
+ EOpParameters, // an aggregate listing the parameters to a function
+
+ EOpDeclaration,
+ EOpPrototype,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpLogicalNot,
+ EOpVectorLogicalNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ EOpConvIntToBool,
+ EOpConvFloatToBool,
+ EOpConvBoolToFloat,
+ EOpConvIntToFloat,
+ EOpConvFloatToInt,
+ EOpConvBoolToInt,
+
+ //
+ // binary operations
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpEqual,
+ EOpNotEqual,
+ EOpVectorEqual,
+ EOpVectorNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+
+ EOpVectorSwizzle,
+
+ //
+ // Built-in functions potentially mapped to operators
+ //
+
+ EOpRadians,
+ EOpDegrees,
+ EOpSin,
+ EOpCos,
+ EOpTan,
+ EOpAsin,
+ EOpAcos,
+ EOpAtan,
+
+ EOpPow,
+ EOpExp,
+ EOpLog,
+ EOpExp2,
+ EOpLog2,
+ EOpSqrt,
+ EOpInverseSqrt,
+
+ EOpAbs,
+ EOpSign,
+ EOpFloor,
+ EOpCeil,
+ EOpFract,
+ EOpMod,
+ EOpMin,
+ EOpMax,
+ EOpClamp,
+ EOpMix,
+ EOpStep,
+ EOpSmoothStep,
+
+ EOpLength,
+ EOpDistance,
+ EOpDot,
+ EOpCross,
+ EOpNormalize,
+ EOpFaceForward,
+ EOpReflect,
+ EOpRefract,
+
+ EOpDFdx, // Fragment only, OES_standard_derivatives extension
+ EOpDFdy, // Fragment only, OES_standard_derivatives extension
+ EOpFwidth, // Fragment only, OES_standard_derivatives extension
+
+ EOpMatrixTimesMatrix,
+
+ EOpAny,
+ EOpAll,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructors
+ //
+
+ EOpConstructInt,
+ EOpConstructBool,
+ EOpConstructFloat,
+ EOpConstructVec2,
+ EOpConstructVec3,
+ EOpConstructVec4,
+ EOpConstructBVec2,
+ EOpConstructBVec3,
+ EOpConstructBVec4,
+ EOpConstructIVec2,
+ EOpConstructIVec3,
+ EOpConstructIVec4,
+ EOpConstructMat2,
+ EOpConstructMat3,
+ EOpConstructMat4,
+ EOpConstructStruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+ EOpDivAssign,
+};
+
+extern const char* getOperatorString(TOperator op);
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermUnary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermTyped;
+class TIntermSymbol;
+class TIntermLoop;
+class TInfoSink;
+
+//
+// Base class for the tree nodes
+//
+class TIntermNode {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermNode() : line(0) {}
+
+ TSourceLoc getLine() const { return line; }
+ void setLine(TSourceLoc l) { line = l; }
+
+ virtual void traverse(TIntermTraverser*) = 0;
+ virtual TIntermTyped* getAsTyped() { return 0; }
+ virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
+ virtual TIntermAggregate* getAsAggregate() { return 0; }
+ virtual TIntermBinary* getAsBinaryNode() { return 0; }
+ virtual TIntermUnary* getAsUnaryNode() { return 0; }
+ virtual TIntermSelection* getAsSelectionNode() { return 0; }
+ virtual TIntermSymbol* getAsSymbolNode() { return 0; }
+ virtual TIntermLoop* getAsLoopNode() { return 0; }
+ virtual ~TIntermNode() { }
+
+protected:
+ TSourceLoc line;
+};
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair {
+ TIntermNode* node1;
+ TIntermNode* node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode {
+public:
+ TIntermTyped(const TType& t) : type(t) { }
+ virtual TIntermTyped* getAsTyped() { return this; }
+
+ void setType(const TType& t) { type = t; }
+ const TType& getType() const { return type; }
+ TType* getTypePointer() { return &type; }
+
+ TBasicType getBasicType() const { return type.getBasicType(); }
+ TQualifier getQualifier() const { return type.getQualifier(); }
+ TPrecision getPrecision() const { return type.getPrecision(); }
+ int getNominalSize() const { return type.getNominalSize(); }
+
+ bool isMatrix() const { return type.isMatrix(); }
+ bool isArray() const { return type.isArray(); }
+ bool isVector() const { return type.isVector(); }
+ bool isScalar() const { return type.isScalar(); }
+ const char* getBasicString() const { return type.getBasicString(); }
+ const char* getQualifierString() const { return type.getQualifierString(); }
+ TString getCompleteString() const { return type.getCompleteString(); }
+
+protected:
+ TType type;
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+enum TLoopType {
+ ELoopFor,
+ ELoopWhile,
+ ELoopDoWhile,
+};
+
+class TIntermLoop : public TIntermNode {
+public:
+ TIntermLoop(TLoopType aType,
+ TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
+ TIntermNode* aBody) :
+ type(aType),
+ init(aInit),
+ cond(aCond),
+ expr(aExpr),
+ body(aBody),
+ unrollFlag(false) { }
+
+ virtual TIntermLoop* getAsLoopNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TLoopType getType() const { return type; }
+ TIntermNode* getInit() { return init; }
+ TIntermTyped* getCondition() { return cond; }
+ TIntermTyped* getExpression() { return expr; }
+ TIntermNode* getBody() { return body; }
+
+ void setUnrollFlag(bool flag) { unrollFlag = flag; }
+ bool getUnrollFlag() { return unrollFlag; }
+
+protected:
+ TLoopType type;
+ TIntermNode* init; // for-loop initialization
+ TIntermTyped* cond; // loop exit condition
+ TIntermTyped* expr; // for-loop expression
+ TIntermNode* body; // loop body
+
+ bool unrollFlag; // Whether the loop should be unrolled or not.
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+ TIntermBranch(TOperator op, TIntermTyped* e) :
+ flowOp(op),
+ expression(e) { }
+
+ virtual void traverse(TIntermTraverser*);
+
+ TOperator getFlowOp() { return flowOp; }
+ TIntermTyped* getExpression() { return expression; }
+
+protected:
+ TOperator flowOp;
+ TIntermTyped* expression; // non-zero except for "return exp;" statements
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped {
+public:
+ // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
+ // per process globalpoolallocator, then it causes increased memory usage per compile
+ // it is essential to use "symbol = sym" to assign to symbol
+ TIntermSymbol(int i, const TString& sym, const TType& t) :
+ TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; }
+
+ int getId() const { return id; }
+ const TString& getSymbol() const { return symbol; }
+
+ void setId(int newId) { id = newId; }
+ void setSymbol(const TString& sym) { symbol = sym; }
+
+ const TString& getOriginalSymbol() const { return originalSymbol; }
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermSymbol* getAsSymbolNode() { return this; }
+
+protected:
+ int id;
+ TString symbol;
+ TString originalSymbol;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+ TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
+
+ ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
+ void setUnionArrayPointer(ConstantUnion *c) { unionArrayPointer = c; }
+
+ virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
+
+protected:
+ ConstantUnion *unionArrayPointer;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+ TOperator getOp() const { return op; }
+ void setOp(TOperator o) { op = o; }
+
+ bool modifiesState() const;
+ bool isConstructor() const;
+
+protected:
+ TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
+ TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
+ TOperator op;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+ TIntermBinary(TOperator o) : TIntermOperator(o) {}
+
+ virtual TIntermBinary* getAsBinaryNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ void setLeft(TIntermTyped* n) { left = n; }
+ void setRight(TIntermTyped* n) { right = n; }
+ TIntermTyped* getLeft() const { return left; }
+ TIntermTyped* getRight() const { return right; }
+ bool promote(TInfoSink&);
+
+protected:
+ TIntermTyped* left;
+ TIntermTyped* right;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+ TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
+ TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermUnary* getAsUnaryNode() { return this; }
+
+ void setOperand(TIntermTyped* o) { operand = o; }
+ TIntermTyped* getOperand() { return operand; }
+ bool promote(TInfoSink&);
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+protected:
+ TIntermTyped* operand;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+typedef TVector<TIntermNode*> TIntermSequence;
+typedef TVector<int> TQualifierList;
+
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator {
+public:
+ TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), endLine(0), useEmulatedFunction(false) { }
+ TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
+ ~TIntermAggregate() { }
+
+ virtual TIntermAggregate* getAsAggregate() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermSequence& getSequence() { return sequence; }
+
+ void setName(const TString& n) { name = n; }
+ const TString& getName() const { return name; }
+
+ void setUserDefined() { userDefined = true; }
+ bool isUserDefined() const { return userDefined; }
+
+ void setOptimize(bool o) { optimize = o; }
+ bool getOptimize() { return optimize; }
+ void setDebug(bool d) { debug = d; }
+ bool getDebug() { return debug; }
+
+ void setEndLine(TSourceLoc line) { endLine = line; }
+ TSourceLoc getEndLine() const { return endLine; }
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+protected:
+ TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+ TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+ TIntermSequence sequence;
+ TString name;
+ bool userDefined; // used for user defined function names
+
+ bool optimize;
+ bool debug;
+ TSourceLoc endLine;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+//
+// For if tests. Simplified since there is no switch statement.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+ TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
+ TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+
+ virtual void traverse(TIntermTraverser*);
+
+ bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
+ TIntermNode* getCondition() const { return condition; }
+ TIntermNode* getTrueBlock() const { return trueBlock; }
+ TIntermNode* getFalseBlock() const { return falseBlock; }
+ TIntermSelection* getAsSelectionNode() { return this; }
+
+protected:
+ TIntermTyped* condition;
+ TIntermNode* trueBlock;
+ TIntermNode* falseBlock;
+};
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+//
+// For traversing the tree. User should derive from this,
+// put their traversal specific data in it, and then pass
+// it to a Traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+class TIntermTraverser
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
+ preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ rightToLeft(rightToLeft),
+ depth(0) {}
+ virtual ~TIntermTraverser() {};
+
+ virtual void visitSymbol(TIntermSymbol*) {}
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
+ virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
+ virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
+ virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
+ virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
+
+ void incrementDepth() {depth++;}
+ void decrementDepth() {depth--;}
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+ const bool rightToLeft;
+
+protected:
+ int depth;
+};
+
+#endif // __INTERMEDIATE_H
diff --git a/src/3rdparty/angle/src/compiler/localintermediate.h b/src/3rdparty/angle/src/compiler/localintermediate.h
new file mode 100644
index 0000000000..56890bd569
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/localintermediate.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
+#define _LOCAL_INTERMEDIATE_INCLUDED_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+#include "compiler/SymbolTable.h"
+
+struct TVectorFields {
+ int offsets[4];
+ int num;
+};
+
+//
+// Set of helper functions to help parse and build the tree.
+//
+class TInfoSink;
+class TIntermediate {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermediate(TInfoSink& i) : infoSink(i) { }
+ TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc);
+ TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+ TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&);
+ TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+ TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
+ TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&);
+ TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc);
+ TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc);
+ TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc);
+ TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc);
+ TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
+ TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+ TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc);
+ TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+ bool parseConstTree(TSourceLoc, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false);
+ TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, TSourceLoc);
+ TIntermBranch* addBranch(TOperator, TSourceLoc);
+ TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
+ TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
+ bool postProcess(TIntermNode*);
+ void remove(TIntermNode*);
+ void outputTree(TIntermNode*);
+
+protected:
+ TInfoSink& infoSink;
+
+private:
+ void operator=(TIntermediate&); // prevent assignments
+};
+
+#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/src/3rdparty/angle/src/compiler/osinclude.h b/src/3rdparty/angle/src/compiler/osinclude.h
new file mode 100644
index 0000000000..1d95907b79
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/osinclude.h
@@ -0,0 +1,72 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __OSINCLUDE_H
+#define __OSINCLUDE_H
+
+//
+// This file contains contains os-specific datatypes and
+// declares any os-specific functions.
+//
+
+#if defined(_WIN32) || defined(_WIN64)
+#define ANGLE_OS_WIN
+#elif defined(__APPLE__) || defined(__linux__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__sun) || defined(ANDROID) || \
+ defined(__GLIBC__) || defined(__GNU__) || \
+ defined(__QNX__)
+#define ANGLE_OS_POSIX
+#else
+#error Unsupported platform.
+#endif
+
+#if defined(ANGLE_USE_NSPR)
+#include "prthread.h"
+#elif defined(ANGLE_OS_WIN)
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#elif defined(ANGLE_OS_POSIX)
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#endif // ANGLE_USE_NSPR
+
+
+#include "compiler/debug.h"
+
+//
+// Thread Local Storage Operations
+//
+#if defined(ANGLE_USE_NSPR)
+typedef PRUintn OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX 0xFFFFFFFF
+#elif defined(ANGLE_OS_WIN)
+typedef DWORD OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES)
+#elif defined(ANGLE_OS_POSIX)
+typedef unsigned int OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX 0xFFFFFFFF
+#endif // ANGLE_USE_NSPR
+
+OS_TLSIndex OS_AllocTLSIndex();
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex);
+
+inline void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+ ASSERT(nIndex != OS_INVALID_TLS_INDEX);
+#if defined(ANGLE_USE_NSPR)
+ return PR_GetThreadPrivate(nIndex);
+#elif defined(ANGLE_OS_WIN)
+ return TlsGetValue(nIndex);
+#elif defined(ANGLE_OS_POSIX)
+ return pthread_getspecific(nIndex);
+#endif // ANGLE_OS_WIN
+}
+
+#endif // __OSINCLUDE_H
diff --git a/src/3rdparty/angle/src/compiler/ossource_nspr.cpp b/src/3rdparty/angle/src/compiler/ossource_nspr.cpp
new file mode 100644
index 0000000000..f63d81e5d5
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ossource_nspr.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// This file contains the nspr specific functions
+//
+#include "compiler/osinclude.h"
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ PRUintn index;
+ PRStatus status = PR_NewThreadPrivateIndex(&index, NULL);
+
+ if (status) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return index;
+}
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ return PR_SetThreadPrivate(nIndex, lpvValue) == 0;
+}
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ // Can't delete TLS keys with nspr
+ return true;
+}
+
diff --git a/src/3rdparty/angle/src/compiler/ossource_posix.cpp b/src/3rdparty/angle/src/compiler/ossource_posix.cpp
new file mode 100644
index 0000000000..1e1e699aeb
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ossource_posix.cpp
@@ -0,0 +1,64 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// This file contains the posix specific functions
+//
+#include "compiler/osinclude.h"
+
+#if !defined(ANGLE_OS_POSIX)
+#error Trying to build a posix specific file in a non-posix build.
+#endif
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ pthread_key_t pPoolIndex;
+
+ //
+ // Create global pool key.
+ //
+ if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return false;
+ }
+ else {
+ return pPoolIndex;
+ }
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (pthread_setspecific(nIndex, lpvValue) == 0)
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ //
+ // Delete the global pool key.
+ //
+ if (pthread_key_delete(nIndex) == 0)
+ return true;
+ else
+ return false;
+}
diff --git a/src/3rdparty/angle/src/compiler/ossource_win.cpp b/src/3rdparty/angle/src/compiler/ossource_win.cpp
new file mode 100644
index 0000000000..89922fef3f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/ossource_win.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/osinclude.h"
+//
+// This file contains contains the window's specific functions
+//
+
+#if !defined(ANGLE_OS_WIN)
+#error Trying to build a windows specific file in a non windows build.
+#endif
+
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ DWORD dwIndex = TlsAlloc();
+ if (dwIndex == TLS_OUT_OF_INDEXES) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return dwIndex;
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsSetValue(nIndex, lpvValue))
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsFree(nIndex))
+ return true;
+ else
+ return false;
+}
diff --git a/src/3rdparty/angle/src/compiler/parseConst.cpp b/src/3rdparty/angle/src/compiler/parseConst.cpp
new file mode 100644
index 0000000000..9a8a50c31c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/parseConst.cpp
@@ -0,0 +1,238 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ParseHelper.h"
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TConstTraverser : public TIntermTraverser {
+public:
+ TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t)
+ : error(false),
+ index(0),
+ unionArray(cUnion),
+ type(t),
+ constructorType(constructType),
+ singleConstantParam(singleConstParam),
+ infoSink(sink),
+ symbolTable(symTable),
+ size(0),
+ isMatrix(false),
+ matrixSize(0) {
+ }
+
+ bool error;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ int index;
+ ConstantUnion *unionArray;
+ TType type;
+ TOperator constructorType;
+ bool singleConstantParam;
+ TInfoSink& infoSink;
+ TSymbolTable& symbolTable;
+ int size; // size of the constructor ( 4 for vec4)
+ bool isMatrix;
+ int matrixSize; // dimension of the matrix (nominal size and not the instance size)
+};
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TConstTraverser::visitSymbol(TIntermSymbol* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
+ return;
+
+}
+
+bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TQualifier qualifier = node->getType().getQualifier();
+
+ if (qualifier != EvqConst) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+ }
+
+ infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
+
+ return false;
+}
+
+bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ if (!node->isConstructor() && node->getOp() != EOpComma) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+ }
+
+ if (node->getSequence().size() == 0) {
+ error = true;
+ return false;
+ }
+
+ bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
+ if (flag)
+ {
+ singleConstantParam = true;
+ constructorType = node->getOp();
+ size = node->getType().getObjectSize();
+
+ if (node->getType().isMatrix()) {
+ isMatrix = true;
+ matrixSize = node->getType().getNominalSize();
+ }
+ }
+
+ for (TIntermSequence::iterator p = node->getSequence().begin();
+ p != node->getSequence().end(); p++) {
+
+ if (node->getOp() == EOpComma)
+ index = 0;
+
+ (*p)->traverse(this);
+ }
+ if (flag)
+ {
+ singleConstantParam = false;
+ constructorType = EOpNull;
+ size = 0;
+ isMatrix = false;
+ matrixSize = 0;
+ }
+ return false;
+}
+
+bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ ConstantUnion* leftUnionArray = unionArray;
+ int instanceSize = type.getObjectSize();
+
+ if (index >= instanceSize)
+ return;
+
+ if (!singleConstantParam) {
+ int size = node->getType().getObjectSize();
+
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ for (int i=0; i < size; i++) {
+ if (index >= instanceSize)
+ return;
+ leftUnionArray[index] = rightUnionArray[i];
+
+ (index)++;
+ }
+ } else {
+ int totalSize = index + size;
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ if (!isMatrix) {
+ int count = 0;
+ for (int i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+
+ leftUnionArray[i] = rightUnionArray[count];
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ } else { // for matrix constructors
+ int count = 0;
+ int element = index;
+ for (int i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+ if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
+ leftUnionArray[i] = rightUnionArray[count];
+ else
+ leftUnionArray[i].setFConst(0.0f);
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ }
+ }
+}
+
+bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
+{
+ if (root == 0)
+ return false;
+
+ TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
+
+ root->traverse(&it);
+ if (it.error)
+ return true;
+ else
+ return false;
+}
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/atom.c b/src/3rdparty/angle/src/compiler/preprocessor/atom.c
new file mode 100644
index 0000000000..39158d2fa1
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/atom.c
@@ -0,0 +1,737 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+//
+// atom.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common/angleutils.h"
+#include "compiler/debug.h"
+#include "compiler/preprocessor/slglobals.h"
+
+#undef malloc
+#undef realloc
+#undef free
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////// String table: //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static const struct {
+ int val;
+ const char *str;
+} tokens[] = {
+ { CPP_AND_OP, "&&" },
+ { CPP_AND_ASSIGN, "&=" },
+ { CPP_SUB_ASSIGN, "-=" },
+ { CPP_MOD_ASSIGN, "%=" },
+ { CPP_ADD_ASSIGN, "+=" },
+ { CPP_DIV_ASSIGN, "/=" },
+ { CPP_MUL_ASSIGN, "*=" },
+ { CPP_RIGHT_BRACKET, ":>" },
+ { CPP_EQ_OP, "==" },
+ { CPP_XOR_OP, "^^" },
+ { CPP_XOR_ASSIGN, "^=" },
+ { CPP_FLOATCONSTANT, "<float-const>" },
+ { CPP_GE_OP, ">=" },
+ { CPP_RIGHT_OP, ">>" },
+ { CPP_RIGHT_ASSIGN, ">>=" },
+ { CPP_IDENTIFIER, "<ident>" },
+ { CPP_INTCONSTANT, "<int-const>" },
+ { CPP_LE_OP, "<=" },
+ { CPP_LEFT_OP, "<<" },
+ { CPP_LEFT_ASSIGN, "<<=" },
+ { CPP_LEFT_BRACKET, "<:" },
+ { CPP_LEFT_BRACE, "<%" },
+ { CPP_DEC_OP, "--" },
+ { CPP_RIGHT_BRACE, "%>" },
+ { CPP_NE_OP, "!=" },
+ { CPP_OR_OP, "||" },
+ { CPP_OR_ASSIGN, "|=" },
+ { CPP_INC_OP, "++" },
+ { CPP_STRCONSTANT, "<string-const>" },
+ { CPP_TYPEIDENTIFIER, "<type-ident>" },
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////// String table: //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_STRING_TABLE_SIZE 16384
+
+typedef struct StringTable_Rec {
+ char *strings;
+ int nextFree;
+ int size;
+} StringTable;
+
+/*
+ * InitStringTable() - Initialize the string table.
+ *
+ */
+
+static int InitStringTable(StringTable *stable)
+{
+ stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE);
+ if (!stable->strings)
+ return 0;
+ // Zero-th offset means "empty" so don't use it.
+ stable->nextFree = 1;
+ stable->size = INIT_STRING_TABLE_SIZE;
+ return 1;
+} // InitStringTable
+
+/*
+ * FreeStringTable() - Free the string table.
+ *
+ */
+
+static void FreeStringTable(StringTable *stable)
+{
+ if (stable->strings)
+ free(stable->strings);
+ stable->strings = NULL;
+ stable->nextFree = 0;
+ stable->size = 0;
+} // FreeStringTable
+
+/*
+ * HashString() - Hash a string with the base hash function.
+ *
+ */
+
+static int HashString(const char *s)
+{
+ int hval = 0;
+
+ while (*s) {
+ hval = (hval*13507 + *s*197) ^ (hval >> 2);
+ s++;
+ }
+ return hval & 0x7fffffff;
+} // HashString
+
+/*
+ * HashString2() - Hash a string with the incrimenting hash function.
+ *
+ */
+
+static int HashString2(const char *s)
+{
+ int hval = 0;
+
+ while (*s) {
+ hval = (hval*729 + *s*37) ^ (hval >> 1);
+ s++;
+ }
+ return hval;
+} // HashString2
+
+/*
+ * AddString() - Add a string to a string table. Return it's offset.
+ *
+ */
+
+static int AddString(StringTable *stable, const char *s)
+{
+ int len, loc;
+ char *str;
+
+ len = (int) strlen(s);
+ while (stable->nextFree + len + 1 >= stable->size) {
+ assert(stable->size < 1000000);
+ str = (char *) malloc(stable->size*2);
+ memcpy(str, stable->strings, stable->size);
+ free(stable->strings);
+ stable->strings = str;
+ stable->size = stable->size*2;
+ }
+ loc = stable->nextFree;
+ strcpy(&stable->strings[loc], s);
+ stable->nextFree += len + 1;
+ return loc;
+} // AddString
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////// Hash table: ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_HASH_TABLE_SIZE 2047
+#define HASH_TABLE_MAX_COLLISIONS 3
+
+typedef struct HashEntry_Rec {
+ int index; // String table offset of string representation
+ int value; // Atom (symbol) value
+} HashEntry;
+
+typedef struct HashTable_Rec {
+ HashEntry *entry;
+ int size;
+ int entries;
+ int counts[HASH_TABLE_MAX_COLLISIONS + 1];
+} HashTable;
+
+/*
+ * InitHashTable() - Initialize the hash table.
+ *
+ */
+
+static int InitHashTable(HashTable *htable, int fsize)
+{
+ int ii;
+
+ htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize);
+ if (!htable->entry)
+ return 0;
+ htable->size = fsize;
+ for (ii = 0; ii < fsize; ii++) {
+ htable->entry[ii].index = 0;
+ htable->entry[ii].value = 0;
+ }
+ htable->entries = 0;
+ for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++)
+ htable->counts[ii] = 0;
+ return 1;
+} // InitHashTable
+
+/*
+ * FreeHashTable() - Free the hash table.
+ *
+ */
+
+static void FreeHashTable(HashTable *htable)
+{
+ if (htable->entry)
+ free(htable->entry);
+ htable->entry = NULL;
+ htable->size = 0;
+ htable->entries = 0;
+} // FreeHashTable
+
+/*
+ * Empty() - See if a hash table entry is empty.
+ *
+ */
+
+static int Empty(HashTable *htable, int hashloc)
+{
+ assert(hashloc >= 0 && hashloc < htable->size);
+ if (htable->entry[hashloc].index == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+} // Empty
+
+/*
+ * Match() - See if a hash table entry is matches a string.
+ *
+ */
+
+static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc)
+{
+ int strloc;
+
+ strloc = htable->entry[hashloc].index;
+ if (!strcmp(s, &stable->strings[strloc])) {
+ return 1;
+ } else {
+ return 0;
+ }
+} // Match
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////// Atom table: ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_ATOM_TABLE_SIZE 1024
+
+
+struct AtomTable_Rec {
+ StringTable stable; // String table.
+ HashTable htable; // Hashes string to atom number and token value. Multiple strings can
+ // have the same token value but each unique string is a unique atom.
+ int *amap; // Maps atom value to offset in string table. Atoms all map to unique
+ // strings except for some undefined values in the lower, fixed part
+ // of the atom table that map to "<undefined>". The lowest 256 atoms
+ // correspond to single character ASCII values except for alphanumeric
+ // characters and '_', which can be other tokens. Next come the
+ // language tokens with their atom values equal to the token value.
+ // Then come predefined atoms, followed by user specified identifiers.
+ int *arev; // Reversed atom for symbol table use.
+ int nextFree;
+ int size;
+};
+
+static AtomTable latable = { { NULL, 0, 0 }, { NULL, 0, 0, {0} }, NULL, NULL, 0, 0 };
+AtomTable *atable = &latable;
+
+static int AddAtomFixed(AtomTable *atable, const char *s, int atom);
+
+/*
+ * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller.
+ *
+ */
+
+static int GrowAtomTable(AtomTable *atable, int size)
+{
+ int *newmap, *newrev;
+
+ if (atable->size < size) {
+ if (atable->amap) {
+ newmap = realloc(atable->amap, sizeof(int)*size);
+ newrev = realloc(atable->arev, sizeof(int)*size);
+ } else {
+ newmap = malloc(sizeof(int)*size);
+ newrev = malloc(sizeof(int)*size);
+ atable->size = 0;
+ }
+ if (!newmap || !newrev) {
+ /* failed to grow -- error */
+ if (newmap)
+ atable->amap = newmap;
+ if (newrev)
+ atable->arev = newrev;
+ return -1;
+ }
+ memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
+ memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
+ atable->amap = newmap;
+ atable->arev = newrev;
+ atable->size = size;
+ }
+ return 0;
+} // GrowAtomTable
+
+/*
+ * lReverse() - Reverse the bottom 20 bits of a 32 bit int.
+ *
+ */
+
+static int lReverse(int fval)
+{
+ unsigned int in = fval;
+ int result = 0, cnt = 0;
+
+ while(in) {
+ result <<= 1;
+ result |= in&1;
+ in >>= 1;
+ cnt++;
+ }
+
+ // Don't use all 31 bits. One million atoms is plenty and sometimes the
+ // upper bits are used for other things.
+
+ if (cnt < 20)
+ result <<= 20 - cnt;
+ return result;
+} // lReverse
+
+/*
+ * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1.
+ *
+ */
+
+static int AllocateAtom(AtomTable *atable)
+{
+ if (atable->nextFree >= atable->size)
+ GrowAtomTable(atable, atable->nextFree*2);
+ atable->amap[atable->nextFree] = -1;
+ atable->arev[atable->nextFree] = lReverse(atable->nextFree);
+ atable->nextFree++;
+ return atable->nextFree - 1;
+} // AllocateAtom
+
+/*
+ * SetAtomValue() - Allocate a new atom associated with "hashindex".
+ *
+ */
+
+static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex)
+{
+ atable->amap[atomnumber] = atable->htable.entry[hashindex].index;
+ atable->htable.entry[hashindex].value = atomnumber;
+} // SetAtomValue
+
+/*
+ * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full.
+ *
+ */
+
+static int FindHashLoc(AtomTable *atable, const char *s)
+{
+ int hashloc, hashdelta, count;
+ int FoundEmptySlot = 0;
+ int collision[HASH_TABLE_MAX_COLLISIONS + 1];
+
+ hashloc = HashString(s) % atable->htable.size;
+ if (!Empty(&atable->htable, hashloc)) {
+ if (Match(&atable->htable, &atable->stable, s, hashloc))
+ return hashloc;
+ collision[0] = hashloc;
+ hashdelta = HashString2(s);
+ count = 0;
+ while (count < HASH_TABLE_MAX_COLLISIONS) {
+ hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size;
+ if (!Empty(&atable->htable, hashloc)) {
+ if (Match(&atable->htable, &atable->stable, s, hashloc)) {
+ return hashloc;
+ }
+ } else {
+ FoundEmptySlot = 1;
+ break;
+ }
+ count++;
+ collision[count] = hashloc;
+ }
+
+ if (!FoundEmptySlot) {
+ if (cpp->options.DumpAtomTable) {
+ int ii;
+ char str[200];
+ snprintf(str, sizeof(str), "*** Hash failed with more than %d collisions. Must increase hash table size. ***",
+ HASH_TABLE_MAX_COLLISIONS);
+ CPPShInfoLogMsg(str);
+
+ snprintf(str, sizeof(str), "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta);
+ CPPShInfoLogMsg(str);
+ for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) {
+ snprintf(str, sizeof(str), "*** Collides on try %d at hash entry %04x with \"%s\"",
+ ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value));
+ CPPShInfoLogMsg(str);
+ }
+ }
+ return -1;
+ } else {
+ atable->htable.counts[count]++;
+ }
+ }
+ return hashloc;
+} // FindHashLoc
+
+/*
+ * IncreaseHashTableSize()
+ *
+ */
+
+static int IncreaseHashTableSize(AtomTable *atable)
+{
+ int ii, strloc, oldhashloc, value, size;
+ AtomTable oldtable;
+ char *s;
+
+ // Save the old atom table and create a new one:
+
+ oldtable = *atable;
+ size = oldtable.htable.size*2 + 1;
+ if (!InitAtomTable(atable, size))
+ return 0;
+
+ // Add all the existing values to the new atom table preserving their atom values:
+
+ for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) {
+ strloc = oldtable.amap[ii];
+ s = &oldtable.stable.strings[strloc];
+ oldhashloc = FindHashLoc(&oldtable, s);
+ assert(oldhashloc >= 0);
+ value = oldtable.htable.entry[oldhashloc].value;
+ AddAtomFixed(atable, s, value);
+ }
+ FreeAtomTable(&oldtable);
+ return 1;
+} // IncreaseHashTableSize
+
+/*
+ * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and
+ * initialize the atom value in the hash table to 0. Return the hash table index.
+ */
+
+static int LookUpAddStringHash(AtomTable *atable, const char *s)
+{
+ int hashloc, strloc;
+
+ while(1) {
+ hashloc = FindHashLoc(atable, s);
+ if (hashloc >= 0)
+ break;
+ IncreaseHashTableSize(atable);
+ }
+
+ if (Empty(&atable->htable, hashloc)) {
+ atable->htable.entries++;
+ strloc = AddString(&atable->stable, s);
+ atable->htable.entry[hashloc].index = strloc;
+ atable->htable.entry[hashloc].value = 0;
+ }
+ return hashloc;
+} // LookUpAddStringHash
+
+/*
+ * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and
+ * initialize the atom value in the hash table to the next atom number.
+ * Return the atom value of string.
+ */
+
+int LookUpAddString(AtomTable *atable, const char *s)
+{
+ int hashindex, atom;
+
+ hashindex = LookUpAddStringHash(atable, s);
+ atom = atable->htable.entry[hashindex].value;
+ if (atom == 0) {
+ atom = AllocateAtom(atable);
+ SetAtomValue(atable, atom, hashindex);
+ }
+ return atom;
+} // LookUpAddString
+
+/*
+ * GetAtomString()
+ *
+ */
+
+const char *GetAtomString(AtomTable *atable, int atom)
+{
+ int soffset;
+
+ if (atom > 0 && atom < atable->nextFree) {
+ soffset = atable->amap[atom];
+ if (soffset > 0 && soffset < atable->stable.nextFree) {
+ return &atable->stable.strings[soffset];
+ } else {
+ return "<internal error: bad soffset>";
+ }
+ } else {
+ if (atom == 0) {
+ return "<null atom>";
+ } else {
+ if (atom == EOF) {
+ return "<EOF>";
+ } else {
+ return "<invalid atom>";
+ }
+ }
+ }
+} // GetAtomString
+
+/*
+ * GetReversedAtom()
+ *
+ */
+
+int GetReversedAtom(AtomTable *atable, int atom)
+{
+ if (atom > 0 && atom < atable->nextFree) {
+ return atable->arev[atom];
+ } else {
+ return 0;
+ }
+} // GetReversedAtom
+
+/*
+ * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there.
+ * Return it's atom index.
+ */
+
+int AddAtom(AtomTable *atable, const char *s)
+{
+ int atom;
+
+ atom = LookUpAddString(atable, s);
+ return atom;
+} // AddAtom
+
+/*
+ * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there.
+ * Assign it the atom value of "atom".
+ */
+
+static int AddAtomFixed(AtomTable *atable, const char *s, int atom)
+{
+ int hashindex, lsize;
+
+ hashindex = LookUpAddStringHash(atable, s);
+ if (atable->nextFree >= atable->size || atom >= atable->size) {
+ lsize = atable->size*2;
+ if (lsize <= atom)
+ lsize = atom + 1;
+ GrowAtomTable(atable, lsize);
+ }
+ atable->amap[atom] = atable->htable.entry[hashindex].index;
+ atable->htable.entry[hashindex].value = atom;
+ //if (atom >= atable->nextFree)
+ // atable->nextFree = atom + 1;
+ while (atom >= atable->nextFree) {
+ atable->arev[atable->nextFree] = lReverse(atable->nextFree);
+ atable->nextFree++;
+ }
+ return atom;
+} // AddAtomFixed
+
+/*
+ * InitAtomTable() - Initialize the atom table.
+ *
+ */
+
+int InitAtomTable(AtomTable *atable, int htsize)
+{
+ unsigned int ii;
+
+ htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize;
+ if (!InitStringTable(&atable->stable))
+ return 0;
+ if (!InitHashTable(&atable->htable, htsize))
+ return 0;
+
+ atable->nextFree = 0;
+ atable->amap = NULL;
+ atable->size = 0;
+ GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE);
+ if (!atable->amap)
+ return 0;
+
+ // Initialize lower part of atom table to "<undefined>" atom:
+
+ AddAtomFixed(atable, "<undefined>", 0);
+ for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++)
+ atable->amap[ii] = atable->amap[0];
+
+ // Add single character tokens to the atom table:
+
+ {
+ const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#";
+ char t[2];
+
+ t[1] = '\0';
+ while (*s) {
+ t[0] = *s;
+ AddAtomFixed(atable, t, s[0]);
+ s++;
+ }
+ }
+
+ // Add multiple character scanner tokens :
+
+ for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
+ AddAtomFixed(atable, tokens[ii].str, tokens[ii].val);
+
+ // Add error symbol if running in error mode:
+
+ if (cpp->options.ErrorMode)
+ AddAtomFixed(atable, "error", ERROR_SY);
+
+ AddAtom(atable, "<*** end fixed atoms ***>");
+
+ return 1;
+} // InitAtomTable
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////// Debug Printing Functions: //////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * PrintAtomTable()
+ *
+ */
+
+void PrintAtomTable(AtomTable *atable)
+{
+ int ii;
+ char str[200];
+
+ for (ii = 0; ii < atable->nextFree; ii++) {
+ snprintf(str, sizeof(str), "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]);
+ CPPDebugLogMsg(str);
+ }
+ snprintf(str, sizeof(str), "Hash table: size=%d, entries=%d, collisions=",
+ atable->htable.size, atable->htable.entries);
+ CPPDebugLogMsg(str);
+ for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) {
+ snprintf(str, sizeof(str), " %d", atable->htable.counts[ii]);
+ CPPDebugLogMsg(str);
+ }
+
+} // PrintAtomTable
+
+
+/*
+ * GetStringOfAtom()
+ *
+ */
+
+char* GetStringOfAtom(AtomTable *atable, int atom)
+{
+ char* chr_str;
+ chr_str=&atable->stable.strings[atable->amap[atom]];
+ return chr_str;
+} // GetStringOfAtom
+
+/*
+ * FreeAtomTable() - Free the atom table and associated memory
+ *
+ */
+
+void FreeAtomTable(AtomTable *atable)
+{
+ FreeStringTable(&atable->stable);
+ FreeHashTable(&atable->htable);
+ if (atable->amap)
+ free(atable->amap);
+ if (atable->arev)
+ free(atable->arev);
+ atable->amap = NULL;
+ atable->arev = NULL;
+ atable->nextFree = 0;
+ atable->size = 0;
+} // FreeAtomTable
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////// End of atom.c ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/atom.h b/src/3rdparty/angle/src/compiler/preprocessor/atom.h
new file mode 100644
index 0000000000..1d84c32515
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/atom.h
@@ -0,0 +1,63 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// atom.h
+//
+
+#if !defined(__ATOM_H)
+#define __ATOM_H 1
+
+typedef struct AtomTable_Rec AtomTable;
+
+extern AtomTable *atable;
+
+int InitAtomTable(AtomTable *atable, int htsize);
+void FreeAtomTable(AtomTable *atable);
+int AddAtom(AtomTable *atable, const char *s);
+void PrintAtomTable(AtomTable *atable);
+int LookUpAddString(AtomTable *atable, const char *s);
+const char *GetAtomString(AtomTable *atable, int atom);
+int GetReversedAtom(AtomTable *atable, int atom);
+char* GetStringOfAtom(AtomTable *atable, int atom);
+#endif // !defined(__ATOM_H)
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/compile.h b/src/3rdparty/angle/src/compiler/preprocessor/compile.h
new file mode 100644
index 0000000000..11808531cc
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/compile.h
@@ -0,0 +1,100 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// compile.h
+//
+
+#if !defined(__COMPILE_H)
+#define __COMPILE_H 1
+
+int InitCPPStruct(void);
+
+typedef struct Options_Rec{
+ const char *profileString;
+ int ErrorMode;
+ int Quiet;
+
+ // Debug The Compiler options:
+ int DumpAtomTable;
+} Options;
+
+#define MAX_IF_NESTING 64
+struct CPPStruct_Rec {
+ // Public members
+ SourceLoc *pLastSourceLoc; // Set at the start of each statement by the tree walkers
+ Options options; // Compile options and parameters
+
+ // Private members
+ SourceLoc lastSourceLoc;
+
+ // Scanner data:
+
+ SourceLoc *tokenLoc; // Source location of most recent token seen by the scanner
+ int mostRecentToken; // Most recent token seen by the scanner
+ InputSrc *currentInput;
+ int previous_token;
+ int pastFirstStatement; // used to make sure that #version is the first statement seen in the file, if present
+
+ void *pC; // storing the parseContext of the compile object in cpp.
+
+ // Private members:
+ SourceLoc ltokenLoc;
+ int ifdepth; //current #if-#else-#endif nesting in the cpp.c file (pre-processor)
+ int elsedepth[MAX_IF_NESTING];//Keep a track of #if depth..Max allowed is 64.
+ int elsetracker; //#if-#else and #endif constructs...Counter.
+ const char *ErrMsg;
+ int CompileError; //Indicate compile error when #error, #else,#elif mismatch.
+
+ //
+ // Globals used to communicate between PaParseStrings() and yy_input()and
+ // also across the files.(gen_glslang.cpp and scanner.c)
+ //
+ int PaWhichStr; // which string we're parsing
+ const int* PaStrLen; // array of lengths of the PaArgv strings
+ int PaArgc; // count of strings in the array
+ const char* const* PaArgv; // our array of strings to parse
+ unsigned int tokensBeforeEOF : 1;
+};
+
+#endif // !defined(__COMPILE_H)
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cpp.c b/src/3rdparty/angle/src/compiler/preprocessor/cpp.c
new file mode 100644
index 0000000000..8a1076b9df
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/cpp.c
@@ -0,0 +1,1118 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cpp.c
+//
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "common/angleutils.h"
+#include "compiler/preprocessor/slglobals.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4054)
+#pragma warning(disable: 4152)
+#pragma warning(disable: 4706)
+#endif
+
+static int CPPif(yystypepp * yylvalpp);
+
+/* Don't use memory.c's replacements, as we clean up properly here */
+#undef malloc
+#undef free
+
+static int bindAtom = 0;
+static int constAtom = 0;
+static int defaultAtom = 0;
+static int defineAtom = 0;
+static int definedAtom = 0;
+static int elseAtom = 0;
+static int elifAtom = 0;
+static int endifAtom = 0;
+static int ifAtom = 0;
+static int ifdefAtom = 0;
+static int ifndefAtom = 0;
+static int includeAtom = 0;
+static int lineAtom = 0;
+static int pragmaAtom = 0;
+static int texunitAtom = 0;
+static int undefAtom = 0;
+static int errorAtom = 0;
+static int __LINE__Atom = 0;
+static int __FILE__Atom = 0;
+static int __VERSION__Atom = 0;
+static int versionAtom = 0;
+static int extensionAtom = 0;
+
+static Scope *macros = 0;
+#define MAX_MACRO_ARGS 64
+
+static SourceLoc ifloc; /* outermost #if */
+
+int InitCPP(void)
+{
+ char buffer[64], *t;
+ const char *f;
+
+ // Add various atoms needed by the CPP line scanner:
+ bindAtom = LookUpAddString(atable, "bind");
+ constAtom = LookUpAddString(atable, "const");
+ defaultAtom = LookUpAddString(atable, "default");
+ defineAtom = LookUpAddString(atable, "define");
+ definedAtom = LookUpAddString(atable, "defined");
+ elifAtom = LookUpAddString(atable, "elif");
+ elseAtom = LookUpAddString(atable, "else");
+ endifAtom = LookUpAddString(atable, "endif");
+ ifAtom = LookUpAddString(atable, "if");
+ ifdefAtom = LookUpAddString(atable, "ifdef");
+ ifndefAtom = LookUpAddString(atable, "ifndef");
+ includeAtom = LookUpAddString(atable, "include");
+ lineAtom = LookUpAddString(atable, "line");
+ pragmaAtom = LookUpAddString(atable, "pragma");
+ texunitAtom = LookUpAddString(atable, "texunit");
+ undefAtom = LookUpAddString(atable, "undef");
+ errorAtom = LookUpAddString(atable, "error");
+ __LINE__Atom = LookUpAddString(atable, "__LINE__");
+ __FILE__Atom = LookUpAddString(atable, "__FILE__");
+ __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
+ versionAtom = LookUpAddString(atable, "version");
+ extensionAtom = LookUpAddString(atable, "extension");
+ macros = NewScopeInPool(mem_CreatePool(0, 0));
+ strcpy(buffer, "PROFILE_");
+ t = buffer + strlen(buffer);
+ f = cpp->options.profileString;
+ while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
+ *t++ = toupper(*f++);
+ *t = 0;
+
+ PredefineIntMacro("GL_ES", 1);
+ PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ return 1;
+} // InitCPP
+
+int FreeCPP(void)
+{
+ if (macros)
+ {
+ mem_FreePool(macros->pool);
+ macros = 0;
+ }
+
+ return 1;
+}
+
+int FinalCPP(void)
+{
+ if (cpp->ifdepth)
+ CPPErrorToInfoLog("#if mismatch");
+ return 1;
+}
+
+static int CPPdefine(yystypepp * yylvalpp)
+{
+ int token, name, args[MAX_MACRO_ARGS], argc;
+ const char *message;
+ MacroSymbol mac;
+ Symbol *symb;
+ SourceLoc dummyLoc;
+ memset(&mac, 0, sizeof(mac));
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != CPP_IDENTIFIER) {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ name = yylvalpp->sc_ident;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(' && !yylvalpp->sc_int) {
+ // gather arguments
+ argc = 0;
+ do {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (argc == 0 && token == ')') break;
+ if (token != CPP_IDENTIFIER) {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ if (argc < MAX_MACRO_ARGS)
+ args[argc++] = yylvalpp->sc_ident;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ } while (token == ',');
+ if (token != ')') {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ mac.argc = argc;
+ mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
+ memcpy(mac.args, args, argc * sizeof(int));
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
+ while (token != '\n') {
+ if (token == '\\') {
+ CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
+ return token;
+ } else if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #define preprocessor directive - expected a newline");
+ return 0;
+ }
+ RecordToken(mac.body, token, yylvalpp);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ };
+
+ symb = LookUpSymbol(macros, name);
+ if (symb) {
+ if (!symb->details.mac.undef) {
+ // already defined -- need to make sure they are identical
+ if (symb->details.mac.argc != mac.argc) goto error;
+ for (argc=0; argc < mac.argc; argc++)
+ if (symb->details.mac.args[argc] != mac.args[argc])
+ goto error;
+ RewindTokenStream(symb->details.mac.body);
+ RewindTokenStream(mac.body);
+ do {
+ int old_lval, old_token;
+ old_token = ReadToken(symb->details.mac.body, yylvalpp);
+ old_lval = yylvalpp->sc_int;
+ token = ReadToken(mac.body, yylvalpp);
+ if (token != old_token || yylvalpp->sc_int != old_lval) {
+ error:
+ StoreStr("Macro Redefined");
+ StoreStr(GetStringOfAtom(atable,name));
+ message=GetStrfromTStr();
+ DecLineNumber();
+ CPPShInfoLogMsg(message);
+ IncLineNumber();
+ ResetTString();
+ break; }
+ } while (token > 0);
+ }
+ //FreeMacro(&symb->details.mac);
+ } else {
+ dummyLoc.file = 0;
+ dummyLoc.line = 0;
+ symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
+ }
+ symb->details.mac = mac;
+ return '\n';
+} // CPPdefine
+
+static int CPPundef(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ Symbol *symb;
+ if(token == '\n'){
+ CPPErrorToInfoLog("#undef");
+ return token;
+ }
+ if (token != CPP_IDENTIFIER)
+ goto error;
+ symb = LookUpSymbol(macros, yylvalpp->sc_ident);
+ if (symb) {
+ symb->details.mac.undef = 1;
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ error:
+ CPPErrorToInfoLog("#undef");
+ }
+ return token;
+} // CPPundef
+
+/* CPPelse -- skip forward to appropriate spot. This is actually used
+** to skip to and #endif after seeing an #else, AND to skip to a #else,
+** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
+*/
+
+static int CPPelse(int matchelse, yystypepp * yylvalpp)
+{
+ int atom,depth=0;
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ while (token > 0) {
+ if (token != '#') {
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #else preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ continue;
+ }
+ if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
+ continue;
+ atom = yylvalpp->sc_ident;
+ if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
+ depth++; cpp->ifdepth++; cpp->elsetracker++;
+ if (cpp->ifdepth > MAX_IF_NESTING) {
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+ }
+ else if (atom == endifAtom) {
+ if(--depth<0){
+ if (cpp->elsetracker)
+ --cpp->elsetracker;
+ if (cpp->ifdepth)
+ --cpp->ifdepth;
+ break;
+ }
+ --cpp->elsetracker;
+ --cpp->ifdepth;
+ }
+ else if (((int)(matchelse) != 0)&& depth==0) {
+ if (atom == elseAtom ) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input following #else preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+ else if (atom == elifAtom) {
+ /* we decrement cpp->ifdepth here, because CPPif will increment
+ * it and we really want to leave it alone */
+ if (cpp->ifdepth){
+ --cpp->ifdepth;
+ --cpp->elsetracker;
+ }
+ return CPPif(yylvalpp);
+ }
+ }
+ else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
+ CPPErrorToInfoLog("#else after a #else");
+ cpp->CompileError=1;
+ return 0;
+ }
+ };
+ return token;
+}
+
+enum eval_prec {
+ MIN_PREC,
+ COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
+ MAX_PREC
+};
+
+static int op_logor(int a, int b) { return a || b; }
+static int op_logand(int a, int b) { return a && b; }
+static int op_or(int a, int b) { return a | b; }
+static int op_xor(int a, int b) { return a ^ b; }
+static int op_and(int a, int b) { return a & b; }
+static int op_eq(int a, int b) { return a == b; }
+static int op_ne(int a, int b) { return a != b; }
+static int op_ge(int a, int b) { return a >= b; }
+static int op_le(int a, int b) { return a <= b; }
+static int op_gt(int a, int b) { return a > b; }
+static int op_lt(int a, int b) { return a < b; }
+static int op_shl(int a, int b) { return a << b; }
+static int op_shr(int a, int b) { return a >> b; }
+static int op_add(int a, int b) { return a + b; }
+static int op_sub(int a, int b) { return a - b; }
+static int op_mul(int a, int b) { return a * b; }
+static int op_div(int a, int b) { return a / b; }
+static int op_mod(int a, int b) { return a % b; }
+static int op_pos(int a) { return a; }
+static int op_neg(int a) { return -a; }
+static int op_cmpl(int a) { return ~a; }
+static int op_not(int a) { return !a; }
+
+struct {
+ int token, prec, (*op)(int, int);
+} binop[] = {
+ { CPP_OR_OP, LOGOR, op_logor },
+ { CPP_AND_OP, LOGAND, op_logand },
+ { '|', OR, op_or },
+ { '^', XOR, op_xor },
+ { '&', AND, op_and },
+ { CPP_EQ_OP, EQUAL, op_eq },
+ { CPP_NE_OP, EQUAL, op_ne },
+ { '>', RELATION, op_gt },
+ { CPP_GE_OP, RELATION, op_ge },
+ { '<', RELATION, op_lt },
+ { CPP_LE_OP, RELATION, op_le },
+ { CPP_LEFT_OP, SHIFT, op_shl },
+ { CPP_RIGHT_OP, SHIFT, op_shr },
+ { '+', ADD, op_add },
+ { '-', ADD, op_sub },
+ { '*', MUL, op_mul },
+ { '/', MUL, op_div },
+ { '%', MUL, op_mod },
+};
+
+struct {
+ int token, (*op)(int);
+} unop[] = {
+ { '+', op_pos },
+ { '-', op_neg },
+ { '~', op_cmpl },
+ { '!', op_not },
+};
+
+#define ALEN(A) (sizeof(A)/sizeof(A[0]))
+
+static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
+{
+ int i, val;
+ Symbol *s;
+ if (token == CPP_IDENTIFIER) {
+ if (yylvalpp->sc_ident == definedAtom) {
+ int needclose = 0;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(') {
+ needclose = 1;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ if (token != CPP_IDENTIFIER)
+ goto error;
+ *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
+ ? !s->details.mac.undef : 0;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (needclose) {
+ if (token != ')')
+ goto error;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ return eval(token, prec, res, err, yylvalpp);
+ } else {
+ goto error;
+ }
+ } else if (token == CPP_INTCONSTANT) {
+ *res = yylvalpp->sc_int;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ } else if (token == '(') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, MIN_PREC, res, err, yylvalpp);
+ if (!*err) {
+ if (token != ')')
+ goto error;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ } else {
+ for (i = ALEN(unop) - 1; i >= 0; i--) {
+ if (unop[i].token == token)
+ break;
+ }
+ if (i >= 0) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, UNARY, res, err, yylvalpp);
+ *res = unop[i].op(*res);
+ } else {
+ goto error;
+ }
+ }
+ while (!*err) {
+ if (token == ')' || token == '\n') break;
+ for (i = ALEN(binop) - 1; i >= 0; i--) {
+ if (binop[i].token == token)
+ break;
+ }
+ if (i < 0 || binop[i].prec <= prec)
+ break;
+ val = *res;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, binop[i].prec, res, err, yylvalpp);
+
+ if (binop[i].op == op_div || binop[i].op == op_mod)
+ {
+ if (*res == 0)
+ {
+ CPPErrorToInfoLog("preprocessor divide or modulo by zero");
+ *err = 1;
+ return token;
+ }
+ }
+
+ *res = binop[i].op(val, *res);
+ }
+ return token;
+error:
+ CPPErrorToInfoLog("incorrect preprocessor directive");
+ *err = 1;
+ *res = 0;
+ return token;
+} // eval
+
+static int CPPif(yystypepp * yylvalpp) {
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ int res = 0, err = 0;
+
+ if (!cpp->ifdepth++)
+ ifloc = *cpp->tokenLoc;
+ if(cpp->ifdepth > MAX_IF_NESTING){
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsetracker++;
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+
+ token = eval(token, MIN_PREC, &res, &err, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #if preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #if preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ if (!res && !err) {
+ token = CPPelse(1, yylvalpp);
+ }
+
+ return token;
+} // CPPif
+
+static int CPPifdef(int defined, yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ int name = yylvalpp->sc_ident;
+ if(++cpp->ifdepth > MAX_IF_NESTING){
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsetracker++;
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+
+ if (token != CPP_IDENTIFIER) {
+ defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
+ } else {
+ Symbol *s = LookUpSymbol(macros, name);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
+ token = CPPelse(1, yylvalpp);
+ }
+ return token;
+} // CPPifdef
+
+static int CPPline(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if(token=='\n'){
+ DecLineNumber();
+ CPPErrorToInfoLog("#line");
+ IncLineNumber();
+ return token;
+ }
+ else if (token == CPP_INTCONSTANT) {
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ SetLineNumber(yylvalpp->sc_int);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token == CPP_INTCONSTANT) {
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ SetStringNumber(yylvalpp->sc_int);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if(token!='\n')
+ CPPErrorToInfoLog("#line");
+ }
+ else if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#line");
+ }
+ }
+ else{
+ CPPErrorToInfoLog("#line");
+ }
+ return token;
+}
+
+static int CPPerror(yystypepp * yylvalpp) {
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ const char *message;
+
+ while (token != '\n') {
+ if (token <= 0){
+ CPPErrorToInfoLog("unexpected end of input in #error preprocessor directive - expected a newline");
+ return 0;
+ }else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
+ StoreStr(yylvalpp->symbol_name);
+ }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
+ StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
+ }else {
+ StoreStr(GetStringOfAtom(atable,token));
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ DecLineNumber();
+ //store this msg into the shader's information log..set the Compile Error flag!!!!
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ cpp->CompileError=1;
+ IncLineNumber();
+ return '\n';
+}//CPPerror
+
+static int CPPpragma(yystypepp * yylvalpp)
+{
+ char SrcStrName[2];
+ char** allTokens;
+ int tokenCount = 0;
+ int maxTokenCount = 10;
+ const char* SrcStr;
+ int i;
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token=='\n') {
+ DecLineNumber();
+ CPPErrorToInfoLog("#pragma");
+ IncLineNumber();
+ return token;
+ }
+
+ allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
+
+ while (token != '\n') {
+ if (tokenCount >= maxTokenCount) {
+ maxTokenCount *= 2;
+ allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
+ }
+ switch (token) {
+ case CPP_IDENTIFIER:
+ SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case CPP_INTCONSTANT:
+ SrcStr = yylvalpp->symbol_name;
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case CPP_FLOATCONSTANT:
+ SrcStr = yylvalpp->symbol_name;
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case -1:
+ // EOF
+ CPPShInfoLogMsg("#pragma directive must end with a newline");
+ goto freeMemoryAndReturnToken;
+ default:
+ SrcStrName[0] = token;
+ SrcStrName[1] = '\0';
+ allTokens[tokenCount] = (char*)malloc(2);
+ strcpy(allTokens[tokenCount++], SrcStrName);
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+
+ HandlePragma((const char**)allTokens, tokenCount);
+
+freeMemoryAndReturnToken:
+ for (i = 0; i < tokenCount; ++i) {
+ free (allTokens[i]);
+ }
+ free (allTokens);
+
+ return token;
+} // CPPpragma
+
+#define ESSL_VERSION_NUMBER 100
+#define ESSL_VERSION_STRING "100"
+
+static int CPPversion(yystypepp * yylvalpp)
+{
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (cpp->pastFirstStatement == 1)
+ CPPShInfoLogMsg("#version must occur before any other statement in the program");
+
+ if(token=='\n'){
+ DecLineNumber();
+ CPPErrorToInfoLog("#version");
+ IncLineNumber();
+ return token;
+ }
+ if (token != CPP_INTCONSTANT)
+ CPPErrorToInfoLog("#version");
+
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ //SetVersionNumber(yylvalpp->sc_int);
+
+ if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
+ CPPShInfoLogMsg("Version number not supported by ESSL");
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#version");
+ }
+ return token;
+} // CPPversion
+
+static int CPPextension(yystypepp * yylvalpp)
+{
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ char extensionName[MAX_SYMBOL_NAME_LEN + 1];
+
+ if(token=='\n'){
+ DecLineNumber();
+ CPPShInfoLogMsg("extension name not specified");
+ IncLineNumber();
+ return token;
+ }
+
+ if (token != CPP_IDENTIFIER)
+ CPPErrorToInfoLog("#extension");
+
+ strncpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident), MAX_SYMBOL_NAME_LEN);
+ extensionName[MAX_SYMBOL_NAME_LEN] = '\0';
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != ':') {
+ CPPShInfoLogMsg("':' missing after extension name");
+ return token;
+ }
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != CPP_IDENTIFIER) {
+ CPPShInfoLogMsg("behavior for extension not specified");
+ return token;
+ }
+
+ updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#extension");
+ }
+ return token;
+} // CPPextension
+
+int readCPPline(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ const char *message;
+
+ if (token == CPP_IDENTIFIER) {
+ if (yylvalpp->sc_ident == defineAtom) {
+ token = CPPdefine(yylvalpp);
+ } else if (yylvalpp->sc_ident == elseAtom) {
+ if(ChkCorrectElseNesting()){
+ if (!cpp->ifdepth ){
+ CPPErrorToInfoLog("#else mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ token = CPPelse(0, yylvalpp);
+ }else{
+ CPPErrorToInfoLog("#else after a #else");
+ cpp->ifdepth = 0;
+ cpp->elsetracker = 0;
+ cpp->pastFirstStatement = 1;
+ cpp->CompileError = 1;
+ return 0;
+ }
+ } else if (yylvalpp->sc_ident == elifAtom) {
+ if (!cpp->ifdepth){
+ CPPErrorToInfoLog("#elif mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ // this token is really a dont care, but we still need to eat the tokens
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpect tokens following #elif preprocessor directive - expected a newline");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ }
+ token = CPPelse(0, yylvalpp);
+ } else if (yylvalpp->sc_ident == endifAtom) {
+ if (!cpp->ifdepth){
+ CPPErrorToInfoLog("#endif mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ else
+ --cpp->ifdepth;
+
+ if (cpp->elsetracker)
+ --cpp->elsetracker;
+
+ } else if (yylvalpp->sc_ident == ifAtom) {
+ token = CPPif(yylvalpp);
+ } else if (yylvalpp->sc_ident == ifdefAtom) {
+ token = CPPifdef(1, yylvalpp);
+ } else if (yylvalpp->sc_ident == ifndefAtom) {
+ token = CPPifdef(0, yylvalpp);
+ } else if (yylvalpp->sc_ident == lineAtom) {
+ token = CPPline(yylvalpp);
+ } else if (yylvalpp->sc_ident == pragmaAtom) {
+ token = CPPpragma(yylvalpp);
+ } else if (yylvalpp->sc_ident == undefAtom) {
+ token = CPPundef(yylvalpp);
+ } else if (yylvalpp->sc_ident == errorAtom) {
+ token = CPPerror(yylvalpp);
+ } else if (yylvalpp->sc_ident == versionAtom) {
+ token = CPPversion(yylvalpp);
+ } else if (yylvalpp->sc_ident == extensionAtom) {
+ token = CPPextension(yylvalpp);
+ } else {
+ StoreStr("Invalid Directive");
+ StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ }
+ }
+ while (token != '\n' && token != 0 && token != EOF) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+
+ cpp->pastFirstStatement = 1;
+
+ return token;
+} // readCPPline
+
+void FreeMacro(MacroSymbol *s) {
+ DeleteTokenStream(s->body);
+}
+
+void PredefineIntMacro(const char *name, int value) {
+ SourceLoc location = {0, 0};
+ Symbol *symbol = NULL;
+ MacroSymbol macro = {0, NULL, NULL, 0, 0};
+ yystypepp val = {0, 0.0, 0, {0}};
+ int atom = 0;
+
+ macro.body = NewTokenStream(name, macros->pool);
+ val.sc_int = value;
+ snprintf(val.symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", value);
+ RecordToken(macro.body, CPP_INTCONSTANT, &val);
+ atom = LookUpAddString(atable, name);
+ symbol = AddSymbol(&location, macros, atom, MACRO_S);
+ symbol->details.mac = macro;
+}
+
+static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
+static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
+
+static void PushEofSrc() {
+ InputSrc *in = malloc(sizeof(InputSrc));
+ memset(in, 0, sizeof(InputSrc));
+ in->scan = eof_scan;
+ in->getch = eof_scan;
+ in->ungetch = noop;
+ in->prev = cpp->currentInput;
+ cpp->currentInput = in;
+}
+
+static void PopEofSrc() {
+ if (cpp->currentInput->scan == eof_scan) {
+ InputSrc *in = cpp->currentInput;
+ cpp->currentInput = in->prev;
+ free(in);
+ }
+}
+
+static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
+ int token;
+ TokenStream *n;
+ RewindTokenStream(a);
+ do {
+ token = ReadToken(a, yylvalpp);
+ if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
+ break;
+ } while (token > 0);
+ if (token <= 0) return a;
+ n = NewTokenStream("macro arg", 0);
+ PushEofSrc();
+ ReadFromTokenStream(a, 0, 0);
+ while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
+ if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
+ continue;
+ RecordToken(n, token, yylvalpp);
+ }
+ PopEofSrc();
+ DeleteTokenStream(a);
+ return n;
+} // PrescanMacroArg
+
+typedef struct MacroInputSrc {
+ InputSrc base;
+ MacroSymbol *mac;
+ TokenStream **args;
+} MacroInputSrc;
+
+/* macro_scan ---
+** return the next token for a macro expanion, handling macro args
+*/
+static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
+ int i;
+ int token = ReadToken(in->mac->body, yylvalpp);
+ if (token == CPP_IDENTIFIER) {
+ for (i = in->mac->argc-1; i>=0; i--)
+ if (in->mac->args[i] == yylvalpp->sc_ident) break;
+ if (i >= 0) {
+ ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ }
+ if (token > 0) return token;
+ in->mac->busy = 0;
+ cpp->currentInput = in->base.prev;
+ if (in->args) {
+ for (i=in->mac->argc-1; i>=0; i--)
+ DeleteTokenStream(in->args[i]);
+ free(in->args);
+ }
+ free(in);
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+} // macro_scan
+
+/* MacroExpand
+** check an identifier (atom) to see if it a macro that should be expanded.
+** If it is, push an InputSrc that will produce the appropriate expansion
+** and return TRUE. If not, return FALSE.
+*/
+
+int MacroExpand(int atom, yystypepp * yylvalpp)
+{
+ Symbol *sym = LookUpSymbol(macros, atom);
+ MacroInputSrc *in;
+ int i,j, token, depth=0;
+ const char *message;
+ if (atom == __LINE__Atom) {
+ yylvalpp->sc_int = GetLineNumber();
+ snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", yylvalpp->sc_int);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (atom == __FILE__Atom) {
+ yylvalpp->sc_int = GetStringNumber();
+ snprintf(yylvalpp->symbol_name, MAX_SYMBOL_NAME_LEN+1, "%d", yylvalpp->sc_int);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (atom == __VERSION__Atom) {
+ strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
+ yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (!sym || sym->details.mac.undef) return 0;
+ if (sym->details.mac.busy) return 0; // no recursive expansions
+ in = malloc(sizeof(*in));
+ memset(in, 0, sizeof(*in));
+ in->base.scan = (void *)macro_scan;
+ in->base.line = cpp->currentInput->line;
+ in->base.name = cpp->currentInput->name;
+ in->mac = &sym->details.mac;
+ if (sym->details.mac.args) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '(') {
+ UngetToken(token, yylvalpp);
+ yylvalpp->sc_ident = atom;
+ return 0;
+ }
+ in->args = malloc(in->mac->argc * sizeof(TokenStream *));
+ for (i=0; i<in->mac->argc; i++)
+ in->args[i] = NewTokenStream("macro arg", 0);
+ i=0;j=0;
+ do{
+ depth = 0;
+ while(1) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) {
+ StoreStr("EOF in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ return 1;
+ }
+ if((in->mac->argc==0) && (token!=')')) break;
+ if (depth == 0 && (token == ',' || token == ')')) break;
+ if (token == '(') depth++;
+ if (token == ')') depth--;
+ RecordToken(in->args[i], token, yylvalpp);
+ j=1;
+ }
+ if (token == ')') {
+ if((in->mac->argc==1) &&j==0)
+ break;
+ i++;
+ break;
+ }
+ i++;
+ }while(i < in->mac->argc);
+
+ if (i < in->mac->argc) {
+ StoreStr("Too few args in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ } else if (token != ')') {
+ depth=0;
+ while (token >= 0 && (depth > 0 || token != ')')) {
+ if (token == ')') depth--;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(') depth++;
+ }
+
+ if (token <= 0) {
+ StoreStr("EOF in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ return 1;
+ }
+ StoreStr("Too many args in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ }
+ for (i=0; i<in->mac->argc; i++) {
+ in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
+ }
+ }
+#if 0
+ printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
+ loc.line, GetAtomString(atable, atom));
+ for (i=0; i<in->mac->argc; i++) {
+ printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
+ DumpTokenStream(stdout, in->args[i]);
+ printf("'\n");
+ }
+#endif
+ /*retain the input source*/
+ in->base.prev = cpp->currentInput;
+ sym->details.mac.busy = 1;
+ RewindTokenStream(sym->details.mac.body);
+ cpp->currentInput = &in->base;
+ return 1;
+} // MacroExpand
+
+int ChkCorrectElseNesting(void)
+{
+ // sanity check to make sure elsetracker is in a valid range
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ return 0;
+ }
+
+ if (cpp->elsedepth[cpp->elsetracker] == 0) {
+ cpp->elsedepth[cpp->elsetracker] = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cpp.h b/src/3rdparty/angle/src/compiler/preprocessor/cpp.h
new file mode 100644
index 0000000000..802e23ef07
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/cpp.h
@@ -0,0 +1,86 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cpp.h
+//
+
+#if !defined(__CPP_H)
+#define __CPP_H 1
+
+#include "compiler/preprocessor/parser.h"
+#include "compiler/preprocessor/tokens.h"
+
+int InitCPP(void);
+int FinalCPP(void);
+int readCPPline(yystypepp * yylvalpp);
+int MacroExpand(int atom, yystypepp * yylvalpp);
+int ChkCorrectElseNesting(void);
+
+typedef struct MacroSymbol {
+ int argc;
+ int *args;
+ TokenStream *body;
+ unsigned busy:1;
+ unsigned undef:1;
+} MacroSymbol;
+
+void FreeMacro(MacroSymbol *);
+void PredefineIntMacro(const char *name, int value);
+
+void CPPDebugLogMsg(const char *msg); // Prints information into debug log
+void CPPShInfoLogMsg(const char*); // Store cpp Err Msg into Sh.Info.Log
+void CPPWarningToInfoLog(const char *msg); // Prints warning messages into info log
+void HandlePragma(const char**, int numTokens); // #pragma directive container.
+void ResetTString(void); // #error Message as TString.
+void CPPErrorToInfoLog(const char*); // Stick all cpp errors into Sh.Info.log.
+void StoreStr(const char*); // Store the TString in Parse Context.
+void SetLineNumber(int); // Set line number.
+void SetStringNumber(int); // Set string number.
+int GetLineNumber(void); // Get the current String Number.
+int GetStringNumber(void); // Get the current String Number.
+const char* GetStrfromTStr(void); // Convert TString to String.
+void updateExtensionBehavior(const char* extName, const char* behavior);
+int FreeCPP(void);
+
+#endif // !(defined(__CPP_H)
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c b/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c
new file mode 100644
index 0000000000..58cff31091
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/cppstruct.c
@@ -0,0 +1,152 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cppstruct.c
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "compiler/preprocessor/slglobals.h"
+
+CPPStruct *cpp = NULL;
+static int refCount = 0;
+
+int InitPreprocessor(void);
+int ResetPreprocessor(void);
+int FreeCPPStruct(void);
+int FinalizePreprocessor(void);
+
+/*
+ * InitCPPStruct() - Initilaize the CPP structure.
+ *
+ */
+
+int InitCPPStruct(void)
+{
+ int len;
+ char *p;
+
+ cpp = (CPPStruct *) malloc(sizeof(CPPStruct));
+ if (cpp == NULL)
+ return 0;
+
+ refCount++;
+
+ // Initialize public members:
+ cpp->pLastSourceLoc = &cpp->lastSourceLoc;
+
+ p = (char *) &cpp->options;
+ len = sizeof(cpp->options);
+ while (--len >= 0)
+ p[len] = 0;
+
+ ResetPreprocessor();
+ return 1;
+} // InitCPPStruct
+
+int ResetPreprocessor(void)
+{
+ // Initialize private members:
+
+ cpp->lastSourceLoc.file = 0;
+ cpp->lastSourceLoc.line = 0;
+ cpp->pC = 0;
+ cpp->CompileError = 0;
+ cpp->ifdepth = 0;
+ for(cpp->elsetracker = 0; cpp->elsetracker < MAX_IF_NESTING; cpp->elsetracker++)
+ cpp->elsedepth[cpp->elsetracker] = 0;
+ cpp->elsetracker = 0;
+ cpp->tokensBeforeEOF = 0;
+ return 1;
+}
+
+//Intializing the Preprocessor.
+
+int InitPreprocessor(void)
+{
+ # define CPP_STUFF true
+ # ifdef CPP_STUFF
+ FreeCPPStruct();
+ InitCPPStruct();
+ cpp->options.Quiet = 1;
+ cpp->options.profileString = "generic";
+ if (!InitAtomTable(atable, 0))
+ return 1;
+ if (!InitScanner(cpp))
+ return 1;
+ # endif
+ return 0;
+}
+
+//FreeCPPStruct() - Free the CPP structure.
+
+int FreeCPPStruct(void)
+{
+ if (refCount)
+ {
+ free(cpp);
+ refCount--;
+ }
+
+ return 1;
+}
+
+//Finalizing the Preprocessor.
+
+int FinalizePreprocessor(void)
+{
+ # define CPP_STUFF true
+ # ifdef CPP_STUFF
+ FreeAtomTable(atable);
+ FreeCPPStruct();
+ FreeScanner();
+ # endif
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////// End of cppstruct.c //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h b/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h
new file mode 100644
index 0000000000..4f1f71319f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/length_limits.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// length_limits.h
+//
+
+#if !defined(__LENGTH_LIMITS_H)
+#define __LENGTH_LIMITS_H 1
+
+// These constants are factored out from the rest of the headers to
+// make it easier to reference them from the compiler sources.
+
+// These lengths do not include the NULL terminator.
+#define MAX_SYMBOL_NAME_LEN 256
+#define MAX_STRING_LEN 511
+
+#endif // !(defined(__LENGTH_LIMITS_H)
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/memory.c b/src/3rdparty/angle/src/compiler/preprocessor/memory.c
new file mode 100644
index 0000000000..029521a559
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/memory.c
@@ -0,0 +1,158 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+
+#include "compiler/preprocessor/memory.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4706)
+#endif
+
+// default alignment and chunksize, if called with 0 arguments
+#define CHUNKSIZE (64*1024)
+#define ALIGN 8
+
+// we need to call the `real' malloc and free, not our replacements
+#undef malloc
+#undef free
+
+struct chunk {
+ struct chunk *next;
+};
+
+struct cleanup {
+ struct cleanup *next;
+ void (*fn)(void *);
+ void *arg;
+};
+
+struct MemoryPool_rec {
+ struct chunk *next;
+ uintptr_t free, end;
+ size_t chunksize;
+ uintptr_t alignmask;
+ struct cleanup *cleanup;
+};
+
+MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align)
+{
+ MemoryPool *pool;
+
+ if (align == 0) align = ALIGN;
+ if (chunksize == 0) chunksize = CHUNKSIZE;
+ if (align & (align-1)) return 0;
+ if (chunksize < sizeof(MemoryPool)) return 0;
+ if (chunksize & (align-1)) return 0;
+ if (!(pool = malloc(chunksize))) return 0;
+ pool->next = 0;
+ pool->chunksize = chunksize;
+ pool->alignmask = (uintptr_t)(align)-1;
+ pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask;
+ pool->end = (uintptr_t)pool + chunksize;
+ pool->cleanup = 0;
+ return pool;
+}
+
+void mem_FreePool(MemoryPool *pool)
+{
+ struct cleanup *cleanup;
+ struct chunk *p, *next;
+
+ for (cleanup = pool->cleanup; cleanup; cleanup = cleanup->next) {
+ cleanup->fn(cleanup->arg);
+ }
+ for (p = (struct chunk *)pool; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+}
+
+void *mem_Alloc(MemoryPool *pool, size_t size)
+{
+ struct chunk *ch;
+ void *rv = (void *)pool->free;
+ size = (size + pool->alignmask) & ~pool->alignmask;
+ if (size <= 0) size = pool->alignmask;
+ pool->free += size;
+ if (pool->free > pool->end || pool->free < (uintptr_t)rv) {
+ size_t minreq = (size + sizeof(struct chunk) + pool->alignmask)
+ & ~pool->alignmask;
+ pool->free = (uintptr_t)rv;
+ if (minreq >= pool->chunksize) {
+ // request size is too big for the chunksize, so allocate it as
+ // a single chunk of the right size
+ ch = malloc(minreq);
+ if (!ch) return 0;
+ } else {
+ ch = malloc(pool->chunksize);
+ if (!ch) return 0;
+ pool->free = (uintptr_t)ch + minreq;
+ pool->end = (uintptr_t)ch + pool->chunksize;
+ }
+ ch->next = pool->next;
+ pool->next = ch;
+ rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask);
+ }
+ return rv;
+}
+
+int mem_AddCleanup(MemoryPool *pool, void (*fn)(void *), void *arg) {
+ struct cleanup *cleanup;
+
+ pool->free = (pool->free + sizeof(void *) - 1) & ~(sizeof(void *)-1);
+ cleanup = mem_Alloc(pool, sizeof(struct cleanup));
+ if (!cleanup) return -1;
+ cleanup->next = pool->cleanup;
+ cleanup->fn = fn;
+ cleanup->arg = arg;
+ pool->cleanup = cleanup;
+ return 0;
+}
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/memory.h b/src/3rdparty/angle/src/compiler/preprocessor/memory.h
new file mode 100644
index 0000000000..5fcadb32f6
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/memory.h
@@ -0,0 +1,58 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+#ifndef __MEMORY_H
+#define __MEMORY_H
+
+#include <stddef.h>
+
+typedef struct MemoryPool_rec MemoryPool;
+
+extern MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align);
+extern void mem_FreePool(MemoryPool *);
+extern void *mem_Alloc(MemoryPool *p, size_t size);
+extern void *mem_Realloc(MemoryPool *p, void *old, size_t oldsize, size_t newsize);
+extern int mem_AddCleanup(MemoryPool *p, void (*fn)(void *), void *arg);
+
+#endif /* __MEMORY_H */
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp
new file mode 100644
index 0000000000..3f50dfc98a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Diagnostics.h"
+
+#include <cassert>
+
+namespace pp
+{
+
+Diagnostics::~Diagnostics()
+{
+}
+
+void Diagnostics::report(ID id,
+ const SourceLocation& loc,
+ const std::string& text)
+{
+ // TODO(alokp): Keep a count of errors and warnings.
+ print(id, loc, text);
+}
+
+Diagnostics::Severity Diagnostics::severity(ID id)
+{
+ if ((id > ERROR_BEGIN) && (id < ERROR_END))
+ return ERROR;
+
+ if ((id > WARNING_BEGIN) && (id < WARNING_END))
+ return WARNING;
+
+ assert(false);
+ return ERROR;
+}
+
+std::string Diagnostics::message(ID id)
+{
+ switch (id)
+ {
+ // Errors begin.
+ case INTERNAL_ERROR:
+ return "internal error";
+ case OUT_OF_MEMORY:
+ return "out of memory";
+ case INVALID_CHARACTER:
+ return "invalid character";
+ case INVALID_NUMBER:
+ return "invalid number";
+ case INTEGER_OVERFLOW:
+ return "integer overflow";
+ case FLOAT_OVERFLOW:
+ return "float overflow";
+ case TOKEN_TOO_LONG:
+ return "token too long";
+ case INVALID_EXPRESSION:
+ return "invalid expression";
+ case DIVISION_BY_ZERO:
+ return "division by zero";
+ case EOF_IN_COMMENT:
+ return "unexpected end of file found in comment";
+ case UNEXPECTED_TOKEN:
+ return "unexpected token";
+ case DIRECTIVE_INVALID_NAME:
+ return "invalid directive name";
+ case MACRO_NAME_RESERVED:
+ return "macro name is reserved";
+ case MACRO_REDEFINED:
+ return "macro redefined";
+ case MACRO_PREDEFINED_REDEFINED:
+ return "predefined macro redefined";
+ case MACRO_PREDEFINED_UNDEFINED:
+ return "predefined macro undefined";
+ case MACRO_UNTERMINATED_INVOCATION:
+ return "unterminated macro invocation";
+ case MACRO_TOO_FEW_ARGS:
+ return "Not enough arguments for macro";
+ case MACRO_TOO_MANY_ARGS:
+ return "Too many arguments for macro";
+ case CONDITIONAL_ENDIF_WITHOUT_IF:
+ return "unexpected #endif found without a matching #if";
+ case CONDITIONAL_ELSE_WITHOUT_IF:
+ return "unexpected #else found without a matching #if";
+ case CONDITIONAL_ELSE_AFTER_ELSE:
+ return "unexpected #else found after another #else";
+ case CONDITIONAL_ELIF_WITHOUT_IF:
+ return "unexpected #elif found without a matching #if";
+ case CONDITIONAL_ELIF_AFTER_ELSE:
+ return "unexpected #elif found after #else";
+ case CONDITIONAL_UNTERMINATED:
+ return "unexpected end of file found in conditional block";
+ case INVALID_EXTENSION_NAME:
+ return "invalid extension name";
+ case INVALID_EXTENSION_BEHAVIOR:
+ return "invalid extension behavior";
+ case INVALID_EXTENSION_DIRECTIVE:
+ return "invalid extension directive";
+ case INVALID_VERSION_NUMBER:
+ return "invalid version number";
+ case INVALID_VERSION_DIRECTIVE:
+ return "invalid version directive";
+ case VERSION_NOT_FIRST_STATEMENT:
+ return "#version directive must occur before anything else, "
+ "except for comments and white space";
+ case INVALID_LINE_NUMBER:
+ return "invalid line number";
+ case INVALID_FILE_NUMBER:
+ return "invalid file number";
+ case INVALID_LINE_DIRECTIVE:
+ return "invalid line directive";
+ // Errors end.
+ // Warnings begin.
+ case EOF_IN_DIRECTIVE:
+ return "unexpected end of file found in directive";
+ case CONDITIONAL_UNEXPECTED_TOKEN:
+ return "unexpected token after conditional expression";
+ case UNRECOGNIZED_PRAGMA:
+ return "unrecognized pragma";
+ // Warnings end.
+ default:
+ assert(false);
+ return "";
+ }
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h
new file mode 100644
index 0000000000..07bc411846
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Diagnostics.h
@@ -0,0 +1,87 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for reporting diagnostic messages.
+// Derived classes are responsible for formatting and printing the messages.
+class Diagnostics
+{
+ public:
+ enum Severity
+ {
+ ERROR,
+ WARNING
+ };
+ enum ID
+ {
+ ERROR_BEGIN,
+ INTERNAL_ERROR,
+ OUT_OF_MEMORY,
+ INVALID_CHARACTER,
+ INVALID_NUMBER,
+ INTEGER_OVERFLOW,
+ FLOAT_OVERFLOW,
+ TOKEN_TOO_LONG,
+ INVALID_EXPRESSION,
+ DIVISION_BY_ZERO,
+ EOF_IN_COMMENT,
+ UNEXPECTED_TOKEN,
+ DIRECTIVE_INVALID_NAME,
+ MACRO_NAME_RESERVED,
+ MACRO_REDEFINED,
+ MACRO_PREDEFINED_REDEFINED,
+ MACRO_PREDEFINED_UNDEFINED,
+ MACRO_UNTERMINATED_INVOCATION,
+ MACRO_TOO_FEW_ARGS,
+ MACRO_TOO_MANY_ARGS,
+ CONDITIONAL_ENDIF_WITHOUT_IF,
+ CONDITIONAL_ELSE_WITHOUT_IF,
+ CONDITIONAL_ELSE_AFTER_ELSE,
+ CONDITIONAL_ELIF_WITHOUT_IF,
+ CONDITIONAL_ELIF_AFTER_ELSE,
+ CONDITIONAL_UNTERMINATED,
+ INVALID_EXTENSION_NAME,
+ INVALID_EXTENSION_BEHAVIOR,
+ INVALID_EXTENSION_DIRECTIVE,
+ INVALID_VERSION_NUMBER,
+ INVALID_VERSION_DIRECTIVE,
+ VERSION_NOT_FIRST_STATEMENT,
+ INVALID_LINE_NUMBER,
+ INVALID_FILE_NUMBER,
+ INVALID_LINE_DIRECTIVE,
+ ERROR_END,
+
+ WARNING_BEGIN,
+ EOF_IN_DIRECTIVE,
+ CONDITIONAL_UNEXPECTED_TOKEN,
+ UNRECOGNIZED_PRAGMA,
+ WARNING_END
+ };
+
+ virtual ~Diagnostics();
+
+ void report(ID id, const SourceLocation& loc, const std::string& text);
+
+ protected:
+ Severity severity(ID id);
+ std::string message(ID id);
+
+ virtual void print(ID id,
+ const SourceLocation& loc,
+ const std::string& text) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp
new file mode 100644
index 0000000000..ca91e1c71b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.cpp
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "DirectiveHandler.h"
+
+namespace pp
+{
+
+DirectiveHandler::~DirectiveHandler()
+{
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h
new file mode 100644
index 0000000000..2aaeec2818
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveHandler.h
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for handling directives.
+// Preprocessor uses this class to notify the clients about certain
+// preprocessor directives. Derived classes are responsible for
+// handling them in an appropriate manner.
+class DirectiveHandler
+{
+ public:
+ virtual ~DirectiveHandler();
+
+ virtual void handleError(const SourceLocation& loc,
+ const std::string& msg) = 0;
+
+ // Handle pragma of form: #pragma name[(value)]
+ virtual void handlePragma(const SourceLocation& loc,
+ const std::string& name,
+ const std::string& value) = 0;
+
+ virtual void handleExtension(const SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior) = 0;
+
+ virtual void handleVersion(const SourceLocation& loc,
+ int version) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp
new file mode 100644
index 0000000000..f2e42d06bf
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.cpp
@@ -0,0 +1,932 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "DirectiveParser.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <sstream>
+
+#include "Diagnostics.h"
+#include "DirectiveHandler.h"
+#include "ExpressionParser.h"
+#include "MacroExpander.h"
+#include "Token.h"
+#include "Tokenizer.h"
+
+namespace {
+enum DirectiveType
+{
+ DIRECTIVE_NONE,
+ DIRECTIVE_DEFINE,
+ DIRECTIVE_UNDEF,
+ DIRECTIVE_IF,
+ DIRECTIVE_IFDEF,
+ DIRECTIVE_IFNDEF,
+ DIRECTIVE_ELSE,
+ DIRECTIVE_ELIF,
+ DIRECTIVE_ENDIF,
+ DIRECTIVE_ERROR,
+ DIRECTIVE_PRAGMA,
+ DIRECTIVE_EXTENSION,
+ DIRECTIVE_VERSION,
+ DIRECTIVE_LINE
+};
+} // namespace
+
+static DirectiveType getDirective(const pp::Token* token)
+{
+ static const std::string kDirectiveDefine("define");
+ static const std::string kDirectiveUndef("undef");
+ static const std::string kDirectiveIf("if");
+ static const std::string kDirectiveIfdef("ifdef");
+ static const std::string kDirectiveIfndef("ifndef");
+ static const std::string kDirectiveElse("else");
+ static const std::string kDirectiveElif("elif");
+ static const std::string kDirectiveEndif("endif");
+ static const std::string kDirectiveError("error");
+ static const std::string kDirectivePragma("pragma");
+ static const std::string kDirectiveExtension("extension");
+ static const std::string kDirectiveVersion("version");
+ static const std::string kDirectiveLine("line");
+
+ if (token->type != pp::Token::IDENTIFIER)
+ return DIRECTIVE_NONE;
+
+ if (token->text == kDirectiveDefine)
+ return DIRECTIVE_DEFINE;
+ else if (token->text == kDirectiveUndef)
+ return DIRECTIVE_UNDEF;
+ else if (token->text == kDirectiveIf)
+ return DIRECTIVE_IF;
+ else if (token->text == kDirectiveIfdef)
+ return DIRECTIVE_IFDEF;
+ else if (token->text == kDirectiveIfndef)
+ return DIRECTIVE_IFNDEF;
+ else if (token->text == kDirectiveElse)
+ return DIRECTIVE_ELSE;
+ else if (token->text == kDirectiveElif)
+ return DIRECTIVE_ELIF;
+ else if (token->text == kDirectiveEndif)
+ return DIRECTIVE_ENDIF;
+ else if (token->text == kDirectiveError)
+ return DIRECTIVE_ERROR;
+ else if (token->text == kDirectivePragma)
+ return DIRECTIVE_PRAGMA;
+ else if (token->text == kDirectiveExtension)
+ return DIRECTIVE_EXTENSION;
+ else if (token->text == kDirectiveVersion)
+ return DIRECTIVE_VERSION;
+ else if (token->text == kDirectiveLine)
+ return DIRECTIVE_LINE;
+
+ return DIRECTIVE_NONE;
+}
+
+static bool isConditionalDirective(DirectiveType directive)
+{
+ switch (directive)
+ {
+ case DIRECTIVE_IF:
+ case DIRECTIVE_IFDEF:
+ case DIRECTIVE_IFNDEF:
+ case DIRECTIVE_ELSE:
+ case DIRECTIVE_ELIF:
+ case DIRECTIVE_ENDIF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true if the token represents End Of Directive.
+static bool isEOD(const pp::Token* token)
+{
+ return (token->type == '\n') || (token->type == pp::Token::LAST);
+}
+
+static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+{
+ while(!isEOD(token))
+ {
+ lexer->lex(token);
+ }
+}
+
+static bool isMacroNameReserved(const std::string& name)
+{
+ // Names prefixed with "GL_" are reserved.
+ if (name.substr(0, 3) == "GL_")
+ return true;
+
+ // Names containing two consecutive underscores are reserved.
+ if (name.find("__") != std::string::npos)
+ return true;
+
+ return false;
+}
+
+static bool isMacroPredefined(const std::string& name,
+ const pp::MacroSet& macroSet)
+{
+ pp::MacroSet::const_iterator iter = macroSet.find(name);
+ return iter != macroSet.end() ? iter->second.predefined : false;
+}
+
+namespace pp
+{
+
+class DefinedParser : public Lexer
+{
+ public:
+ DefinedParser(Lexer* lexer,
+ const MacroSet* macroSet,
+ Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics)
+ {
+ }
+
+ protected:
+ virtual void lex(Token* token)
+ {
+ static const std::string kDefined("defined");
+
+ mLexer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ return;
+ if (token->text != kDefined)
+ return;
+
+ bool paren = false;
+ mLexer->lex(token);
+ if (token->type == '(')
+ {
+ paren = true;
+ mLexer->lex(token);
+ }
+
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mLexer, token);
+ return;
+ }
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ std::string expression = iter != mMacroSet->end() ? "1" : "0";
+
+ if (paren)
+ {
+ mLexer->lex(token);
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mLexer, token);
+ return;
+ }
+ }
+
+ // We have a valid defined operator.
+ // Convert the current token into a CONST_INT token.
+ token->type = Token::CONST_INT;
+ token->text = expression;
+ }
+
+ private:
+ Lexer* mLexer;
+ const MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+};
+
+DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler) :
+ mPastFirstStatement(false),
+ mTokenizer(tokenizer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics),
+ mDirectiveHandler(directiveHandler)
+{
+}
+
+void DirectiveParser::lex(Token* token)
+{
+ do
+ {
+ mTokenizer->lex(token);
+
+ if (token->type == Token::PP_HASH)
+ {
+ parseDirective(token);
+ mPastFirstStatement = true;
+ }
+
+ if (token->type == Token::LAST)
+ {
+ if (!mConditionalStack.empty())
+ {
+ const ConditionalBlock& block = mConditionalStack.back();
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+ block.location, block.type);
+ }
+ break;
+ }
+
+ } while (skipping() || (token->type == '\n'));
+
+ mPastFirstStatement = true;
+}
+
+void DirectiveParser::parseDirective(Token* token)
+{
+ assert(token->type == Token::PP_HASH);
+
+ mTokenizer->lex(token);
+ if (isEOD(token))
+ {
+ // Empty Directive.
+ return;
+ }
+
+ DirectiveType directive = getDirective(token);
+
+ // While in an excluded conditional block/group,
+ // we only parse conditional directives.
+ if (skipping() && !isConditionalDirective(directive))
+ {
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ switch(directive)
+ {
+ case DIRECTIVE_NONE:
+ mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ break;
+ case DIRECTIVE_DEFINE:
+ parseDefine(token);
+ break;
+ case DIRECTIVE_UNDEF:
+ parseUndef(token);
+ break;
+ case DIRECTIVE_IF:
+ parseIf(token);
+ break;
+ case DIRECTIVE_IFDEF:
+ parseIfdef(token);
+ break;
+ case DIRECTIVE_IFNDEF:
+ parseIfndef(token);
+ break;
+ case DIRECTIVE_ELSE:
+ parseElse(token);
+ break;
+ case DIRECTIVE_ELIF:
+ parseElif(token);
+ break;
+ case DIRECTIVE_ENDIF:
+ parseEndif(token);
+ break;
+ case DIRECTIVE_ERROR:
+ parseError(token);
+ break;
+ case DIRECTIVE_PRAGMA:
+ parsePragma(token);
+ break;
+ case DIRECTIVE_EXTENSION:
+ parseExtension(token);
+ break;
+ case DIRECTIVE_VERSION:
+ parseVersion(token);
+ break;
+ case DIRECTIVE_LINE:
+ parseLine(token);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ skipUntilEOD(mTokenizer, token);
+ if (token->type == Token::LAST)
+ {
+ mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+ token->location, token->text);
+ }
+}
+
+void DirectiveParser::parseDefine(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_DEFINE);
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ return;
+ }
+ if (isMacroPredefined(token->text, *mMacroSet))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ token->location, token->text);
+ return;
+ }
+ if (isMacroNameReserved(token->text))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+ token->location, token->text);
+ return;
+ }
+
+ Macro macro;
+ macro.type = Macro::kTypeObj;
+ macro.name = token->text;
+
+ mTokenizer->lex(token);
+ if (token->type == '(' && !token->hasLeadingSpace())
+ {
+ // Function-like macro. Collect arguments.
+ macro.type = Macro::kTypeFunc;
+ do {
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ break;
+ macro.parameters.push_back(token->text);
+
+ mTokenizer->lex(token); // Get ','.
+ } while (token->type == ',');
+
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location,
+ token->text);
+ return;
+ }
+ mTokenizer->lex(token); // Get ')'.
+ }
+
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ // Reset the token location because it is unnecessary in replacement
+ // list. Resetting it also allows us to reuse Token::equals() to
+ // compare macros.
+ token->location = SourceLocation();
+ macro.replacements.push_back(*token);
+ mTokenizer->lex(token);
+ }
+ if (!macro.replacements.empty())
+ {
+ // Whitespace preceding the replacement list is not considered part of
+ // the replacement list for either form of macro.
+ macro.replacements.front().setHasLeadingSpace(false);
+ }
+
+ // Check for macro redefinition.
+ MacroSet::const_iterator iter = mMacroSet->find(macro.name);
+ if (iter != mMacroSet->end() && !macro.equals(iter->second))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
+ token->location,
+ macro.name);
+ return;
+ }
+ mMacroSet->insert(std::make_pair(macro.name, macro));
+}
+
+void DirectiveParser::parseUndef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_UNDEF);
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ return;
+ }
+
+ MacroSet::iterator iter = mMacroSet->find(token->text);
+ if (iter != mMacroSet->end())
+ {
+ if (iter->second.predefined)
+ {
+ mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ token->location, token->text);
+ }
+ else
+ {
+ mMacroSet->erase(iter);
+ }
+ }
+
+ mTokenizer->lex(token);
+}
+
+void DirectiveParser::parseIf(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfdef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IFDEF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfndef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IFNDEF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseElse(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ELSE);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ ConditionalBlock& block = mConditionalStack.back();
+ if (block.skipBlock)
+ {
+ // No diagnostics. Just skip the whole line.
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundElseGroup)
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ block.foundElseGroup = true;
+ block.skipGroup = block.foundValidGroup;
+ block.foundValidGroup = true;
+
+ // Warn if there are extra tokens after #else.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+}
+
+void DirectiveParser::parseElif(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ELIF);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ ConditionalBlock& block = mConditionalStack.back();
+ if (block.skipBlock)
+ {
+ // No diagnostics. Just skip the whole line.
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundElseGroup)
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundValidGroup)
+ {
+ // Do not parse the expression.
+ // Also be careful not to emit a diagnostic.
+ block.skipGroup = true;
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ int expression = parseExpressionIf(token);
+ block.skipGroup = expression == 0;
+ block.foundValidGroup = expression != 0;
+}
+
+void DirectiveParser::parseEndif(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ENDIF);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ mConditionalStack.pop_back();
+
+ // Warn if there are tokens after #endif.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+}
+
+void DirectiveParser::parseError(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ERROR);
+
+ std::ostringstream stream;
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ stream << *token;
+ mTokenizer->lex(token);
+ }
+ mDirectiveHandler->handleError(token->location, stream.str());
+}
+
+// Parses pragma of form: #pragma name[(value)].
+void DirectiveParser::parsePragma(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_PRAGMA);
+
+ enum State
+ {
+ PRAGMA_NAME,
+ LEFT_PAREN,
+ PRAGMA_VALUE,
+ RIGHT_PAREN
+ };
+
+ bool valid = true;
+ std::string name, value;
+ int state = PRAGMA_NAME;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch(state++)
+ {
+ case PRAGMA_NAME:
+ name = token->text;
+ valid = valid && (token->type == Token::IDENTIFIER);
+ break;
+ case LEFT_PAREN:
+ valid = valid && (token->type == '(');
+ break;
+ case PRAGMA_VALUE:
+ value = token->text;
+ valid = valid && (token->type == Token::IDENTIFIER);
+ break;
+ case RIGHT_PAREN:
+ valid = valid && (token->type == ')');
+ break;
+ default:
+ valid = false;
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+
+ valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
+ (state == LEFT_PAREN) || // Without value.
+ (state == RIGHT_PAREN + 1)); // With value.
+ if (!valid)
+ {
+ mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
+ token->location, name);
+ }
+ else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
+ {
+ mDirectiveHandler->handlePragma(token->location, name, value);
+ }
+}
+
+void DirectiveParser::parseExtension(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_EXTENSION);
+
+ enum State
+ {
+ EXT_NAME,
+ COLON,
+ EXT_BEHAVIOR
+ };
+
+ bool valid = true;
+ std::string name, behavior;
+ int state = EXT_NAME;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case EXT_NAME:
+ if (valid && (token->type != Token::IDENTIFIER))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid) name = token->text;
+ break;
+ case COLON:
+ if (valid && (token->type != ':'))
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ case EXT_BEHAVIOR:
+ if (valid && (token->type != Token::IDENTIFIER))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid) behavior = token->text;
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+ if (valid && (state != EXT_BEHAVIOR + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ mDirectiveHandler->handleExtension(token->location, name, behavior);
+}
+
+void DirectiveParser::parseVersion(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_VERSION);
+
+ if (mPastFirstStatement)
+ {
+ mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ enum State
+ {
+ VERSION_NUMBER
+ };
+
+ bool valid = true;
+ int version = 0;
+ int state = VERSION_NUMBER;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case VERSION_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&version))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+ if (valid && (state != VERSION_NUMBER + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ mDirectiveHandler->handleVersion(token->location, version);
+}
+
+void DirectiveParser::parseLine(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_LINE);
+
+ enum State
+ {
+ LINE_NUMBER,
+ FILE_NUMBER
+ };
+
+ bool valid = true;
+ int line = 0, file = 0;
+ int state = LINE_NUMBER;
+
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
+ macroExpander.lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case LINE_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&line))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ case FILE_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&file))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ macroExpander.lex(token);
+ }
+
+ if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ {
+ mTokenizer->setLineNumber(line);
+ if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+ }
+}
+
+bool DirectiveParser::skipping() const
+{
+ if (mConditionalStack.empty()) return false;
+
+ const ConditionalBlock& block = mConditionalStack.back();
+ return block.skipBlock || block.skipGroup;
+}
+
+void DirectiveParser::parseConditionalIf(Token* token)
+{
+ ConditionalBlock block;
+ block.type = token->text;
+ block.location = token->location;
+
+ if (skipping())
+ {
+ // This conditional block is inside another conditional group
+ // which is skipped. As a consequence this whole block is skipped.
+ // Be careful not to parse the conditional expression that might
+ // emit a diagnostic.
+ skipUntilEOD(mTokenizer, token);
+ block.skipBlock = true;
+ }
+ else
+ {
+ DirectiveType directive = getDirective(token);
+
+ int expression = 0;
+ switch (directive)
+ {
+ case DIRECTIVE_IF:
+ expression = parseExpressionIf(token);
+ break;
+ case DIRECTIVE_IFDEF:
+ expression = parseExpressionIfdef(token);
+ break;
+ case DIRECTIVE_IFNDEF:
+ expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ block.skipGroup = expression == 0;
+ block.foundValidGroup = expression != 0;
+ }
+ mConditionalStack.push_back(block);
+}
+
+int DirectiveParser::parseExpressionIf(Token* token)
+{
+ assert((getDirective(token) == DIRECTIVE_IF) ||
+ (getDirective(token) == DIRECTIVE_ELIF));
+
+ DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
+ MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
+ ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+
+ int expression = 0;
+ macroExpander.lex(token);
+ expressionParser.parse(token, &expression);
+
+ // Warn if there are tokens after #if expression.
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+
+ return expression;
+}
+
+int DirectiveParser::parseExpressionIfdef(Token* token)
+{
+ assert((getDirective(token) == DIRECTIVE_IFDEF) ||
+ (getDirective(token) == DIRECTIVE_IFNDEF));
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return 0;
+ }
+
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ int expression = iter != mMacroSet->end() ? 1 : 0;
+
+ // Warn if there are tokens after #ifdef expression.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+ return expression;
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h
new file mode 100644
index 0000000000..8a7f0072ba
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/DirectiveParser.h
@@ -0,0 +1,82 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+
+#include "Lexer.h"
+#include "Macro.h"
+#include "pp_utils.h"
+#include "SourceLocation.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class DirectiveHandler;
+class Tokenizer;
+
+class DirectiveParser : public Lexer
+{
+ public:
+ DirectiveParser(Tokenizer* tokenizer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler);
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
+
+ void parseDirective(Token* token);
+ void parseDefine(Token* token);
+ void parseUndef(Token* token);
+ void parseIf(Token* token);
+ void parseIfdef(Token* token);
+ void parseIfndef(Token* token);
+ void parseElse(Token* token);
+ void parseElif(Token* token);
+ void parseEndif(Token* token);
+ void parseError(Token* token);
+ void parsePragma(Token* token);
+ void parseExtension(Token* token);
+ void parseVersion(Token* token);
+ void parseLine(Token* token);
+
+ bool skipping() const;
+ void parseConditionalIf(Token* token);
+ int parseExpressionIf(Token* token);
+ int parseExpressionIfdef(Token* token);
+
+ struct ConditionalBlock
+ {
+ std::string type;
+ SourceLocation location;
+ bool skipBlock;
+ bool skipGroup;
+ bool foundValidGroup;
+ bool foundElseGroup;
+
+ ConditionalBlock() :
+ skipBlock(false),
+ skipGroup(false),
+ foundValidGroup(false),
+ foundElseGroup(false)
+ {
+ }
+ };
+ bool mPastFirstStatement;
+ std::vector<ConditionalBlock> mConditionalStack;
+ Tokenizer* mTokenizer;
+ MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+ DirectiveHandler* mDirectiveHandler;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h
new file mode 100644
index 0000000000..092d059413
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class Lexer;
+struct Token;
+
+class ExpressionParser
+{
+ public:
+ ExpressionParser(Lexer* lexer, Diagnostics* diagnostics);
+
+ bool parse(Token* token, int* result);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
+
+ Lexer* mLexer;
+ Diagnostics* mDiagnostics;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y
new file mode 100644
index 0000000000..832ad4001e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/ExpressionParser.y
@@ -0,0 +1,279 @@
+/*
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Yacc grammar for GLSL ES preprocessor expression.
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES preprocessor expression parser.
+*/
+
+%{
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated pplval variable.
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065 4701)
+#endif
+
+#include "ExpressionParser.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "Diagnostics.h"
+#include "Lexer.h"
+#include "Token.h"
+
+#if defined(_MSC_VER)
+typedef __int64 YYSTYPE;
+#else
+#include <stdint.h>
+typedef intmax_t YYSTYPE;
+#endif // _MSC_VER
+#define YYSTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_DECLARED 1
+
+namespace {
+struct Context
+{
+ pp::Diagnostics* diagnostics;
+ pp::Lexer* lexer;
+ pp::Token* token;
+ int* result;
+};
+} // namespace
+%}
+
+%pure-parser
+%name-prefix="pp"
+%parse-param {Context *context}
+%lex-param {Context *context}
+
+%{
+static int yylex(YYSTYPE* lvalp, Context* context);
+static void yyerror(Context* context, const char* reason);
+%}
+
+%token TOK_CONST_INT
+%left TOK_OP_OR
+%left TOK_OP_AND
+%left '|'
+%left '^'
+%left '&'
+%left TOK_OP_EQ TOK_OP_NE
+%left '<' '>' TOK_OP_LE TOK_OP_GE
+%left TOK_OP_LEFT TOK_OP_RIGHT
+%left '+' '-'
+%left '*' '/' '%'
+%right TOK_UNARY
+
+%%
+
+input
+ : expression {
+ *(context->result) = static_cast<int>($1);
+ YYACCEPT;
+ }
+;
+
+expression
+ : TOK_CONST_INT
+ | expression TOK_OP_OR expression {
+ $$ = $1 || $3;
+ }
+ | expression TOK_OP_AND expression {
+ $$ = $1 && $3;
+ }
+ | expression '|' expression {
+ $$ = $1 | $3;
+ }
+ | expression '^' expression {
+ $$ = $1 ^ $3;
+ }
+ | expression '&' expression {
+ $$ = $1 & $3;
+ }
+ | expression TOK_OP_NE expression {
+ $$ = $1 != $3;
+ }
+ | expression TOK_OP_EQ expression {
+ $$ = $1 == $3;
+ }
+ | expression TOK_OP_GE expression {
+ $$ = $1 >= $3;
+ }
+ | expression TOK_OP_LE expression {
+ $$ = $1 <= $3;
+ }
+ | expression '>' expression {
+ $$ = $1 > $3;
+ }
+ | expression '<' expression {
+ $$ = $1 < $3;
+ }
+ | expression TOK_OP_RIGHT expression {
+ $$ = $1 >> $3;
+ }
+ | expression TOK_OP_LEFT expression {
+ $$ = $1 << $3;
+ }
+ | expression '-' expression {
+ $$ = $1 - $3;
+ }
+ | expression '+' expression {
+ $$ = $1 + $3;
+ }
+ | expression '%' expression {
+ if ($3 == 0) {
+ std::ostringstream stream;
+ stream << $1 << " % " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ $$ = $1 % $3;
+ }
+ }
+ | expression '/' expression {
+ if ($3 == 0) {
+ std::ostringstream stream;
+ stream << $1 << " / " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ $$ = $1 / $3;
+ }
+ }
+ | expression '*' expression {
+ $$ = $1 * $3;
+ }
+ | '!' expression %prec TOK_UNARY {
+ $$ = ! $2;
+ }
+ | '~' expression %prec TOK_UNARY {
+ $$ = ~ $2;
+ }
+ | '-' expression %prec TOK_UNARY {
+ $$ = - $2;
+ }
+ | '+' expression %prec TOK_UNARY {
+ $$ = + $2;
+ }
+ | '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+%%
+
+int yylex(YYSTYPE* lvalp, Context* context)
+{
+ int type = 0;
+
+ pp::Token* token = context->token;
+ switch (token->type)
+ {
+ case pp::Token::CONST_INT:
+ {
+ unsigned int val = 0;
+ if (!token->uValue(&val))
+ {
+ context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ }
+ *lvalp = static_cast<YYSTYPE>(val);
+ type = TOK_CONST_INT;
+ break;
+ }
+ case pp::Token::OP_OR: type = TOK_OP_OR; break;
+ case pp::Token::OP_AND: type = TOK_OP_AND; break;
+ case pp::Token::OP_NE: type = TOK_OP_NE; break;
+ case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
+ case pp::Token::OP_GE: type = TOK_OP_GE; break;
+ case pp::Token::OP_LE: type = TOK_OP_LE; break;
+ case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
+ case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
+ case '|': type = '|'; break;
+ case '^': type = '^'; break;
+ case '&': type = '&'; break;
+ case '>': type = '>'; break;
+ case '<': type = '<'; break;
+ case '-': type = '-'; break;
+ case '+': type = '+'; break;
+ case '%': type = '%'; break;
+ case '/': type = '/'; break;
+ case '*': type = '*'; break;
+ case '!': type = '!'; break;
+ case '~': type = '~'; break;
+ case '(': type = '('; break;
+ case ')': type = ')'; break;
+
+ default: break;
+ }
+
+ // Advance to the next token if the current one is valid.
+ if (type != 0) context->lexer->lex(token);
+
+ return type;
+}
+
+void yyerror(Context* context, const char* reason)
+{
+ context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+ context->token->location,
+ reason);
+}
+
+namespace pp {
+
+ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mDiagnostics(diagnostics)
+{
+}
+
+bool ExpressionParser::parse(Token* token, int* result)
+{
+ Context context;
+ context.diagnostics = mDiagnostics;
+ context.lexer = mLexer;
+ context.token = token;
+ context.result = result;
+ int ret = yyparse(&context);
+ switch (ret)
+ {
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+ break;
+
+ default:
+ assert(false);
+ mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+ break;
+ }
+
+ return ret == 0;
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp
new file mode 100644
index 0000000000..c3de95f313
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.cpp
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Input.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+namespace pp
+{
+
+Input::Input() : mCount(0), mString(0)
+{
+}
+
+Input::Input(int count, const char* const string[], const int length[]) :
+ mCount(count),
+ mString(string)
+{
+ assert(mCount >= 0);
+ mLength.reserve(mCount);
+ for (int i = 0; i < mCount; ++i)
+ {
+ int len = length ? length[i] : -1;
+ mLength.push_back(len < 0 ? strlen(mString[i]) : len);
+ }
+}
+
+int Input::read(char* buf, int maxSize)
+{
+ int nRead = 0;
+ while ((nRead < maxSize) && (mReadLoc.sIndex < mCount))
+ {
+ int size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
+ size = std::min(size, maxSize);
+ memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
+ nRead += size;
+ mReadLoc.cIndex += size;
+
+ // Advance string if we reached the end of current string.
+ if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
+ {
+ ++mReadLoc.sIndex;
+ mReadLoc.cIndex = 0;
+ }
+ }
+ return nRead;
+}
+
+} // namespace pp
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h
new file mode 100644
index 0000000000..dac734b68d
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Input.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_INPUT_H_
+#define COMPILER_PREPROCESSOR_INPUT_H_
+
+#include <vector>
+
+namespace pp
+{
+
+// Holds and reads input for Lexer.
+class Input
+{
+ public:
+ Input();
+ Input(int count, const char* const string[], const int length[]);
+
+ int count() const { return mCount; }
+ const char* string(int index) const { return mString[index]; }
+ int length(int index) const { return mLength[index]; }
+
+ int read(char* buf, int maxSize);
+
+ struct Location
+ {
+ int sIndex; // String index;
+ int cIndex; // Char index.
+
+ Location() : sIndex(0), cIndex(0) { }
+ };
+ const Location& readLoc() const { return mReadLoc; }
+
+ private:
+ // Input.
+ int mCount;
+ const char* const* mString;
+ std::vector<int> mLength;
+
+ Location mReadLoc;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_INPUT_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp
new file mode 100644
index 0000000000..7c663ee761
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.cpp
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Lexer.h"
+
+namespace pp
+{
+
+Lexer::~Lexer()
+{
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h
new file mode 100644
index 0000000000..eb85cea873
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Lexer.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_LEXER_H_
+#define COMPILER_PREPROCESSOR_LEXER_H_
+
+namespace pp
+{
+
+struct Token;
+
+class Lexer
+{
+ public:
+ virtual ~Lexer();
+
+ virtual void lex(Token* token) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_LEXER_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp
new file mode 100644
index 0000000000..b2e3088e32
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Macro.h"
+
+#include "Token.h"
+
+namespace pp
+{
+
+bool Macro::equals(const Macro& other) const
+{
+ return (type == other.type) &&
+ (name == other.name) &&
+ (parameters == other.parameters) &&
+ (replacements == other.replacements);
+}
+
+} // namespace pp
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h
new file mode 100644
index 0000000000..7ec0149116
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Macro.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_MACRO_H_
+#define COMPILER_PREPROCESSOR_MACRO_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace pp
+{
+
+struct Token;
+
+struct Macro
+{
+ enum Type
+ {
+ kTypeObj,
+ kTypeFunc
+ };
+ typedef std::vector<std::string> Parameters;
+ typedef std::vector<Token> Replacements;
+
+ Macro() : predefined(false), disabled(false), type(kTypeObj) { }
+ bool equals(const Macro& other) const;
+
+ bool predefined;
+ mutable bool disabled;
+
+ Type type;
+ std::string name;
+ Parameters parameters;
+ Replacements replacements;
+};
+
+typedef std::map<std::string, Macro> MacroSet;
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp
new file mode 100644
index 0000000000..701cec9a4b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.cpp
@@ -0,0 +1,370 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "MacroExpander.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "Diagnostics.h"
+#include "Token.h"
+
+namespace pp
+{
+
+class TokenLexer : public Lexer
+{
+ public:
+ typedef std::vector<Token> TokenVector;
+
+ TokenLexer(TokenVector* tokens)
+ {
+ tokens->swap(mTokens);
+ mIter = mTokens.begin();
+ }
+
+ virtual void lex(Token* token)
+ {
+ if (mIter == mTokens.end())
+ {
+ token->reset();
+ token->type = Token::LAST;
+ }
+ else
+ {
+ *token = *mIter++;
+ }
+ }
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
+
+ TokenVector mTokens;
+ TokenVector::const_iterator mIter;
+};
+
+MacroExpander::MacroExpander(Lexer* lexer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics)
+{
+}
+
+MacroExpander::~MacroExpander()
+{
+ for (size_t i = 0; i < mContextStack.size(); ++i)
+ {
+ delete mContextStack[i];
+ }
+}
+
+void MacroExpander::lex(Token* token)
+{
+ while (true)
+ {
+ getToken(token);
+
+ if (token->type != Token::IDENTIFIER)
+ break;
+
+ if (token->expansionDisabled())
+ break;
+
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ if (iter == mMacroSet->end())
+ break;
+
+ const Macro& macro = iter->second;
+ if (macro.disabled)
+ {
+ // If a particular token is not expanded, it is never expanded.
+ token->setExpansionDisabled(true);
+ break;
+ }
+ if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
+ {
+ // If the token immediately after the macro name is not a '(',
+ // this macro should not be expanded.
+ break;
+ }
+
+ pushMacro(macro, *token);
+ }
+}
+
+void MacroExpander::getToken(Token* token)
+{
+ if (mReserveToken.get())
+ {
+ *token = *mReserveToken;
+ mReserveToken.reset();
+ return;
+ }
+
+ // First pop all empty macro contexts.
+ while (!mContextStack.empty() && mContextStack.back()->empty())
+ {
+ popMacro();
+ }
+
+ if (!mContextStack.empty())
+ {
+ *token = mContextStack.back()->get();
+ }
+ else
+ {
+ mLexer->lex(token);
+ }
+}
+
+void MacroExpander::ungetToken(const Token& token)
+{
+ if (!mContextStack.empty())
+ {
+ MacroContext* context = mContextStack.back();
+ context->unget();
+ assert(context->replacements[context->index] == token);
+ }
+ else
+ {
+ assert(!mReserveToken.get());
+ mReserveToken.reset(new Token(token));
+ }
+}
+
+bool MacroExpander::isNextTokenLeftParen()
+{
+ Token token;
+ getToken(&token);
+
+ bool lparen = token.type == '(';
+ ungetToken(token);
+
+ return lparen;
+}
+
+bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
+{
+ assert(!macro.disabled);
+ assert(!identifier.expansionDisabled());
+ assert(identifier.type == Token::IDENTIFIER);
+ assert(identifier.text == macro.name);
+
+ std::vector<Token> replacements;
+ if (!expandMacro(macro, identifier, &replacements))
+ return false;
+
+ // Macro is disabled for expansion until it is popped off the stack.
+ macro.disabled = true;
+
+ MacroContext* context = new MacroContext;
+ context->macro = &macro;
+ context->replacements.swap(replacements);
+ mContextStack.push_back(context);
+ return true;
+}
+
+void MacroExpander::popMacro()
+{
+ assert(!mContextStack.empty());
+
+ MacroContext* context = mContextStack.back();
+ mContextStack.pop_back();
+
+ assert(context->empty());
+ assert(context->macro->disabled);
+ context->macro->disabled = false;
+ delete context;
+}
+
+bool MacroExpander::expandMacro(const Macro& macro,
+ const Token& identifier,
+ std::vector<Token>* replacements)
+{
+ replacements->clear();
+ if (macro.type == Macro::kTypeObj)
+ {
+ replacements->assign(macro.replacements.begin(),
+ macro.replacements.end());
+
+ if (macro.predefined)
+ {
+ static const std::string kLine = "__LINE__";
+ static const std::string kFile = "__FILE__";
+
+ assert(replacements->size() == 1);
+ Token& repl = replacements->front();
+ if (macro.name == kLine)
+ {
+ std::ostringstream stream;
+ stream << identifier.location.line;
+ repl.text = stream.str();
+ }
+ else if (macro.name == kFile)
+ {
+ std::ostringstream stream;
+ stream << identifier.location.file;
+ repl.text = stream.str();
+ }
+ }
+ }
+ else
+ {
+ assert(macro.type == Macro::kTypeFunc);
+ std::vector<MacroArg> args;
+ args.reserve(macro.parameters.size());
+ if (!collectMacroArgs(macro, identifier, &args))
+ return false;
+
+ replaceMacroParams(macro, args, replacements);
+ }
+
+ for (size_t i = 0; i < replacements->size(); ++i)
+ {
+ Token& repl = replacements->at(i);
+ if (i == 0)
+ {
+ // The first token in the replacement list inherits the padding
+ // properties of the identifier token.
+ repl.setAtStartOfLine(identifier.atStartOfLine());
+ repl.setHasLeadingSpace(identifier.hasLeadingSpace());
+ }
+ repl.location = identifier.location;
+ }
+ return true;
+}
+
+bool MacroExpander::collectMacroArgs(const Macro& macro,
+ const Token& identifier,
+ std::vector<MacroArg>* args)
+{
+ Token token;
+ getToken(&token);
+ assert(token.type == '(');
+
+ args->push_back(MacroArg());
+ for (int openParens = 1; openParens != 0; )
+ {
+ getToken(&token);
+
+ if (token.type == Token::LAST)
+ {
+ mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
+ identifier.location, identifier.text);
+ // Do not lose EOF token.
+ ungetToken(token);
+ return false;
+ }
+
+ bool isArg = false; // True if token is part of the current argument.
+ switch (token.type)
+ {
+ case '(':
+ ++openParens;
+ isArg = true;
+ break;
+ case ')':
+ --openParens;
+ isArg = openParens != 0;
+ break;
+ case ',':
+ // The individual arguments are separated by comma tokens, but
+ // the comma tokens between matching inner parentheses do not
+ // seperate arguments.
+ if (openParens == 1) args->push_back(MacroArg());
+ isArg = openParens != 1;
+ break;
+ default:
+ isArg = true;
+ break;
+ }
+ if (isArg)
+ {
+ MacroArg& arg = args->back();
+ // Initial whitespace is not part of the argument.
+ if (arg.empty()) token.setHasLeadingSpace(false);
+ arg.push_back(token);
+ }
+ }
+
+ const Macro::Parameters& params = macro.parameters;
+ // If there is only one empty argument, it is equivalent to no argument.
+ if (params.empty() && (args->size() == 1) && args->front().empty())
+ {
+ args->clear();
+ }
+ // Validate the number of arguments.
+ if (args->size() != params.size())
+ {
+ Diagnostics::ID id = args->size() < macro.parameters.size() ?
+ Diagnostics::MACRO_TOO_FEW_ARGS :
+ Diagnostics::MACRO_TOO_MANY_ARGS;
+ mDiagnostics->report(id, identifier.location, identifier.text);
+ return false;
+ }
+
+ // Pre-expand each argument before substitution.
+ // This step expands each argument individually before they are
+ // inserted into the macro body.
+ for (size_t i = 0; i < args->size(); ++i)
+ {
+ MacroArg& arg = args->at(i);
+ TokenLexer lexer(&arg);
+ MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
+
+ arg.clear();
+ expander.lex(&token);
+ while (token.type != Token::LAST)
+ {
+ arg.push_back(token);
+ expander.lex(&token);
+ }
+ }
+ return true;
+}
+
+void MacroExpander::replaceMacroParams(const Macro& macro,
+ const std::vector<MacroArg>& args,
+ std::vector<Token>* replacements)
+{
+ for (size_t i = 0; i < macro.replacements.size(); ++i)
+ {
+ const Token& repl = macro.replacements[i];
+ if (repl.type != Token::IDENTIFIER)
+ {
+ replacements->push_back(repl);
+ continue;
+ }
+
+ // TODO(alokp): Optimize this.
+ // There is no need to search for macro params every time.
+ // The param index can be cached with the replacement token.
+ Macro::Parameters::const_iterator iter = std::find(
+ macro.parameters.begin(), macro.parameters.end(), repl.text);
+ if (iter == macro.parameters.end())
+ {
+ replacements->push_back(repl);
+ continue;
+ }
+
+ size_t iArg = std::distance(macro.parameters.begin(), iter);
+ const MacroArg& arg = args[iArg];
+ if (arg.empty())
+ {
+ continue;
+ }
+ size_t iRepl = replacements->size();
+ replacements->insert(replacements->end(), arg.begin(), arg.end());
+ // The replacement token inherits padding properties from
+ // macro replacement token.
+ replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
+ }
+}
+
+} // namespace pp
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h
new file mode 100644
index 0000000000..7c5c543871
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/MacroExpander.h
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#include "Lexer.h"
+#include "Macro.h"
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+
+class MacroExpander : public Lexer
+{
+ public:
+ MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
+ virtual ~MacroExpander();
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
+
+ void getToken(Token* token);
+ void ungetToken(const Token& token);
+ bool isNextTokenLeftParen();
+
+ bool pushMacro(const Macro& macro, const Token& identifier);
+ void popMacro();
+
+ bool expandMacro(const Macro& macro,
+ const Token& identifier,
+ std::vector<Token>* replacements);
+
+ typedef std::vector<Token> MacroArg;
+ bool collectMacroArgs(const Macro& macro,
+ const Token& identifier,
+ std::vector<MacroArg>* args);
+ void replaceMacroParams(const Macro& macro,
+ const std::vector<MacroArg>& args,
+ std::vector<Token>* replacements);
+
+ struct MacroContext
+ {
+ const Macro* macro;
+ size_t index;
+ std::vector<Token> replacements;
+
+ MacroContext() : macro(0), index(0) { }
+ bool empty() const { return index == replacements.size(); }
+ const Token& get() { return replacements[index++]; }
+ void unget() { assert(index > 0); --index; }
+ };
+
+ Lexer* mLexer;
+ MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+
+ std::auto_ptr<Token> mReserveToken;
+ std::vector<MacroContext*> mContextStack;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp
new file mode 100644
index 0000000000..ffa7225a8f
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.cpp
@@ -0,0 +1,142 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Preprocessor.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "Diagnostics.h"
+#include "DirectiveParser.h"
+#include "Macro.h"
+#include "MacroExpander.h"
+#include "Token.h"
+#include "Tokenizer.h"
+
+namespace pp
+{
+
+struct PreprocessorImpl
+{
+ Diagnostics* diagnostics;
+ MacroSet macroSet;
+ Tokenizer tokenizer;
+ DirectiveParser directiveParser;
+ MacroExpander macroExpander;
+
+ PreprocessorImpl(Diagnostics* diag,
+ DirectiveHandler* directiveHandler) :
+ diagnostics(diag),
+ tokenizer(diag),
+ directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
+ macroExpander(&directiveParser, &macroSet, diag)
+ {
+ }
+};
+
+Preprocessor::Preprocessor(Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler)
+{
+ mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
+}
+
+Preprocessor::~Preprocessor()
+{
+ delete mImpl;
+}
+
+bool Preprocessor::init(int count,
+ const char* const string[],
+ const int length[])
+{
+ static const int kGLSLVersion = 100;
+
+ // Add standard pre-defined macros.
+ predefineMacro("__LINE__", 0);
+ predefineMacro("__FILE__", 0);
+ predefineMacro("__VERSION__", kGLSLVersion);
+ predefineMacro("GL_ES", 1);
+
+ return mImpl->tokenizer.init(count, string, length);
+}
+
+void Preprocessor::predefineMacro(const char* name, int value)
+{
+ std::ostringstream stream;
+ stream << value;
+
+ Token token;
+ token.type = Token::CONST_INT;
+ token.text = stream.str();
+
+ Macro macro;
+ macro.predefined = true;
+ macro.type = Macro::kTypeObj;
+ macro.name = name;
+ macro.replacements.push_back(token);
+
+ mImpl->macroSet[name] = macro;
+}
+
+void Preprocessor::lex(Token* token)
+{
+ bool validToken = false;
+ while (!validToken)
+ {
+ mImpl->macroExpander.lex(token);
+ switch (token->type)
+ {
+ // We should not be returning internal preprocessing tokens.
+ // Convert preprocessing tokens to compiler tokens or report
+ // diagnostics.
+ case Token::PP_HASH:
+ assert(false);
+ break;
+ case Token::CONST_INT:
+ {
+ int val = 0;
+ if (!token->iValue(&val))
+ {
+ // Do not mark the token as invalid.
+ // Just emit the diagnostic and reset value to 0.
+ mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ token->text.assign("0");
+ }
+ validToken = true;
+ break;
+ }
+ case Token::CONST_FLOAT:
+ {
+ float val = 0;
+ if (!token->fValue(&val))
+ {
+ // Do not mark the token as invalid.
+ // Just emit the diagnostic and reset value to 0.0.
+ mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
+ token->location, token->text);
+ token->text.assign("0.0");
+ }
+ validToken = true;
+ break;
+ }
+ case Token::PP_NUMBER:
+ mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
+ token->location, token->text);
+ break;
+ case Token::PP_OTHER:
+ mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
+ token->location, token->text);
+ break;
+ default:
+ validToken = true;
+ break;
+ }
+ }
+}
+
+} // namespace pp
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h
new file mode 100644
index 0000000000..5fe35b27bd
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Preprocessor.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class DirectiveHandler;
+struct PreprocessorImpl;
+struct Token;
+
+class Preprocessor
+{
+ public:
+ Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler);
+ ~Preprocessor();
+
+ // count: specifies the number of elements in the string and length arrays.
+ // string: specifies an array of pointers to strings.
+ // length: specifies an array of string lengths.
+ // If length is NULL, each string is assumed to be null terminated.
+ // If length is a value other than NULL, it points to an array containing
+ // a string length for each of the corresponding elements of string.
+ // Each element in the length array may contain the length of the
+ // corresponding string or a value less than 0 to indicate that the string
+ // is null terminated.
+ bool init(int count, const char* const string[], const int length[]);
+ // Adds a pre-defined macro.
+ void predefineMacro(const char* name, int value);
+
+ void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
+
+ PreprocessorImpl* mImpl;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h
new file mode 100644
index 0000000000..6982613ac7
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/SourceLocation.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+
+namespace pp
+{
+
+struct SourceLocation
+{
+ SourceLocation() : file(0), line(0) { }
+ SourceLocation(int f, int l) : file(f), line(l) { }
+
+ bool equals(const SourceLocation& other) const
+ {
+ return (file == other.file) && (line == other.line);
+ }
+
+ int file;
+ int line;
+};
+
+inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ return lhs.equals(rhs);
+}
+
+inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ return !lhs.equals(rhs);
+}
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp
new file mode 100644
index 0000000000..67f50aa32c
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Token.h"
+
+#include <cassert>
+
+#include "numeric_lex.h"
+
+namespace pp
+{
+
+void Token::reset()
+{
+ type = 0;
+ flags = 0;
+ location = SourceLocation();
+ text.clear();
+}
+
+bool Token::equals(const Token& other) const
+{
+ return (type == other.type) &&
+ (flags == other.flags) &&
+ (location == other.location) &&
+ (text == other.text);
+}
+
+void Token::setAtStartOfLine(bool start)
+{
+ if (start)
+ flags |= AT_START_OF_LINE;
+ else
+ flags &= ~AT_START_OF_LINE;
+}
+
+void Token::setHasLeadingSpace(bool space)
+{
+ if (space)
+ flags |= HAS_LEADING_SPACE;
+ else
+ flags &= ~HAS_LEADING_SPACE;
+}
+
+void Token::setExpansionDisabled(bool disable)
+{
+ if (disable)
+ flags |= EXPANSION_DISABLED;
+ else
+ flags &= ~EXPANSION_DISABLED;
+}
+
+bool Token::iValue(int* value) const
+{
+ assert(type == CONST_INT);
+ return numeric_lex_int(text, value);
+}
+
+bool Token::uValue(unsigned int* value) const
+{
+ assert(type == CONST_INT);
+ return numeric_lex_int(text, value);
+}
+
+bool Token::fValue(float* value) const
+{
+ assert(type == CONST_FLOAT);
+ return numeric_lex_float(text, value);
+}
+
+std::ostream& operator<<(std::ostream& out, const Token& token)
+{
+ if (token.hasLeadingSpace())
+ out << " ";
+
+ out << token.text;
+ return out;
+}
+
+} // namespace pp
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h
new file mode 100644
index 0000000000..8b553aecb6
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Token.h
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_TOKEN_H_
+#define COMPILER_PREPROCESSOR_TOKEN_H_
+
+#include <ostream>
+#include <string>
+
+#include "SourceLocation.h"
+
+namespace pp
+{
+
+struct Token
+{
+ enum Type
+ {
+ LAST = 0, // EOF.
+
+ IDENTIFIER = 258,
+
+ CONST_INT,
+ CONST_FLOAT,
+
+ OP_INC,
+ OP_DEC,
+ OP_LEFT,
+ OP_RIGHT,
+ OP_LE,
+ OP_GE,
+ OP_EQ,
+ OP_NE,
+ OP_AND,
+ OP_XOR,
+ OP_OR,
+ OP_ADD_ASSIGN,
+ OP_SUB_ASSIGN,
+ OP_MUL_ASSIGN,
+ OP_DIV_ASSIGN,
+ OP_MOD_ASSIGN,
+ OP_LEFT_ASSIGN,
+ OP_RIGHT_ASSIGN,
+ OP_AND_ASSIGN,
+ OP_XOR_ASSIGN,
+ OP_OR_ASSIGN,
+
+ // Preprocessing token types.
+ // These types are used by the preprocessor internally.
+ // Preprocessor clients must not depend or check for them.
+ PP_HASH,
+ PP_NUMBER,
+ PP_OTHER
+ };
+ enum Flags
+ {
+ AT_START_OF_LINE = 1 << 0,
+ HAS_LEADING_SPACE = 1 << 1,
+ EXPANSION_DISABLED = 1 << 2
+ };
+
+ Token() : type(0), flags(0) { }
+
+ void reset();
+ bool equals(const Token& other) const;
+
+ // Returns true if this is the first token on line.
+ // It disregards any leading whitespace.
+ bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; }
+ void setAtStartOfLine(bool start);
+
+ bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; }
+ void setHasLeadingSpace(bool space);
+
+ bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; }
+ void setExpansionDisabled(bool disable);
+
+ // Converts text into numeric value for CONST_INT and CONST_FLOAT token.
+ // Returns false if the parsed value cannot fit into an int or float.
+ bool iValue(int* value) const;
+ bool uValue(unsigned int* value) const;
+ bool fValue(float* value) const;
+
+ int type;
+ unsigned int flags;
+ SourceLocation location;
+ std::string text;
+};
+
+inline bool operator==(const Token& lhs, const Token& rhs)
+{
+ return lhs.equals(rhs);
+}
+
+inline bool operator!=(const Token& lhs, const Token& rhs)
+{
+ return !lhs.equals(rhs);
+}
+
+extern std::ostream& operator<<(std::ostream& out, const Token& token);
+
+} // namepsace pp
+#endif // COMPILER_PREPROCESSOR_TOKEN_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h
new file mode 100644
index 0000000000..a594d2d865
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_
+#define COMPILER_PREPROCESSOR_TOKENIZER_H_
+
+#include "Input.h"
+#include "Lexer.h"
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+
+class Tokenizer : public Lexer
+{
+ public:
+ struct Context
+ {
+ Diagnostics* diagnostics;
+
+ Input input;
+ // The location where yytext points to. Token location should track
+ // scanLoc instead of Input::mReadLoc because they may not be the same
+ // if text is buffered up in the scanner input buffer.
+ Input::Location scanLoc;
+
+ bool leadingSpace;
+ bool lineStart;
+ };
+ static const size_t kMaxTokenLength;
+
+ Tokenizer(Diagnostics* diagnostics);
+ ~Tokenizer();
+
+ bool init(int count, const char* const string[], const int length[]);
+
+ void setFileNumber(int file);
+ void setLineNumber(int line);
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
+ bool initScanner();
+ void destroyScanner();
+
+ void* mHandle; // Scanner handle.
+ Context mContext; // Scanner extra.
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l
new file mode 100644
index 0000000000..9762988350
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/Tokenizer.l
@@ -0,0 +1,340 @@
+/*
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES preprocessor.
+Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
+http://msdn.microsoft.com/en-us/library/2scxys89.aspx
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
+*/
+
+%top{
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+}
+
+%{
+#include "Tokenizer.h"
+
+#include "Diagnostics.h"
+#include "Token.h"
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated yy_fatal_error function.
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#endif
+
+typedef std::string YYSTYPE;
+typedef pp::SourceLocation YYLTYPE;
+
+// Use the unused yycolumn variable to track file (string) number.
+#define yyfileno yycolumn
+
+#define YY_USER_INIT \
+ do { \
+ yyfileno = 0; \
+ yylineno = 1; \
+ yyextra->leadingSpace = false; \
+ yyextra->lineStart = true; \
+ } while(0);
+
+#define YY_USER_ACTION \
+ do \
+ { \
+ pp::Input* input = &yyextra->input; \
+ pp::Input::Location* scanLoc = &yyextra->scanLoc; \
+ while ((scanLoc->sIndex < input->count()) && \
+ (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
+ { \
+ scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
+ ++yyfileno; yylineno = 1; \
+ } \
+ yylloc->file = yyfileno; \
+ yylloc->line = yylineno; \
+ scanLoc->cIndex += yyleng; \
+ } while(0);
+
+#define YY_INPUT(buf, result, maxSize) \
+ result = yyextra->input.read(buf, maxSize);
+
+%}
+
+%option noyywrap nounput never-interactive
+%option reentrant bison-bridge bison-locations
+%option prefix="pp"
+%option extra-type="pp::Tokenizer::Context*"
+%x COMMENT
+
+NEWLINE \n|\r|\r\n
+IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
+PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?]
+
+DECIMAL_CONSTANT [1-9][0-9]*
+OCTAL_CONSTANT 0[0-7]*
+HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+
+
+DIGIT [0-9]
+EXPONENT_PART [eE][+-]?{DIGIT}+
+FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
+
+%%
+
+ /* Line comment */
+"//"[^\r\n]*
+
+ /* Block comment */
+ /* Line breaks are just counted - not returned. */
+ /* The comment is replaced by a single space. */
+"/*" { BEGIN(COMMENT); }
+<COMMENT>[^*\r\n]+
+<COMMENT>"*"
+<COMMENT>{NEWLINE} { ++yylineno; }
+<COMMENT>"*/" {
+ yyextra->leadingSpace = true;
+ BEGIN(INITIAL);
+}
+
+# {
+ // # is only valid at start of line for preprocessor directives.
+ yylval->assign(1, yytext[0]);
+ return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
+}
+
+{IDENTIFIER} {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::IDENTIFIER;
+}
+
+{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_INT;
+}
+
+({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_FLOAT;
+}
+
+ /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
+ /* Rule to catch all invalid integers and floats. */
+({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::PP_NUMBER;
+}
+
+"++" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_INC;
+}
+"--" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DEC;
+}
+"<<" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT;
+}
+">>" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT;
+}
+"<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LE;
+}
+">=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_GE;
+}
+"==" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_EQ;
+}
+"!=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_NE;
+}
+"&&" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND;
+}
+"^^" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR;
+}
+"||" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR;
+}
+"+=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_ADD_ASSIGN;
+}
+"-=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_SUB_ASSIGN;
+}
+"*=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MUL_ASSIGN;
+}
+"/=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DIV_ASSIGN;
+}
+"%=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MOD_ASSIGN;
+}
+"<<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT_ASSIGN;
+}
+">>=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT_ASSIGN;
+}
+"&=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND_ASSIGN;
+}
+"^=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR_ASSIGN;
+}
+"|=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR_ASSIGN;
+}
+
+{PUNCTUATOR} {
+ yylval->assign(1, yytext[0]);
+ return yytext[0];
+}
+
+[ \t\v\f]+ { yyextra->leadingSpace = true; }
+
+{NEWLINE} {
+ ++yylineno;
+ yylval->assign(1, '\n');
+ return '\n';
+}
+
+. {
+ yylval->assign(1, yytext[0]);
+ return pp::Token::PP_OTHER;
+}
+
+<*><<EOF>> {
+ // YY_USER_ACTION is not invoked for handling EOF.
+ // Set the location for EOF token manually.
+ pp::Input* input = &yyextra->input;
+ pp::Input::Location* scanLoc = &yyextra->scanLoc;
+ int sIndexMax = std::max(0, input->count() - 1);
+ if (scanLoc->sIndex != sIndexMax)
+ {
+ // We can only reach here if there are empty strings at the
+ // end of the input.
+ scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
+ yyfileno = sIndexMax; yylineno = 1;
+ }
+ yylloc->file = yyfileno;
+ yylloc->line = yylineno;
+ yylval->clear();
+
+ if (YY_START == COMMENT)
+ {
+ yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+ pp::SourceLocation(yyfileno, yylineno),
+ "");
+ }
+ yyterminate();
+}
+
+%%
+
+namespace pp {
+
+// TODO(alokp): Maximum token length should ideally be specified by
+// the preprocessor client, i.e., the compiler.
+const size_t Tokenizer::kMaxTokenLength = 256;
+
+Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
+{
+ mContext.diagnostics = diagnostics;
+}
+
+Tokenizer::~Tokenizer()
+{
+ destroyScanner();
+}
+
+bool Tokenizer::init(int count, const char* const string[], const int length[])
+{
+ if (count < 0) return false;
+ if ((count > 0) && (string == 0)) return false;
+
+ mContext.input = Input(count, string, length);
+ return initScanner();
+}
+
+void Tokenizer::setFileNumber(int file)
+{
+ // We use column number as file number.
+ // See macro yyfileno.
+ yyset_column(file, mHandle);
+}
+
+void Tokenizer::setLineNumber(int line)
+{
+ yyset_lineno(line, mHandle);
+}
+
+void Tokenizer::lex(Token* token)
+{
+ token->type = yylex(&token->text, &token->location, mHandle);
+ if (token->text.size() > kMaxTokenLength)
+ {
+ mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+ token->location, token->text);
+ token->text.erase(kMaxTokenLength);
+ }
+
+ token->flags = 0;
+
+ token->setAtStartOfLine(mContext.lineStart);
+ mContext.lineStart = token->type == '\n';
+
+ token->setHasLeadingSpace(mContext.leadingSpace);
+ mContext.leadingSpace = false;
+}
+
+bool Tokenizer::initScanner()
+{
+ if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle))
+ return false;
+
+ yyrestart(0, mHandle);
+ return true;
+}
+
+void Tokenizer::destroyScanner()
+{
+ if (mHandle == NULL)
+ return;
+
+ yylex_destroy(mHandle);
+ mHandle = NULL;
+}
+
+} // namespace pp
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h
new file mode 100644
index 0000000000..b04125d230
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/numeric_lex.h
@@ -0,0 +1,61 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// numeric_lex.h: Functions to extract numeric values from string.
+
+#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+
+#include <sstream>
+
+namespace pp {
+
+inline std::ios::fmtflags numeric_base_int(const std::string& str)
+{
+ if ((str.size() >= 2) &&
+ (str[0] == '0') &&
+ (str[1] == 'x' || str[1] == 'X'))
+ {
+ return std::ios::hex;
+ }
+ else if ((str.size() >= 1) && (str[0] == '0'))
+ {
+ return std::ios::oct;
+ }
+ return std::ios::dec;
+}
+
+// The following functions parse the given string to extract a numerical
+// value of the given type. These functions assume that the string is
+// of the correct form. They can only fail if the parsed value is too big,
+// in which case false is returned.
+
+template<typename IntType>
+bool numeric_lex_int(const std::string& str, IntType* value)
+{
+ std::istringstream stream(str);
+ // This should not be necessary, but MSVS has a buggy implementation.
+ // It returns incorrect results if the base is not specified.
+ stream.setf(numeric_base_int(str), std::ios::basefield);
+
+ stream >> (*value);
+ return !stream.fail();
+}
+
+template<typename FloatType>
+bool numeric_lex_float(const std::string& str, FloatType* value)
+{
+ std::istringstream stream(str);
+ // Force "C" locale so that decimal character is always '.', and
+ // not dependent on the current locale.
+ stream.imbue(std::locale::classic());
+
+ stream >> (*value);
+ return !stream.fail();
+}
+
+} // namespace pp.
+#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h b/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h
new file mode 100644
index 0000000000..17164ea8b0
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/new/pp_utils.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// pp_utils.h: Common preprocessor utilities
+
+#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_
+#define COMPILER_PREPROCESSOR_PPUTILS_H_
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be used in the private: declarations for a class.
+#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#endif // COMPILER_PREPROCESSOR_PPUTILS_H_
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/parser.h b/src/3rdparty/angle/src/compiler/preprocessor/parser.h
new file mode 100644
index 0000000000..f67342b670
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/parser.h
@@ -0,0 +1,93 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#ifndef BISON_PARSER_H
+# define BISON_PARSER_H
+
+#ifndef yystypepp
+typedef struct {
+ int sc_int;
+ float sc_fval;
+ int sc_ident;
+ char symbol_name[MAX_SYMBOL_NAME_LEN+1];
+} yystypepp;
+
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+# define CPP_AND_OP 257
+# define CPP_SUB_ASSIGN 259
+# define CPP_MOD_ASSIGN 260
+# define CPP_ADD_ASSIGN 261
+# define CPP_DIV_ASSIGN 262
+# define CPP_MUL_ASSIGN 263
+# define CPP_EQ_OP 264
+# define CPP_XOR_OP 265
+# define ERROR_SY 266
+# define CPP_FLOATCONSTANT 267
+# define CPP_GE_OP 268
+# define CPP_RIGHT_OP 269
+# define CPP_IDENTIFIER 270
+# define CPP_INTCONSTANT 271
+# define CPP_LE_OP 272
+# define CPP_LEFT_OP 273
+# define CPP_DEC_OP 274
+# define CPP_NE_OP 275
+# define CPP_OR_OP 276
+# define CPP_INC_OP 277
+# define CPP_STRCONSTANT 278
+# define CPP_TYPEIDENTIFIER 279
+
+# define FIRST_USER_TOKEN_SY 289
+
+# define CPP_RIGHT_ASSIGN 280
+# define CPP_LEFT_ASSIGN 281
+# define CPP_AND_ASSIGN 282
+# define CPP_OR_ASSIGN 283
+# define CPP_XOR_ASSIGN 284
+# define CPP_LEFT_BRACKET 285
+# define CPP_RIGHT_BRACKET 286
+# define CPP_LEFT_BRACE 287
+# define CPP_RIGHT_BRACE 288
+
+#endif /* not BISON_PARSER_H */
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h b/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h
new file mode 100644
index 0000000000..15056da2c9
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/preprocess.h
@@ -0,0 +1,50 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#include "compiler/preprocessor/slglobals.h"
+extern CPPStruct *cpp;
+int InitCPPStruct(void);
+int InitScanner(CPPStruct *cpp);
+int InitAtomTable(AtomTable *atable, int htsize);
+char* GetStringOfAtom(AtomTable *atable, int atom);
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/scanner.c b/src/3rdparty/angle/src/compiler/preprocessor/scanner.c
new file mode 100644
index 0000000000..fde853c1e0
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/scanner.c
@@ -0,0 +1,698 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// scanner.c
+//
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+ #include <ieeefp.h>
+#else
+ #define isinff(x) (((*(int *)&(x) & 0x7f800000L)==0x7f800000L) && \
+ ((*(int *)&(x) & 0x007fffffL)==0000000000L))
+#endif
+
+#include "compiler/preprocessor/slglobals.h"
+#include "compiler/util.h"
+
+typedef struct StringInputSrc {
+ InputSrc base;
+ char *p;
+} StringInputSrc;
+
+static int ScanFromString(const char *s);
+
+static int eof_scan(InputSrc *is, yystypepp * yylvalpp)
+{
+ return EOF;
+} // eof_scan
+
+static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) {}
+
+static InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop, 0, 0 };
+
+static int byte_scan(InputSrc *, yystypepp * yylvalpp);
+
+#define EOL_SY '\n'
+
+#if defined(_MSC_VER)
+ #define DBG_BREAKPOINT() __asm int 3
+#elif defined(_M_AMD64)
+ #define DBG_BREAKPOINT() assert(!"Dbg_Breakpoint");
+#else
+ #define DBG_BREAKPOINT()
+#endif
+
+#if defined(_MSC_VER) && !defined(_M_AMD64)
+ __int64 RDTSC ( void ) {
+
+ __int64 v;
+
+ __asm __emit 0x0f
+ __asm __emit 0x31
+ __asm mov dword ptr v, eax
+ __asm mov dword ptr v+4, edx
+
+ return v;
+ }
+#endif
+
+
+int InitScanner(CPPStruct *cpp)
+{
+ // Add various atoms needed by the CPP line scanner:
+ if (!InitCPP())
+ return 0;
+
+ cpp->mostRecentToken = 0;
+ cpp->tokenLoc = &cpp->ltokenLoc;
+
+ cpp->ltokenLoc.file = 0;
+ cpp->ltokenLoc.line = 0;
+
+ cpp->currentInput = &eof_inputsrc;
+ cpp->previous_token = '\n';
+ cpp->pastFirstStatement = 0;
+
+ return 1;
+} // InitScanner
+
+int FreeScanner(void)
+{
+ return (FreeCPP());
+}
+
+int InitScannerInput(CPPStruct *cpp, int count, const char* const string[], const int length[])
+{
+ cpp->PaWhichStr = 0;
+ cpp->PaArgv = string;
+ cpp->PaArgc = count;
+ cpp->PaStrLen = length;
+ ScanFromString(string[0]);
+ return 0;
+}
+
+/*
+ * str_getch()
+ * takes care of reading from multiple strings.
+ * returns the next-char from the input stream.
+ * returns EOF when the complete shader is parsed.
+ */
+static int str_getch(StringInputSrc *in)
+{
+ for(;;){
+ if (*in->p){
+ if (*in->p == '\n') {
+ in->base.line++;
+ IncLineNumber();
+ }
+ return *in->p++;
+ }
+ if(++(cpp->PaWhichStr) < cpp->PaArgc){
+ free(in);
+ SetStringNumber(cpp->PaWhichStr);
+ SetLineNumber(1);
+ ScanFromString(cpp->PaArgv[cpp->PaWhichStr]);
+ in=(StringInputSrc*)cpp->currentInput;
+ continue;
+ }
+ else{
+ cpp->currentInput = in->base.prev;
+ cpp->PaWhichStr=0;
+ free(in);
+ return EOF;
+ }
+ }
+} // str_getch
+
+static void str_ungetch(StringInputSrc *in, int ch, yystypepp *type) {
+ if (in->p[-1] == ch)in->p--;
+ else {
+ *(in->p)='\0'; //this would take care of shifting to the previous string.
+ cpp->PaWhichStr--;
+ }
+ if (ch == '\n') {
+ in->base.line--;
+ DecLineNumber();
+ }
+} // str_ungetch
+
+int ScanFromString(const char *s)
+{
+
+ StringInputSrc *in = malloc(sizeof(StringInputSrc));
+ memset(in, 0, sizeof(StringInputSrc));
+ in->p = (char*) s;
+ in->base.line = 1;
+ in->base.scan = byte_scan;
+ in->base.getch = (int (*)(InputSrc *, yystypepp *))str_getch;
+ in->base.ungetch = (void (*)(InputSrc *, int, yystypepp *))str_ungetch;
+ in->base.prev = cpp->currentInput;
+ cpp->currentInput = &in->base;
+
+ return 1;
+} // ScanFromString;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Floating point constants: /////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define APPEND_CHAR_S(ch, str, len, max_len) \
+ if (len < max_len) { \
+ str[len++] = ch; \
+ } else if (!alreadyComplained) { \
+ CPPErrorToInfoLog("BUFFER OVERFLOW"); \
+ alreadyComplained = 1; \
+ }
+
+/*
+ * lFloatConst() - Scan a floating point constant. Assumes that the scanner
+ * has seen at least one digit, followed by either a decimal '.' or the
+ * letter 'e'.
+ * ch - '.' or 'e'
+ * len - length of string already copied into yylvalpp->symbol_name.
+ */
+
+static int lFloatConst(int ch, int len, yystypepp * yylvalpp)
+{
+ int alreadyComplained = 0;
+ assert((ch == '.') || (ch == 'e') || (ch == 'E'));
+
+ if (ch == '.') {
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '9');
+ }
+
+ // Exponent:
+ if (ch == 'e' || ch == 'E') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '+') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } else if (ch == '-') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ if (ch >= '0' && ch <= '9') {
+ while (ch >= '0' && ch <= '9') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ } else {
+ CPPErrorToInfoLog("EXPONENT INVALID");
+ }
+ }
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ yylvalpp->sc_fval = (float) atof_dot(yylvalpp->symbol_name);
+ if (isinff(yylvalpp->sc_fval)) {
+ CPPErrorToInfoLog("FLOAT CONSTANT OVERFLOW");
+ }
+ return CPP_FLOATCONSTANT;
+} // lFloatConst
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////// Normal Scanner //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static int byte_scan(InputSrc *in, yystypepp * yylvalpp)
+{
+ char string_val[MAX_STRING_LEN + 1];
+ int alreadyComplained = 0;
+ int len, ch, ii, ival = 0;
+
+ for (;;) {
+ yylvalpp->sc_int = 0;
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+
+ while (ch == ' ' || ch == '\t' || ch == '\r') {
+ yylvalpp->sc_int = 1;
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+
+ cpp->ltokenLoc.file = cpp->currentInput->name;
+ cpp->ltokenLoc.line = cpp->currentInput->line;
+ alreadyComplained = 0;
+ len = 0;
+ switch (ch) {
+ default:
+ return ch; // Single character token
+ case EOF:
+ return -1;
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z': case '_':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '_');
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_ident = LookUpAddString(atable, yylvalpp->symbol_name);
+ return CPP_IDENTIFIER;
+ break;
+ case '0':
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == 'x' || ch == 'X') { // hexadecimal integer constants
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') ||
+ (ch >= 'a' && ch <= 'f'))
+ {
+ ival = 0;
+ do {
+ if ((ival <= 0x0fffffff) && (len < MAX_SYMBOL_NAME_LEN)) {
+ yylvalpp->symbol_name[len++] = ch;
+ if (ch >= '0' && ch <= '9') {
+ ii = ch - '0';
+ } else if (ch >= 'A' && ch <= 'F') {
+ ii = ch - 'A' + 10;
+ } else {
+ ii = ch - 'a' + 10;
+ }
+ ival = (ival << 4) | ii;
+ } else if (!alreadyComplained) {
+ CPPErrorToInfoLog("HEX CONSTANT OVERFLOW");
+ alreadyComplained = 1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') ||
+ (ch >= 'a' && ch <= 'f'));
+ } else {
+ CPPErrorToInfoLog("HEX CONSTANT INVALID");
+ }
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_int = ival;
+ return CPP_INTCONSTANT;
+ } else if (ch >= '0' && ch <= '7') { // octal integer constants
+ ival = 0;
+ do {
+ if ((ival <= 0x1fffffff) && (len < MAX_SYMBOL_NAME_LEN)) {
+ yylvalpp->symbol_name[len++] = ch;
+ ii = ch - '0';
+ ival = (ival << 3) | ii;
+ } else if (!alreadyComplained) {
+ CPPErrorToInfoLog("OCT CONSTANT OVERFLOW");
+ alreadyComplained = 1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '7');
+ if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E')
+ return lFloatConst(ch, len, yylvalpp);
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_int = ival;
+ return CPP_INTCONSTANT;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ ch = '0';
+ }
+ // Fall through...
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '9');
+ if (ch == '.' || ch == 'e' || ch == 'E') {
+ return lFloatConst(ch, len, yylvalpp);
+ } else {
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ ival = 0;
+ for (ii = 0; ii < len; ii++) {
+ ch = yylvalpp->symbol_name[ii] - '0';
+ ival = ival*10 + ch;
+ if ((ival > 214748364) || (ival == 214748364 && ch >= 8)) {
+ CPPErrorToInfoLog("INTEGER CONSTANT OVERFLOW");
+ break;
+ }
+ }
+ yylvalpp->sc_int = ival;
+ if(ival==0)
+ strcpy(yylvalpp->symbol_name,"0");
+ return CPP_INTCONSTANT;
+ }
+ break;
+ case '-':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '-') {
+ return CPP_DEC_OP;
+ } else if (ch == '=') {
+ return CPP_SUB_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '-';
+ }
+ case '+':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '+') {
+ return CPP_INC_OP;
+ } else if (ch == '=') {
+ return CPP_ADD_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '+';
+ }
+ case '*':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_MUL_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '*';
+ }
+ case '%':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_MOD_ASSIGN;
+ } else if (ch == '>'){
+ return CPP_RIGHT_BRACE;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '%';
+ }
+ case ':':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '>') {
+ return CPP_RIGHT_BRACKET;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return ':';
+ }
+ case '^':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '^') {
+ return CPP_XOR_OP;
+ } else {
+ if (ch == '=')
+ return CPP_XOR_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '^';
+ }
+ }
+
+ case '=':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_EQ_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '=';
+ }
+ case '!':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_NE_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '!';
+ }
+ case '|':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '|') {
+ return CPP_OR_OP;
+ } else {
+ if (ch == '=')
+ return CPP_OR_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '|';
+ }
+ }
+ case '&':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '&') {
+ return CPP_AND_OP;
+ } else {
+ if (ch == '=')
+ return CPP_AND_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '&';
+ }
+ }
+ case '<':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '<') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if(ch == '=')
+ return CPP_LEFT_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return CPP_LEFT_OP;
+ }
+ } else {
+ if (ch == '=') {
+ return CPP_LE_OP;
+ } else {
+ if (ch == '%')
+ return CPP_LEFT_BRACE;
+ else if (ch == ':')
+ return CPP_LEFT_BRACKET;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '<';
+ }
+ }
+ }
+ case '>':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '>') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if(ch == '=')
+ return CPP_RIGHT_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return CPP_RIGHT_OP;
+ }
+ } else {
+ if (ch == '=') {
+ return CPP_GE_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '>';
+ }
+ }
+ case '.':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch >= '0' && ch <= '9') {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return lFloatConst('.', 0, yylvalpp);
+ } else {
+ if (ch == '.') {
+ return -1; // Special EOF hack
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '.';
+ }
+ }
+ case '/':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '/') {
+ do {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch != '\n' && ch != EOF);
+ if (ch == EOF)
+ return -1;
+ return '\n';
+ } else if (ch == '*') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ do {
+ while (ch != '*') {
+ if (ch == EOF) {
+ CPPErrorToInfoLog("EOF IN COMMENT");
+ return -1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == EOF) {
+ CPPErrorToInfoLog("EOF IN COMMENT");
+ return -1;
+ }
+ } while (ch != '/');
+ // Go try it again...
+ } else if (ch == '=') {
+ return CPP_DIV_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '/';
+ }
+ break;
+ case '"':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ while (ch != '"' && ch != '\n' && ch != EOF) {
+ if (ch == '\\') {
+ CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
+ return -1;
+ }
+ APPEND_CHAR_S(ch, string_val, len, MAX_STRING_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ };
+ assert(len <= MAX_STRING_LEN);
+ string_val[len] = '\0';
+ if (ch == '"') {
+ yylvalpp->sc_ident = LookUpAddString(atable, string_val);
+ return CPP_STRCONSTANT;
+ } else {
+ CPPErrorToInfoLog("EOL IN STRING");
+ return ERROR_SY;
+ }
+ break;
+ }
+ }
+} // byte_scan
+
+int yylex_CPP(char* buf, int maxSize)
+{
+ yystypepp yylvalpp;
+ int token = '\n';
+
+ for(;;) {
+
+ char* tokenString = 0;
+ token = cpp->currentInput->scan(cpp->currentInput, &yylvalpp);
+ if(check_EOF(token))
+ return 0;
+ if (token < 0) {
+ // This check may need to be improved to support UTF-8
+ // characters in comments.
+ CPPErrorToInfoLog("preprocessor encountered non-ASCII character in shader source");
+ return 0;
+ }
+ if (token == '#') {
+ if (cpp->previous_token == '\n'|| cpp->previous_token == 0) {
+ token = readCPPline(&yylvalpp);
+ if(check_EOF(token))
+ return 0;
+ continue;
+ } else {
+ CPPErrorToInfoLog("preprocessor command must not be preceded by any other statement in that line");
+ return 0;
+ }
+ }
+ cpp->previous_token = token;
+ // expand macros
+ if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp.sc_ident, &yylvalpp)) {
+ cpp->pastFirstStatement = 1;
+ continue;
+ }
+
+ if (token == '\n')
+ continue;
+ cpp->pastFirstStatement = 1;
+
+ if (token == CPP_IDENTIFIER) {
+ tokenString = GetStringOfAtom(atable,yylvalpp.sc_ident);
+ } else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
+ tokenString = yylvalpp.symbol_name;
+ } else {
+ tokenString = GetStringOfAtom(atable,token);
+ }
+
+ if (tokenString) {
+ int len = strlen(tokenString);
+ cpp->tokensBeforeEOF = 1;
+ if (len >= maxSize) {
+ return maxSize;
+ } else if (len > 0) {
+ strcpy(buf, tokenString);
+ return len;
+ }
+
+ return 0;
+ }
+ }
+} // yylex
+
+//Checks if the token just read is EOF or not.
+int check_EOF(int token)
+{
+ if(token==-1){
+ if(cpp->ifdepth >0){
+ CPPErrorToInfoLog("#endif missing!! Compilation stopped");
+ cpp->CompileError=1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////// End of scanner.c //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/scanner.h b/src/3rdparty/angle/src/compiler/preprocessor/scanner.h
new file mode 100644
index 0000000000..b67c1d644e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/scanner.h
@@ -0,0 +1,81 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// scanner.h
+//
+
+#if !defined(__SCANNER_H)
+#define __SCANNER_H 1
+
+#include "compiler/preprocessor/length_limits.h"
+#include "compiler/preprocessor/parser.h"
+
+// Not really atom table stuff but needed first...
+
+typedef struct SourceLoc_Rec {
+ unsigned short file, line;
+} SourceLoc;
+
+int yylex_CPP(char* buf, int maxSize);
+
+typedef struct InputSrc {
+ struct InputSrc *prev;
+ int (*scan)(struct InputSrc *, yystypepp *);
+ int (*getch)(struct InputSrc *, yystypepp *);
+ void (*ungetch)(struct InputSrc *, int, yystypepp *);
+ int name; /* atom */
+ int line;
+} InputSrc;
+
+int InitScanner(CPPStruct *cpp); // Intialise the cpp scanner.
+int InitScannerInput(CPPStruct *cpp, int count, const char* const string[], const int length[]);
+int check_EOF(int); // check if we hit a EOF abruptly
+void CPPErrorToInfoLog(const char *); // sticking the msg,line into the Shader's.Info.log
+void SetLineNumber(int);
+void SetStringNumber(int);
+void IncLineNumber(void);
+void DecLineNumber(void);
+int FreeScanner(void); // Free the cpp scanner
+#endif // !(defined(__SCANNER_H)
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h b/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h
new file mode 100644
index 0000000000..4634626643
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/slglobals.h
@@ -0,0 +1,82 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// slglobals.h
+//
+
+#if !defined(__SLGLOBALS_H)
+#define __SLGLOBALS_H 1
+
+typedef struct CPPStruct_Rec CPPStruct;
+
+extern CPPStruct *cpp;
+
+#undef CPPC_DEBUG_THE_COMPILER
+#if defined(_DEBUG)
+#define CPPC_DEBUG_THE_COMPILER 1
+#endif
+
+#undef CPPC_ENABLE_TOOLS
+#define CPPC_ENABLE_TOOLS 1
+
+#include "compiler/preprocessor/memory.h"
+#include "compiler/preprocessor/atom.h"
+#include "compiler/preprocessor/scanner.h"
+#include "compiler/preprocessor/cpp.h"
+#include "compiler/preprocessor/tokens.h"
+#include "compiler/preprocessor/symbols.h"
+#include "compiler/preprocessor/compile.h"
+#if !defined(NO_PARSER)
+#include "compiler/preprocessor/parser.h"
+#endif
+
+#if !defined(NULL)
+#define NULL 0
+#endif
+
+#endif // !(defined(__SLGLOBALS_H)
+
+
+
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/symbols.c b/src/3rdparty/angle/src/compiler/preprocessor/symbols.c
new file mode 100644
index 0000000000..f18b2569b3
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/symbols.c
@@ -0,0 +1,288 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// symbols.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "compiler/preprocessor/slglobals.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4706)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Symbol Table Variables: ///////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+Scope *ScopeList = NULL;
+Scope *CurrentScope = NULL;
+Scope *GlobalScope = NULL;
+
+static void unlinkScope(void *_scope) {
+ Scope *scope = _scope;
+
+ if (scope->next)
+ scope->next->prev = scope->prev;
+ if (scope->prev)
+ scope->prev->next = scope->next;
+ else
+ ScopeList = scope->next;
+}
+
+/*
+ * NewScope()
+ *
+ */
+Scope *NewScopeInPool(MemoryPool *pool)
+{
+ Scope *lScope;
+
+ lScope = mem_Alloc(pool, sizeof(Scope));
+ lScope->pool = pool;
+ lScope->parent = NULL;
+ lScope->funScope = NULL;
+ lScope->symbols = NULL;
+
+ lScope->level = 0;
+
+ lScope->programs = NULL;
+ if ((lScope->next = ScopeList))
+ ScopeList->prev = lScope;
+ lScope->prev = 0;
+ ScopeList = lScope;
+ mem_AddCleanup(pool, unlinkScope, lScope);
+ return lScope;
+} // NewScope
+
+/*
+ * PushScope()
+ *
+ */
+
+void PushScope(Scope *fScope)
+{
+ Scope *lScope;
+
+ if (CurrentScope) {
+ fScope->level = CurrentScope->level + 1;
+ if (fScope->level == 1) {
+ if (!GlobalScope) {
+ /* HACK - CTD -- if GlobalScope==NULL and level==1, we're
+ * defining a function in the superglobal scope. Things
+ * will break if we leave the level as 1, so we arbitrarily
+ * set it to 2 */
+ fScope->level = 2;
+ }
+ }
+ if (fScope->level >= 2) {
+ lScope = fScope;
+ while (lScope->level > 2)
+ lScope = lScope->next;
+ fScope->funScope = lScope;
+ }
+ } else {
+ fScope->level = 0;
+ }
+ fScope->parent = CurrentScope;
+ CurrentScope = fScope;
+} // PushScope
+
+/*
+ * PopScope()
+ *
+ */
+
+Scope *PopScope(void)
+{
+ Scope *lScope;
+
+ lScope = CurrentScope;
+ if (CurrentScope)
+ CurrentScope = CurrentScope->parent;
+ return lScope;
+} // PopScope
+
+/*
+ * NewSymbol() - Allocate a new symbol node;
+ *
+ */
+
+Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind)
+{
+ Symbol *lSymb;
+ char *pch;
+ unsigned int ii;
+
+ lSymb = (Symbol *) mem_Alloc(fScope->pool, sizeof(Symbol));
+ lSymb->left = NULL;
+ lSymb->right = NULL;
+ lSymb->next = NULL;
+ lSymb->name = name;
+ lSymb->loc = *loc;
+ lSymb->kind = kind;
+
+ // Clear union area:
+
+ pch = (char *) &lSymb->details;
+ for (ii = 0; ii < sizeof(lSymb->details); ii++)
+ *pch++ = 0;
+ return lSymb;
+} // NewSymbol
+
+/*
+ * lAddToTree() - Using a binary tree is not a good idea for basic atom values because they
+ * are generated in order. We'll fix this later (by reversing the bit pattern).
+ */
+
+static void lAddToTree(Symbol **fSymbols, Symbol *fSymb)
+{
+ Symbol *lSymb;
+ int lrev, frev;
+
+ lSymb = *fSymbols;
+ if (lSymb) {
+ frev = GetReversedAtom(atable, fSymb->name);
+ while (lSymb) {
+ lrev = GetReversedAtom(atable, lSymb->name);
+ if (lrev == frev) {
+ CPPErrorToInfoLog("GetAtomString(atable, fSymb->name)");
+ break;
+ } else {
+ if (lrev > frev) {
+ if (lSymb->left) {
+ lSymb = lSymb->left;
+ } else {
+ lSymb->left = fSymb;
+ break;
+ }
+ } else {
+ if (lSymb->right) {
+ lSymb = lSymb->right;
+ } else {
+ lSymb->right = fSymb;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ *fSymbols = fSymb;
+ }
+} // lAddToTree
+
+
+/*
+ * AddSymbol() - Add a variable, type, or function name to a scope.
+ *
+ */
+
+Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind)
+{
+ Symbol *lSymb;
+
+ if (!fScope)
+ fScope = CurrentScope;
+ lSymb = NewSymbol(loc, fScope, atom, kind);
+ lAddToTree(&fScope->symbols, lSymb);
+ return lSymb;
+} // AddSymbol
+
+
+/*********************************************************************************************/
+/************************************ Symbol Semantic Functions ******************************/
+/*********************************************************************************************/
+
+/*
+ * LookUpLocalSymbol()
+ *
+ */
+
+Symbol *LookUpLocalSymbol(Scope *fScope, int atom)
+{
+ Symbol *lSymb;
+ int rname, ratom;
+
+ ratom = GetReversedAtom(atable, atom);
+ if (!fScope)
+ fScope = CurrentScope;
+ lSymb = fScope->symbols;
+ while (lSymb) {
+ rname = GetReversedAtom(atable, lSymb->name);
+ if (rname == ratom) {
+ return lSymb;
+ } else {
+ if (rname > ratom) {
+ lSymb = lSymb->left;
+ } else {
+ lSymb = lSymb->right;
+ }
+ }
+ }
+ return NULL;
+} // LookUpLocalSymbol
+
+/*
+ * LookUpSymbol()
+ *
+ */
+
+Symbol *LookUpSymbol(Scope *fScope, int atom)
+{
+ Symbol *lSymb;
+
+ if (!fScope)
+ fScope = CurrentScope;
+ while (fScope) {
+ lSymb = LookUpLocalSymbol(fScope, atom);
+ if (lSymb)
+ return lSymb;
+ fScope = fScope->parent;
+ }
+ return NULL;
+} // LookUpSymbol
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/symbols.h b/src/3rdparty/angle/src/compiler/preprocessor/symbols.h
new file mode 100644
index 0000000000..e7d0b075fa
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/symbols.h
@@ -0,0 +1,111 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// symbols.h
+//
+
+#if !defined(__SYMBOLS_H)
+#define __SYMBOLS_H 1
+
+#include "compiler/preprocessor/memory.h"
+
+typedef enum symbolkind {
+ MACRO_S
+} symbolkind;
+
+// Typedefs for things defined here in "symbols.h":
+
+typedef struct Scope_Rec Scope;
+typedef struct Symbol_Rec Symbol;
+
+typedef struct SymbolList_Rec {
+ struct SymbolList_Rec *next;
+ Symbol *symb;
+} SymbolList;
+
+struct Scope_Rec {
+ Scope *next, *prev; // doubly-linked list of all scopes
+ Scope *parent;
+ Scope *funScope; // Points to base scope of enclosing function
+ MemoryPool *pool; // pool used for allocation in this scope
+ Symbol *symbols;
+
+ int level; // 0 = super globals, 1 = globals, etc.
+
+ // Only used at global scope (level 1):
+ SymbolList *programs; // List of programs for this compilation.
+};
+
+
+// Symbol table is a simple binary tree.
+
+#include "compiler/preprocessor/cpp.h" // to get MacroSymbol def
+
+struct Symbol_Rec {
+ Symbol *left, *right;
+ Symbol *next;
+ int name; // Name atom
+ SourceLoc loc;
+ symbolkind kind;
+ union {
+ MacroSymbol mac;
+ } details;
+};
+
+extern Scope *CurrentScope;
+extern Scope *GlobalScope;
+extern Scope *ScopeList;
+
+Scope *NewScopeInPool(MemoryPool *);
+#define NewScope() NewScopeInPool(CurrentScope->pool)
+void PushScope(Scope *fScope);
+Scope *PopScope(void);
+Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind);
+Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind);
+Symbol *LookUpLocalSymbol(Scope *fScope, int atom);
+Symbol *LookUpSymbol(Scope *fScope, int atom);
+
+
+#endif // !defined(__SYMBOLS_H)
+
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/tokens.c b/src/3rdparty/angle/src/compiler/preprocessor/tokens.c
new file mode 100644
index 0000000000..b94c05ebd4
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/tokens.c
@@ -0,0 +1,467 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// tokens.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "common/angleutils.h"
+#include "compiler/debug.h"
+#include "compiler/preprocessor/slglobals.h"
+#include "compiler/util.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4054)
+#pragma warning(disable: 4152)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////// Preprocessor and Token Recorder and Playback: ////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * idstr()
+ * Copy a string to a malloc'ed block and convert it into something suitable
+ * for an ID
+ *
+ */
+
+static char *idstr(const char *fstr, MemoryPool *pool)
+{
+ size_t len;
+ char *str, *t;
+ const char *f;
+
+ len = strlen(fstr);
+ if (!pool)
+ str = (char *) malloc(len + 1);
+ else
+ str = (char *) mem_Alloc(pool, len + 1);
+
+ for (f=fstr, t=str; *f; f++) {
+ if (isalnum(*f)) *t++ = *f;
+ else if (*f == '.' || *f == '/') *t++ = '_';
+ }
+ *t = 0;
+ return str;
+} // idstr
+
+
+/*
+ * lNewBlock()
+ *
+ */
+
+static TokenBlock *lNewBlock(TokenStream *fTok, MemoryPool *pool)
+{
+ TokenBlock *lBlock;
+
+ if (!pool)
+ lBlock = (TokenBlock *) malloc(sizeof(TokenBlock) + 256);
+ else
+ lBlock = (TokenBlock *) mem_Alloc(pool, sizeof(TokenBlock) + 256);
+ lBlock->count = 0;
+ lBlock->current = 0;
+ lBlock->data = (unsigned char *) lBlock + sizeof(TokenBlock);
+ lBlock->max = 256;
+ lBlock->next = NULL;
+ if (fTok->head) {
+ fTok->current->next = lBlock;
+ } else {
+ fTok->head = lBlock;
+ }
+ fTok->current = lBlock;
+ return lBlock;
+} // lNewBlock
+
+/*
+ * lAddByte()
+ *
+ */
+
+static void lAddByte(TokenStream *fTok, unsigned char fVal)
+{
+ TokenBlock *lBlock;
+ lBlock = fTok->current;
+ if (lBlock->count >= lBlock->max)
+ lBlock = lNewBlock(fTok, 0);
+ lBlock->data[lBlock->count++] = fVal;
+} // lAddByte
+
+
+
+/*
+ * lReadByte() - Get the next byte from a stream.
+ *
+ */
+
+static int lReadByte(TokenStream *pTok)
+{
+ TokenBlock *lBlock;
+ int lval = -1;
+
+ lBlock = pTok->current;
+ if (lBlock) {
+ if (lBlock->current >= lBlock->count) {
+ lBlock = lBlock->next;
+ if (lBlock)
+ lBlock->current = 0;
+ pTok->current = lBlock;
+ }
+ if (lBlock)
+ lval = lBlock->data[lBlock->current++];
+ }
+ return lval;
+} // lReadByte
+
+/////////////////////////////////////// Global Functions://////////////////////////////////////
+
+/*
+ * NewTokenStream()
+ *
+ */
+
+TokenStream *NewTokenStream(const char *name, MemoryPool *pool)
+{
+ TokenStream *pTok;
+
+ if (!pool)
+ pTok = (TokenStream *) malloc(sizeof(TokenStream));
+ else
+ pTok = (TokenStream*)mem_Alloc(pool, sizeof(TokenStream));
+ pTok->next = NULL;
+ pTok->name = idstr(name, pool);
+ pTok->head = NULL;
+ pTok->current = NULL;
+ lNewBlock(pTok, pool);
+ return pTok;
+} // NewTokenStream
+
+/*
+ * DeleteTokenStream()
+ *
+ */
+
+void DeleteTokenStream(TokenStream *pTok)
+{
+ TokenBlock *pBlock, *nBlock;
+
+ if (pTok) {
+ pBlock = pTok->head;
+ while (pBlock) {
+ nBlock = pBlock->next;
+ free(pBlock);
+ pBlock = nBlock;
+ }
+ if (pTok->name)
+ free(pTok->name);
+ free(pTok);
+ }
+} // DeleteTokenStream
+
+/*
+ * RecordToken() - Add a token to the end of a list for later playback or printout.
+ *
+ */
+
+void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp)
+{
+ const char *s;
+ char *str=NULL;
+
+ if (token > 256)
+ lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80));
+ else
+ lAddByte(pTok, (unsigned char)(token & 0x7f));
+ switch (token) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ case CPP_STRCONSTANT:
+ s = GetAtomString(atable, yylvalpp->sc_ident);
+ while (*s)
+ lAddByte(pTok, (unsigned char) *s++);
+ lAddByte(pTok, 0);
+ break;
+ case CPP_FLOATCONSTANT:
+ case CPP_INTCONSTANT:
+ str=yylvalpp->symbol_name;
+ while (*str){
+ lAddByte(pTok, (unsigned char) *str++);
+ }
+ lAddByte(pTok, 0);
+ break;
+ case '(':
+ lAddByte(pTok, (unsigned char)(yylvalpp->sc_int ? 1 : 0));
+ default:
+ break;
+ }
+} // RecordToken
+
+/*
+ * RewindTokenStream() - Reset a token stream in preperation for reading.
+ *
+ */
+
+void RewindTokenStream(TokenStream *pTok)
+{
+ if (pTok->head) {
+ pTok->current = pTok->head;
+ pTok->current->current = 0;
+ }
+} // RewindTokenStream
+
+/*
+ * ReadToken() - Read the next token from a stream.
+ *
+ */
+
+int ReadToken(TokenStream *pTok, yystypepp * yylvalpp)
+{
+ char symbol_name[MAX_SYMBOL_NAME_LEN + 1];
+ char string_val[MAX_STRING_LEN + 1];
+ int ltoken, len;
+ char ch;
+ int base, accum;
+ char ch_val;
+
+ ltoken = lReadByte(pTok);
+ if (ltoken >= 0) {
+ if (ltoken > 127)
+ ltoken += 128;
+ switch (ltoken) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ len = 0;
+ ch = lReadByte(pTok);
+ while ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '_')
+ {
+ if (len < MAX_SYMBOL_NAME_LEN) {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ }
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ yylvalpp->sc_ident = LookUpAddString(atable, symbol_name);
+ return CPP_IDENTIFIER;
+ break;
+ case CPP_STRCONSTANT:
+ len = 0;
+ while ((ch = lReadByte(pTok)) != 0)
+ if (len < MAX_STRING_LEN)
+ string_val[len++] = ch;
+ string_val[len] = '\0';
+ yylvalpp->sc_ident = LookUpAddString(atable, string_val);
+ break;
+ case CPP_FLOATCONSTANT:
+ len = 0;
+ ch = lReadByte(pTok);
+ while ((ch >= '0' && ch <= '9')||(ch=='e'||ch=='E'||ch=='.')||(ch=='+'||ch=='-'))
+ {
+ if (len < MAX_SYMBOL_NAME_LEN) {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ }
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ strcpy(yylvalpp->symbol_name,symbol_name);
+ yylvalpp->sc_fval=(float)atof_dot(yylvalpp->symbol_name);
+ break;
+ case CPP_INTCONSTANT:
+ len = 0;
+ accum = 0;
+ ch = lReadByte(pTok);
+ if (ch == '0') {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ if (ch == 'x' || ch == 'X') {
+ symbol_name[len++] = ch;
+ base = 16;
+ ch = lReadByte(pTok);
+ } else {
+ base = 8;
+ }
+ } else {
+ base = 10;
+ }
+
+ while (len < MAX_SYMBOL_NAME_LEN)
+ {
+ ch_val = -1;
+ if (isdigit(ch))
+ ch_val = ch - '0';
+ else if (isxdigit(ch))
+ ch_val = tolower(ch) - 'a' + 10;
+
+ if (ch_val < 0 || ch_val >= base)
+ break;
+
+ symbol_name[len++] = ch;
+ accum = accum * base + ch_val;
+ ch = lReadByte(pTok);
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ strcpy(yylvalpp->symbol_name, symbol_name);
+ yylvalpp->sc_int = accum;
+ break;
+ case '(':
+ yylvalpp->sc_int = lReadByte(pTok);
+ break;
+ }
+ return ltoken;
+ }
+ return EOF_SY;
+} // ReadToken
+
+typedef struct TokenInputSrc {
+ InputSrc base;
+ TokenStream *tokens;
+ int (*final)(CPPStruct *);
+} TokenInputSrc;
+
+static int scan_token(TokenInputSrc *in, yystypepp * yylvalpp)
+{
+ int token = ReadToken(in->tokens, yylvalpp);
+ int (*final)(CPPStruct *);
+ cpp->tokenLoc->file = cpp->currentInput->name;
+ cpp->tokenLoc->line = cpp->currentInput->line;
+ if (token == '\n') {
+ in->base.line++;
+ return token;
+ }
+ if (token > 0) return token;
+ cpp->currentInput = in->base.prev;
+ final = in->final;
+ free(in);
+ if (final && !final(cpp)) return -1;
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+}
+
+int ReadFromTokenStream(TokenStream *ts, int name, int (*final)(CPPStruct *))
+{
+ TokenInputSrc *in = malloc(sizeof(TokenInputSrc));
+ memset(in, 0, sizeof(TokenInputSrc));
+ in->base.name = name;
+ in->base.prev = cpp->currentInput;
+ in->base.scan = (int (*)(InputSrc *, yystypepp *))scan_token;
+ in->base.line = 1;
+ in->tokens = ts;
+ in->final = final;
+ RewindTokenStream(ts);
+ cpp->currentInput = &in->base;
+ return 1;
+}
+
+typedef struct UngotToken {
+ InputSrc base;
+ int token;
+ yystypepp lval;
+} UngotToken;
+
+static int reget_token(UngotToken *t, yystypepp * yylvalpp)
+{
+ int token = t->token;
+ *yylvalpp = t->lval;
+ cpp->currentInput = t->base.prev;
+ free(t);
+ return token;
+}
+
+void UngetToken(int token, yystypepp * yylvalpp) {
+ UngotToken *t = malloc(sizeof(UngotToken));
+ memset(t, 0, sizeof(UngotToken));
+ t->token = token;
+ t->lval = *yylvalpp;
+ t->base.scan = (void *)reget_token;
+ t->base.prev = cpp->currentInput;
+ t->base.name = cpp->currentInput->name;
+ t->base.line = cpp->currentInput->line;
+ cpp->currentInput = &t->base;
+}
+
+
+void DumpTokenStream(FILE *fp, TokenStream *s, yystypepp * yylvalpp) {
+ int token;
+ char str[100];
+
+ if (fp == 0) fp = stdout;
+ RewindTokenStream(s);
+ while ((token = ReadToken(s, yylvalpp)) > 0) {
+ switch (token) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ snprintf(str, sizeof(str), "%s ", GetAtomString(atable, yylvalpp->sc_ident));
+ break;
+ case CPP_STRCONSTANT:
+ snprintf(str, sizeof(str), "\"%s\"", GetAtomString(atable, yylvalpp->sc_ident));
+ break;
+ case CPP_FLOATCONSTANT:
+ //printf("%g9.6 ", yylvalpp->sc_fval);
+ break;
+ case CPP_INTCONSTANT:
+ //printf("%d ", yylvalpp->sc_int);
+ break;
+ default:
+ if (token >= 127)
+ snprintf(str, sizeof(str), "%s ", GetAtomString(atable, token));
+ else
+ snprintf(str, sizeof(str), "%c", token);
+ break;
+ }
+ CPPDebugLogMsg(str);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////// End of tokens.c ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/tokens.h b/src/3rdparty/angle/src/compiler/preprocessor/tokens.h
new file mode 100644
index 0000000000..dbf4a2ccfe
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/preprocessor/tokens.h
@@ -0,0 +1,90 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// tokens.h
+//
+
+#if !defined(__TOKENS_H)
+#define __TOKENS_H 1
+
+#include <stdio.h>
+#include "compiler/preprocessor/parser.h"
+
+#define EOF_SY (-1)
+
+typedef struct TokenBlock_Rec TokenBlock;
+
+typedef struct TokenStream_Rec {
+ struct TokenStream_Rec *next;
+ char *name;
+ TokenBlock *head;
+ TokenBlock *current;
+} TokenStream;
+
+struct TokenBlock_Rec {
+ TokenBlock *next;
+ int current;
+ int count;
+ int max;
+ unsigned char *data;
+};
+
+extern TokenStream stdlib_cpp_stream;
+
+
+TokenStream *NewTokenStream(const char *name, MemoryPool *pool);
+void DeleteTokenStream(TokenStream *pTok);
+void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp);
+void RewindTokenStream(TokenStream *pTok);
+int ReadToken(TokenStream *pTok, yystypepp * yylvalpp);
+int ReadFromTokenStream(TokenStream *pTok, int name, int (*final)(CPPStruct *));
+void UngetToken(int, yystypepp * yylvalpp);
+
+#if defined(CPPC_ENABLE_TOOLS)
+
+void DumpTokenStream(FILE *, TokenStream *, yystypepp * yylvalpp);
+
+#endif // defined(CPPC_ENABLE_TOOLS)
+
+#endif // !defined(__TOKENS_H)
diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp
new file mode 100644
index 0000000000..538b731b8e
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InfoSink.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/depgraph/DependencyGraphOutput.h"
+#include "compiler/timing/RestrictFragmentShaderTiming.h"
+
+RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
+ : mSink(sink)
+ , mNumErrors(0)
+{
+ // Sampling ops found only in fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
+ mSamplingOps.insert("textureCube(sC1;vf3;f1;");
+ // Sampling ops found in both vertex and fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;");
+ mSamplingOps.insert("textureCube(sC1;vf3;");
+ // Sampling ops provided by OES_EGL_image_external.
+ mSamplingOps.insert("texture2D(1;vf2;");
+ mSamplingOps.insert("texture2DProj(1;vf3;");
+ mSamplingOps.insert("texture2DProj(1;vf4;");
+ // Sampling ops provided by ARB_texture_rectangle.
+ mSamplingOps.insert("texture2DRect(1;vf2;");
+ mSamplingOps.insert("texture2DRectProj(1;vf3;");
+ mSamplingOps.insert("texture2DRectProj(1;vf4;");
+}
+
+// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
+// can vary based on the value of the input arguments. If so, we should restrict those as well.
+void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
+{
+ mNumErrors = 0;
+
+ // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
+ // so we generate errors for them.
+ validateUserDefinedFunctionCallUsage(graph);
+
+ // Starting from each sampler, traverse the dependency graph and generate an error each time we
+ // hit a node where sampler dependent values are not allowed.
+ for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
+ iter != graph.endSamplerSymbols();
+ ++iter)
+ {
+ TGraphSymbol* samplerSymbol = *iter;
+ clearVisited();
+ samplerSymbol->traverse(this);
+ }
+}
+
+void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
+{
+ for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+ iter != graph.endUserDefinedFunctionCalls();
+ ++iter)
+ {
+ TGraphFunctionCall* functionCall = *iter;
+ beginError(functionCall->getIntermFunctionCall());
+ mSink << "A call to a user defined function is not permitted.\n";
+ }
+}
+
+void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
+{
+ ++mNumErrors;
+ mSink.prefix(EPrefixError);
+ mSink.location(node->getLine());
+}
+
+bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
+{
+ return !intermFunctionCall->isUserDefined() &&
+ mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
+}
+
+void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
+{
+ // Texture cache access time might leak sensitive information.
+ // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
+ // sampling operation.
+ if (isSamplingOp(parameter->getIntermFunctionCall())) {
+ switch (parameter->getArgumentNumber()) {
+ case 1:
+ // Second argument (coord)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " coordinate argument of a sampling operation.\n";
+ break;
+ case 2:
+ // Third argument (bias)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " bias argument of a sampling operation.\n";
+ break;
+ default:
+ // First argument (sampler)
+ break;
+ }
+ }
+}
+
+void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
+{
+ beginError(selection->getIntermSelection());
+ mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
+{
+ beginError(loop->getIntermLoop());
+ mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ beginError(logicalOp->getIntermLogicalOp());
+ mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
+ << logicalOp->getOpString()
+ << " operator.\n";
+}
diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h
new file mode 100644
index 0000000000..899165ca28
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/timing/RestrictFragmentShaderTiming.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/depgraph/DependencyGraph.h"
+
+class TInfoSinkBase;
+
+class RestrictFragmentShaderTiming : TDependencyGraphTraverser {
+public:
+ RestrictFragmentShaderTiming(TInfoSinkBase& sink);
+ void enforceRestrictions(const TDependencyGraph& graph);
+ int numErrors() const { return mNumErrors; }
+
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+private:
+ void beginError(const TIntermNode* node);
+ void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph);
+ bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const;
+
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+
+ typedef std::set<TString> StringSet;
+ StringSet mSamplingOps;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp
new file mode 100644
index 0000000000..524c6cf53a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.cpp
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/timing/RestrictVertexShaderTiming.h"
+
+void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node)
+{
+ if (IsSampler(node->getBasicType())) {
+ ++mNumErrors;
+ mSink.prefix(EPrefixError);
+ mSink.location(node->getLine());
+ mSink << "Samplers are not permitted in vertex shaders.\n";
+ }
+}
diff --git a/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h
new file mode 100644
index 0000000000..19a05fa68b
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/timing/RestrictVertexShaderTiming.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/InfoSink.h"
+
+class TInfoSinkBase;
+
+class RestrictVertexShaderTiming : public TIntermTraverser {
+public:
+ RestrictVertexShaderTiming(TInfoSinkBase& sink)
+ : TIntermTraverser(true, false, false)
+ , mSink(sink)
+ , mNumErrors(0) {}
+
+ void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
+ int numErrors() { return mNumErrors; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+private:
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
diff --git a/src/3rdparty/angle/src/compiler/util.cpp b/src/3rdparty/angle/src/compiler/util.cpp
new file mode 100644
index 0000000000..b46e4d0e34
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/util.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#ifdef _MSC_VER
+ #include <locale.h>
+#else
+ #include <sstream>
+#endif
+
+double atof_dot(const char *str)
+{
+#ifdef _MSC_VER
+ _locale_t l = _create_locale(LC_NUMERIC, "C");
+ double result = _atof_l(str, l);
+ _free_locale(l);
+ return result;
+#else
+ double result;
+ std::istringstream s(str);
+ std::locale l("C");
+ s.imbue(l);
+ s >> result;
+ return result;
+#endif
+}
diff --git a/src/3rdparty/angle/src/compiler/util.h b/src/3rdparty/angle/src/compiler/util.h
new file mode 100644
index 0000000000..35288b7396
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/util.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_UTIL_H
+#define COMPILER_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point.
+double atof_dot(const char *str);
+
+#ifdef __cplusplus
+} // end extern "C"
+#endif
+
+#endif // COMPILER_UTIL_H