blob: f5650e1c5ee1179ce498ef6a1f9591d612a74d24 [file] [log] [blame]
alokp@chromium.org07620a52010-09-23 17:53:56 +00001//
Jamie Madill88f6e942014-02-19 10:27:53 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org07620a52010-09-23 17:53:56 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madilld4a3a312014-06-25 16:04:56 -04007#include "compiler/translator/Compiler.h"
Corentin Wallez71d147f2015-02-11 11:15:24 -08008#include "compiler/translator/CallDAG.h"
Geoff Lang17732822013-08-29 13:46:49 -04009#include "compiler/translator/ForLoopUnroll.h"
10#include "compiler/translator/Initialize.h"
Geoff Lang17732822013-08-29 13:46:49 -040011#include "compiler/translator/InitializeParseContext.h"
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080012#include "compiler/translator/InitializeVariables.h"
Jamie Madill6b9cb252013-10-17 10:45:47 -040013#include "compiler/translator/ParseContext.h"
Olli Etuahoc6833112015-04-22 15:15:54 +030014#include "compiler/translator/PruneEmptyDeclarations.h"
Zhenyao Moe740add2014-07-18 17:01:01 -070015#include "compiler/translator/RegenerateStructNames.h"
Geoff Lang17732822013-08-29 13:46:49 -040016#include "compiler/translator/RenameFunction.h"
Zhenyao Mocd68fe72014-07-11 10:45:44 -070017#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
Zhenyao Mo7cab38b2013-10-15 12:59:30 -070018#include "compiler/translator/UnfoldShortCircuitAST.h"
Geoff Lang17732822013-08-29 13:46:49 -040019#include "compiler/translator/ValidateLimitations.h"
20#include "compiler/translator/ValidateOutputs.h"
21#include "compiler/translator/VariablePacker.h"
22#include "compiler/translator/depgraph/DependencyGraph.h"
23#include "compiler/translator/depgraph/DependencyGraphOutput.h"
24#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
25#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
shannon.woods@transgaming.comda1ed362013-01-25 21:54:57 +000026#include "third_party/compiler/ArrayBoundsClamper.h"
Jamie Madill183bde52014-07-02 15:31:19 -040027#include "angle_gl.h"
Jamie Madillaa72d782014-07-02 15:31:19 -040028#include "common/utilities.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000029
Jamie Madill5508f392014-02-20 13:31:36 -050030bool IsWebGLBasedSpec(ShShaderSpec spec)
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +000031{
Zhenyao Modb9b40b2014-10-29 15:00:04 -070032 return (spec == SH_WEBGL_SPEC ||
33 spec == SH_CSS_SHADERS_SPEC ||
34 spec == SH_WEBGL2_SPEC);
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +000035}
36
Zhenyao Mo7faf1a12014-04-25 18:03:56 -070037size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
Jamie Madill88f6e942014-02-19 10:27:53 -050038{
Jamie Madill88f6e942014-02-19 10:27:53 -050039 // WebGL defines a max token legnth of 256, while ES2 leaves max token
40 // size undefined. ES3 defines a max size of 1024 characters.
Zhenyao Modb9b40b2014-10-29 15:00:04 -070041 switch (spec)
Jamie Madill88f6e942014-02-19 10:27:53 -050042 {
Zhenyao Modb9b40b2014-10-29 15:00:04 -070043 case SH_WEBGL_SPEC:
44 case SH_CSS_SHADERS_SPEC:
Jamie Madill88f6e942014-02-19 10:27:53 -050045 return 256;
Zhenyao Modb9b40b2014-10-29 15:00:04 -070046 default:
Jamie Madill88f6e942014-02-19 10:27:53 -050047 return 1024;
48 }
49}
50
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000051namespace {
Zhenyao Modb9b40b2014-10-29 15:00:04 -070052
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080053class TScopedPoolAllocator
54{
55 public:
56 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
57 {
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040058 mAllocator->push();
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000059 SetGlobalPoolAllocator(mAllocator);
60 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080061 ~TScopedPoolAllocator()
62 {
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000063 SetGlobalPoolAllocator(NULL);
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040064 mAllocator->pop();
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000065 }
66
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080067 private:
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000068 TPoolAllocator* mAllocator;
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040069};
70
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080071class TScopedSymbolTableLevel
72{
73 public:
74 TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
75 {
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040076 ASSERT(mTable->atBuiltInLevel());
77 mTable->push();
78 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080079 ~TScopedSymbolTableLevel()
80 {
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040081 while (!mTable->atBuiltInLevel())
82 mTable->pop();
83 }
84
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080085 private:
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -040086 TSymbolTable* mTable;
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000087};
Zhenyao Modb9b40b2014-10-29 15:00:04 -070088
89int MapSpecToShaderVersion(ShShaderSpec spec)
90{
91 switch (spec)
92 {
93 case SH_GLES2_SPEC:
94 case SH_WEBGL_SPEC:
95 case SH_CSS_SHADERS_SPEC:
96 return 100;
97 case SH_GLES3_SPEC:
98 case SH_WEBGL2_SPEC:
99 return 300;
100 default:
101 UNREACHABLE();
102 return 0;
103 }
104}
105
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000106} // namespace
107
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800108TShHandleBase::TShHandleBase()
109{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000110 allocator.push();
111 SetGlobalPoolAllocator(&allocator);
112}
113
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800114TShHandleBase::~TShHandleBase()
115{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000116 SetGlobalPoolAllocator(NULL);
117 allocator.popAll();
118}
119
Jamie Madill183bde52014-07-02 15:31:19 -0400120TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000121 : shaderType(type),
zmo@google.comf420c422011-09-12 18:27:59 +0000122 shaderSpec(spec),
Jamie Madill68fe74a2014-05-27 12:56:01 -0400123 outputType(output),
Jamie Madilleb1a0102013-07-08 13:31:38 -0400124 maxUniformVectors(0),
125 maxExpressionComplexity(0),
126 maxCallStackDepth(0),
shannon.woods%transgaming.com@gtempaccount.comcbb6b6a2013-04-13 03:27:47 +0000127 fragmentPrecisionHigh(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000128 clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200129 builtInFunctionEmulator(),
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200130 mSourcePath(NULL)
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000131{
132}
133
134TCompiler::~TCompiler()
135{
136}
137
138bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000139{
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000140 shaderVersion = 100;
Jamie Madill183bde52014-07-02 15:31:19 -0400141 maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
gman@chromium.org8d804792012-10-17 21:33:48 +0000142 resources.MaxVertexUniformVectors :
143 resources.MaxFragmentUniformVectors;
Jamie Madilleb1a0102013-07-08 13:31:38 -0400144 maxExpressionComplexity = resources.MaxExpressionComplexity;
145 maxCallStackDepth = resources.MaxCallStackDepth;
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -0400146
147 SetGlobalPoolAllocator(&allocator);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000148
alokp@chromium.org07620a52010-09-23 17:53:56 +0000149 // Generate built-in symbol table.
150 if (!InitBuiltInSymbolTable(resources))
151 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000152 InitExtensionBehavior(resources, extensionBehavior);
shannon.woods%transgaming.com@gtempaccount.comcbb6b6a2013-04-13 03:27:47 +0000153 fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000154
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000155 arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
156 clampingStrategy = resources.ArrayIndexClampingStrategy;
157
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000158 hashFunction = resources.HashFunction;
159
alokp@chromium.org07620a52010-09-23 17:53:56 +0000160 return true;
161}
162
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200163TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
164 size_t numStrings, int compileOptions)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000165{
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200166 return compileTreeImpl(shaderStrings, numStrings, compileOptions);
167}
168
169TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[],
170 size_t numStrings, int compileOptions)
171{
alokp@chromium.org07620a52010-09-23 17:53:56 +0000172 clearResults();
173
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200174 ASSERT(numStrings > 0);
175 ASSERT(GetGlobalPoolAllocator());
alokp@chromium.org07620a52010-09-23 17:53:56 +0000176
David Yen0fbd1282015-02-02 14:46:09 -0800177 // Reset the extension behavior for each compilation unit.
178 ResetExtensionBehavior(extensionBehavior);
179
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000180 // If compiling for WebGL, validate loop and indexing as well.
Jamie Madill5508f392014-02-20 13:31:36 -0500181 if (IsWebGLBasedSpec(shaderSpec))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000182 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000183
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000184 // First string is path of source file if flag is set. The actual source follows.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000185 size_t firstSource = 0;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000186 if (compileOptions & SH_SOURCE_PATH)
187 {
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200188 mSourcePath = shaderStrings[0];
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000189 ++firstSource;
190 }
191
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200192 bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000193 TIntermediate intermediate(infoSink);
194 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000195 shaderType, shaderSpec, compileOptions, true,
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200196 infoSink, debugShaderPrecision);
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200197
shannon.woods%transgaming.com@gtempaccount.comcbb6b6a2013-04-13 03:27:47 +0000198 parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400199 SetGlobalParseContext(&parseContext);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000200
201 // We preserve symbols at the built-in level from compile-to-compile.
202 // Start pushing the user-defined symbols at global level.
Alok Priyadarshibc3f1ac2013-09-23 14:57:02 -0400203 TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000204
205 // Parse shader.
206 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000207 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000208 (parseContext.treeRoot != NULL);
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000209
shannon.woods%transgaming.com@gtempaccount.com5524db02013-04-13 03:38:16 +0000210 shaderVersion = parseContext.getShaderVersion();
Zhenyao Modb9b40b2014-10-29 15:00:04 -0700211 if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
212 {
213 infoSink.info.prefix(EPrefixError);
214 infoSink.info << "unsupported shader version";
215 success = false;
216 }
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000217
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200218 TIntermNode *root = NULL;
219
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800220 if (success)
221 {
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700222 mPragma = parseContext.pragma();
223 if (mPragma.stdgl.invariantAll)
224 {
225 symbolTable.setGlobalInvariant();
226 }
227
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200228 root = parseContext.treeRoot;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000229 success = intermediate.postProcess(root);
230
Jamie Madill6654bc92014-03-26 14:01:57 -0400231 // Disallow expressions deemed too complex.
232 if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
233 success = limitExpressionComplexity(root);
234
Corentin Wallez71d147f2015-02-11 11:15:24 -0800235 // Create the function DAG and check there is no recursion
zmo@google.comb1762df2011-07-30 02:04:23 +0000236 if (success)
Corentin Wallez71d147f2015-02-11 11:15:24 -0800237 success = initCallDag(root);
238
239 if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH))
240 success = checkCallDepth();
241
242 // Checks which functions are used and if "main" exists
243 if (success)
244 {
245 functionMetadata.clear();
246 functionMetadata.resize(mCallDag.size());
247 success = tagUsedFunctions();
248 }
zmo@google.comb1762df2011-07-30 02:04:23 +0000249
Corentin Walleza094a8a2015-04-07 11:53:06 -0700250 if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
251 success = pruneUnusedFunctions(root);
252
Olli Etuahoc6833112015-04-22 15:15:54 +0300253 // Prune empty declarations to work around driver bugs and to keep declaration output simple.
254 if (success)
255 PruneEmptyDeclarations(root);
256
Jamie Madill183bde52014-07-02 15:31:19 -0400257 if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
Jamie Madill05a80ce2013-06-20 11:55:49 -0400258 success = validateOutputs(root);
259
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000260 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
261 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000262
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000263 if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000264 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000265
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000266 if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
267 rewriteCSSShader(root);
268
zmo@google.com0c6bb7a2011-08-17 19:39:58 +0000269 // Unroll for-loop markup needs to happen after validateLimitations pass.
270 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
Zhenyao Mo3cdfcce2014-03-07 13:00:08 -0800271 {
272 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800273 root->traverse(&marker);
274 }
275 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
Zhenyao Mo3cdfcce2014-03-07 13:00:08 -0800276 {
277 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex);
Zhenyao Mo550c6002014-02-26 15:40:48 -0800278 root->traverse(&marker);
279 if (marker.samplerArrayIndexIsFloatLoopIndex())
280 {
281 infoSink.info.prefix(EPrefixError);
282 infoSink.info << "sampler array index is float loop index";
283 success = false;
284 }
285 }
zmo@google.com0c6bb7a2011-08-17 19:39:58 +0000286
zmo@google.com32e97312011-08-24 01:03:11 +0000287 // Built-in function emulation needs to happen after validateLimitations pass.
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200288 if (success)
289 {
290 initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
zmo@google.com32e97312011-08-24 01:03:11 +0000291 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200292 }
zmo@google.com32e97312011-08-24 01:03:11 +0000293
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000294 // Clamping uniform array bounds needs to happen after validateLimitations pass.
295 if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
296 arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
297
Jamie Madill183bde52014-07-02 15:31:19 -0400298 if (success && shaderType == GL_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800299 initializeGLPosition(root);
Zhenyao Moac44cd22013-09-23 14:57:09 -0400300
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800301 if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
302 {
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700303 UnfoldShortCircuitAST unfoldShortCircuit;
304 root->traverse(&unfoldShortCircuit);
305 unfoldShortCircuit.updateTree();
306 }
307
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800308 if (success && (compileOptions & SH_VARIABLES))
309 {
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400310 collectVariables(root);
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800311 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
312 {
gman@chromium.org8d804792012-10-17 21:33:48 +0000313 success = enforcePackingRestrictions();
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800314 if (!success)
315 {
Jamie Madill075edd82013-07-08 13:30:19 -0400316 infoSink.info.prefix(EPrefixError);
317 infoSink.info << "too many uniforms";
gman@chromium.org8d804792012-10-17 21:33:48 +0000318 }
319 }
Jamie Madill183bde52014-07-02 15:31:19 -0400320 if (success && shaderType == GL_VERTEX_SHADER &&
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800321 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
322 initializeVaryingsWithoutStaticUse(root);
gman@chromium.org8d804792012-10-17 21:33:48 +0000323 }
zmo@google.comfd747b82011-04-23 01:30:07 +0000324
Zhenyao Mocd68fe72014-07-11 10:45:44 -0700325 if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
326 {
Zhenyao Modaf56572014-08-06 16:18:30 -0700327 ScalarizeVecAndMatConstructorArgs scalarizer(
328 shaderType, fragmentPrecisionHigh);
Zhenyao Mocd68fe72014-07-11 10:45:44 -0700329 root->traverse(&scalarizer);
330 }
331
Zhenyao Moe740add2014-07-18 17:01:01 -0700332 if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
333 {
334 RegenerateStructNames gen(symbolTable, shaderVersion);
335 root->traverse(&gen);
336 }
alokp@chromium.org07620a52010-09-23 17:53:56 +0000337 }
338
Zhenyao Mo7faf1a12014-04-25 18:03:56 -0700339 SetGlobalParseContext(NULL);
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200340 if (success)
341 return root;
342
343 return NULL;
344}
345
346bool TCompiler::compile(const char* const shaderStrings[],
347 size_t numStrings, int compileOptions)
348{
349 if (numStrings == 0)
350 return true;
351
352 TScopedPoolAllocator scopedAlloc(&allocator);
353 TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
354
355 if (root)
356 {
357 if (compileOptions & SH_INTERMEDIATE_TREE)
358 TIntermediate::outputTree(root, infoSink.info);
359
360 if (compileOptions & SH_OBJECT_CODE)
361 translate(root, compileOptions);
362
363 // The IntermNode tree doesn't need to be deleted here, since the
364 // memory will be freed in a big chunk by the PoolAllocator.
365 return true;
366 }
367 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000368}
369
Nicolas Capens49a88872013-06-20 09:54:03 -0400370bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000371{
shannon.woods%transgaming.com@gtempaccount.com18b4c4b2013-04-13 03:31:40 +0000372 compileResources = resources;
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400373 setResourceString();
shannonwoods@chromium.org2ac0be92013-05-30 00:02:27 +0000374
Nicolas Capens49a88872013-06-20 09:54:03 -0400375 assert(symbolTable.isEmpty());
376 symbolTable.push(); // COMMON_BUILTINS
377 symbolTable.push(); // ESSL1_BUILTINS
378 symbolTable.push(); // ESSL3_BUILTINS
shannonwoods@chromium.org2ac0be92013-05-30 00:02:27 +0000379
Nicolas Capens49a88872013-06-20 09:54:03 -0400380 TPublicType integer;
381 integer.type = EbtInt;
382 integer.primarySize = 1;
383 integer.secondarySize = 1;
384 integer.array = false;
385
386 TPublicType floatingPoint;
387 floatingPoint.type = EbtFloat;
388 floatingPoint.primarySize = 1;
389 floatingPoint.secondarySize = 1;
390 floatingPoint.array = false;
391
Zhenyao Moa5a1dfc2013-09-23 14:57:03 -0400392 TPublicType sampler;
393 sampler.primarySize = 1;
394 sampler.secondarySize = 1;
395 sampler.array = false;
396
Nicolas Capens49a88872013-06-20 09:54:03 -0400397 switch(shaderType)
398 {
Jamie Madill183bde52014-07-02 15:31:19 -0400399 case GL_FRAGMENT_SHADER:
Nicolas Capens49a88872013-06-20 09:54:03 -0400400 symbolTable.setDefaultPrecision(integer, EbpMedium);
401 break;
Jamie Madill183bde52014-07-02 15:31:19 -0400402 case GL_VERTEX_SHADER:
Nicolas Capens49a88872013-06-20 09:54:03 -0400403 symbolTable.setDefaultPrecision(integer, EbpHigh);
404 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
405 break;
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800406 default:
407 assert(false && "Language not supported");
Nicolas Capens49a88872013-06-20 09:54:03 -0400408 }
Zhenyao Moa5a1dfc2013-09-23 14:57:03 -0400409 // We set defaults for all the sampler types, even those that are
410 // only available if an extension exists.
411 for (int samplerType = EbtGuardSamplerBegin + 1;
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800412 samplerType < EbtGuardSamplerEnd; ++samplerType)
413 {
Zhenyao Moa5a1dfc2013-09-23 14:57:03 -0400414 sampler.type = static_cast<TBasicType>(samplerType);
415 symbolTable.setDefaultPrecision(sampler, EbpLow);
416 }
Nicolas Capens49a88872013-06-20 09:54:03 -0400417
Jamie Madill1b452142013-07-12 14:51:11 -0400418 InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
Nicolas Capens49a88872013-06-20 09:54:03 -0400419
420 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
421
422 return true;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000423}
424
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400425void TCompiler::setResourceString()
426{
427 std::ostringstream strstream;
428 strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
429 << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
430 << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
431 << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
432 << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
433 << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
434 << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
435 << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
436 << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
437 << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
438 << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
439 << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
440 << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
441 << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
442 << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
443 << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
444 << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100445 << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
446 << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
447 << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400448 << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
449 << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
450 << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
Olli Etuahoe61209a2014-09-26 12:01:17 +0300451 << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200452 << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
453 << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision;
Shannon Woods2d76e5f2014-05-16 17:46:41 -0400454
455 builtInResourcesString = strstream.str();
456}
457
alokp@chromium.org07620a52010-09-23 17:53:56 +0000458void TCompiler::clearResults()
459{
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000460 arrayBoundsClamper.Cleanup();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000461 infoSink.info.erase();
462 infoSink.obj.erase();
463 infoSink.debug.erase();
464
Jamie Madilled27c722014-07-02 15:31:23 -0400465 attributes.clear();
466 outputVariables.clear();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000467 uniforms.clear();
Jamie Madill23a8a432014-07-09 13:27:42 -0400468 expandedUniforms.clear();
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400469 varyings.clear();
Jamie Madilled27c722014-07-02 15:31:23 -0400470 interfaceBlocks.clear();
zmo@google.coma3b4ab42011-09-16 00:53:26 +0000471
472 builtInFunctionEmulator.Cleanup();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000473
474 nameMap.clear();
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200475
476 mSourcePath = NULL;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000477}
478
Corentin Wallez71d147f2015-02-11 11:15:24 -0800479bool TCompiler::initCallDag(TIntermNode *root)
zmo@google.comb1762df2011-07-30 02:04:23 +0000480{
Corentin Wallez71d147f2015-02-11 11:15:24 -0800481 mCallDag.clear();
482
483 switch (mCallDag.init(root, &infoSink.info))
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800484 {
Corentin Wallez71d147f2015-02-11 11:15:24 -0800485 case CallDAG::INITDAG_SUCCESS:
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800486 return true;
Corentin Wallez71d147f2015-02-11 11:15:24 -0800487 case CallDAG::INITDAG_RECURSION:
488 infoSink.info.prefix(EPrefixError);
489 infoSink.info << "Function recursion detected";
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800490 return false;
Corentin Wallez71d147f2015-02-11 11:15:24 -0800491 case CallDAG::INITDAG_UNDEFINED:
492 infoSink.info.prefix(EPrefixError);
493 infoSink.info << "Unimplemented function detected";
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800494 return false;
Corentin Wallez71d147f2015-02-11 11:15:24 -0800495 }
496
497 UNREACHABLE();
498 return true;
499}
500
501bool TCompiler::checkCallDepth()
502{
503 std::vector<int> depths(mCallDag.size());
504
505 for (size_t i = 0; i < mCallDag.size(); i++)
506 {
507 int depth = 0;
508 auto &record = mCallDag.getRecordFromIndex(i);
509
510 for (auto &calleeIndex : record.callees)
511 {
512 depth = std::max(depth, depths[calleeIndex] + 1);
513 }
514
515 depths[i] = depth;
516
517 if (depth >= maxCallStackDepth)
518 {
519 // Trace back the function chain to have a meaningful info log.
520 infoSink.info.prefix(EPrefixError);
521 infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
522 << ") with the following call chain: " << record.name;
523
524 int currentFunction = i;
525 int currentDepth = depth;
526
527 while (currentFunction != -1)
528 {
529 infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
530
531 int nextFunction = -1;
532 for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
533 {
534 if (depths[calleeIndex] == currentDepth - 1)
535 {
536 currentDepth--;
537 nextFunction = calleeIndex;
538 }
539 }
540
541 currentFunction = nextFunction;
542 }
543
544 return false;
545 }
546 }
547
548 return true;
549}
550
551bool TCompiler::tagUsedFunctions()
552{
553 // Search from main, starting from the end of the DAG as it usually is the root.
554 for (int i = mCallDag.size(); i-- > 0;)
555 {
556 if (mCallDag.getRecordFromIndex(i).name == "main(")
557 {
558 internalTagUsedFunction(i);
559 return true;
560 }
561 }
562
563 infoSink.info.prefix(EPrefixError);
564 infoSink.info << "Missing main()";
565 return false;
566}
567
568void TCompiler::internalTagUsedFunction(size_t index)
569{
570 if (functionMetadata[index].used)
571 {
572 return;
573 }
574
575 functionMetadata[index].used = true;
576
577 for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees)
578 {
579 internalTagUsedFunction(calleeIndex);
zmo@google.comb1762df2011-07-30 02:04:23 +0000580 }
581}
582
Corentin Walleza094a8a2015-04-07 11:53:06 -0700583// A predicate for the stl that returns if a top-level node is unused
584class TCompiler::UnusedPredicate
585{
586 public:
587 UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
588 : mCallDag(callDag),
589 mMetadatas(metadatas)
590 {
591 }
592
593 bool operator ()(TIntermNode *node)
594 {
595 const TIntermAggregate *asAggregate = node->getAsAggregate();
596
597 if (asAggregate == nullptr)
598 {
599 return false;
600 }
601
602 if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype))
603 {
604 return false;
605 }
606
607 size_t callDagIndex = mCallDag->findIndex(asAggregate);
608 if (callDagIndex == CallDAG::InvalidIndex)
609 {
610 // This happens only for unimplemented prototypes which are thus unused
611 ASSERT(asAggregate->getOp() == EOpPrototype);
612 return true;
613 }
614
615 ASSERT(callDagIndex < mMetadatas->size());
616 return !(*mMetadatas)[callDagIndex].used;
617 }
618
619 private:
620 const CallDAG *mCallDag;
621 const std::vector<FunctionMetadata> *mMetadatas;
622};
623
624bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
625{
626 TIntermAggregate *rootNode = root->getAsAggregate();
627 ASSERT(rootNode != nullptr);
628
629 UnusedPredicate isUnused(&mCallDag, &functionMetadata);
630 TIntermSequence *sequence = rootNode->getSequence();
631 sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
632
633 return true;
634}
635
Jamie Madill05a80ce2013-06-20 11:55:49 -0400636bool TCompiler::validateOutputs(TIntermNode* root)
637{
638 ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers);
639 root->traverse(&validateOutputs);
640 return (validateOutputs.numErrors() == 0);
641}
642
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000643void TCompiler::rewriteCSSShader(TIntermNode* root)
644{
645 RenameFunction renamer("main(", "css_main(");
646 root->traverse(&renamer);
647}
648
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800649bool TCompiler::validateLimitations(TIntermNode* root)
650{
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000651 ValidateLimitations validate(shaderType, infoSink.info);
652 root->traverse(&validate);
653 return validate.numErrors() == 0;
654}
655
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000656bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000657{
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800658 if (shaderSpec != SH_WEBGL_SPEC)
659 {
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000660 infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
661 return false;
662 }
663
Jamie Madill183bde52014-07-02 15:31:19 -0400664 if (shaderType == GL_FRAGMENT_SHADER)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800665 {
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000666 TDependencyGraph graph(root);
667
668 // Output any errors first.
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000669 bool success = enforceFragmentShaderTimingRestrictions(graph);
Jamie Madill5508f392014-02-20 13:31:36 -0500670
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000671 // Then, output the dependency graph.
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800672 if (outputGraph)
673 {
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000674 TDependencyGraphOutput output(infoSink.info);
675 output.outputAllSpanningTrees(graph);
676 }
Jamie Madill5508f392014-02-20 13:31:36 -0500677
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000678 return success;
679 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800680 else
681 {
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000682 return enforceVertexShaderTimingRestrictions(root);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000683 }
684}
685
Jamie Madilleb1a0102013-07-08 13:31:38 -0400686bool TCompiler::limitExpressionComplexity(TIntermNode* root)
687{
Jamie Madill6654bc92014-03-26 14:01:57 -0400688 TMaxDepthTraverser traverser(maxExpressionComplexity+1);
Jamie Madilleb1a0102013-07-08 13:31:38 -0400689 root->traverse(&traverser);
Jamie Madill6654bc92014-03-26 14:01:57 -0400690
691 if (traverser.getMaxDepth() > maxExpressionComplexity)
692 {
693 infoSink.info << "Expression too complex.";
694 return false;
695 }
696
Jamie Madilleb1a0102013-07-08 13:31:38 -0400697 TDependencyGraph graph(root);
698
699 for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
700 iter != graph.endUserDefinedFunctionCalls();
701 ++iter)
702 {
703 TGraphFunctionCall* samplerSymbol = *iter;
704 TDependencyGraphTraverser graphTraverser;
705 samplerSymbol->traverse(&graphTraverser);
706 }
707
Jamie Madilleb1a0102013-07-08 13:31:38 -0400708 return true;
709}
710
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000711bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000712{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000713 RestrictFragmentShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000714 restrictor.enforceRestrictions(graph);
715 return restrictor.numErrors() == 0;
716}
717
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000718bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000719{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000720 RestrictVertexShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000721 restrictor.enforceRestrictions(root);
722 return restrictor.numErrors() == 0;
723}
724
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400725void TCompiler::collectVariables(TIntermNode* root)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000726{
Jamie Madilla2fbb842014-09-03 09:40:47 -0400727 sh::CollectVariables collect(&attributes,
728 &outputVariables,
729 &uniforms,
730 &varyings,
731 &interfaceBlocks,
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700732 hashFunction,
733 symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000734 root->traverse(&collect);
Jamie Madill23a8a432014-07-09 13:27:42 -0400735
Zhenyao Mo409078f2014-10-28 13:23:18 -0700736 // This is for enforcePackingRestriction().
737 sh::ExpandUniforms(uniforms, &expandedUniforms);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000738}
zmo@google.comfd747b82011-04-23 01:30:07 +0000739
gman@chromium.org8d804792012-10-17 21:33:48 +0000740bool TCompiler::enforcePackingRestrictions()
741{
742 VariablePacker packer;
Jamie Madill23a8a432014-07-09 13:27:42 -0400743 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
gman@chromium.org8d804792012-10-17 21:33:48 +0000744}
745
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800746void TCompiler::initializeGLPosition(TIntermNode* root)
747{
748 InitializeVariables::InitVariableInfoList variables;
749 InitializeVariables::InitVariableInfo var(
750 "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
751 variables.push_back(var);
752 InitializeVariables initializer(variables);
753 root->traverse(&initializer);
754}
755
756void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
757{
758 InitializeVariables::InitVariableInfoList variables;
759 for (size_t ii = 0; ii < varyings.size(); ++ii)
760 {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400761 const sh::Varying& varying = varyings[ii];
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800762 if (varying.staticUse)
763 continue;
Jamie Madillaa72d782014-07-02 15:31:19 -0400764 unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type));
765 unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type));
Jamie Madilla718c1e2014-07-02 15:31:22 -0400766 TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800767 TString name = varying.name.c_str();
Jamie Madilla718c1e2014-07-02 15:31:22 -0400768 if (varying.isArray())
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800769 {
Jamie Madilla718c1e2014-07-02 15:31:22 -0400770 type.setArraySize(varying.arraySize);
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800771 name = name.substr(0, name.find_first_of('['));
772 }
773
774 InitializeVariables::InitVariableInfo var(name, type);
775 variables.push_back(var);
776 }
777 InitializeVariables initializer(variables);
778 root->traverse(&initializer);
779}
780
zmo@google.com5601ea02011-06-10 18:23:25 +0000781const TExtensionBehavior& TCompiler::getExtensionBehavior() const
782{
783 return extensionBehavior;
784}
zmo@google.com32e97312011-08-24 01:03:11 +0000785
Olli Etuahoa3a5cc62015-02-13 13:12:22 +0200786const char *TCompiler::getSourcePath() const
787{
788 return mSourcePath;
789}
790
shannon.woods%transgaming.com@gtempaccount.com18b4c4b2013-04-13 03:31:40 +0000791const ShBuiltInResources& TCompiler::getResources() const
792{
793 return compileResources;
794}
795
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000796const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
797{
798 return arrayBoundsClamper;
799}
800
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000801ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
802{
803 return clampingStrategy;
804}
805
Olli Etuaho8efc5ad2015-03-03 17:21:10 +0200806const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000807{
808 return builtInFunctionEmulator;
809}
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700810
811void TCompiler::writePragma()
812{
813 TInfoSinkBase &sink = infoSink.obj;
814 if (mPragma.stdgl.invariantAll)
815 sink << "#pragma STDGL invariant(all)\n";
816}