blob: b067fed5562f9d5030663ce68419218cc81276b8 [file] [log] [blame]
alokp@chromium.org07620a52010-09-23 17:53:56 +00001//
zmo@google.comb9f64aa2012-01-20 00:35:15 +00002// Copyright (c) 2002-2012 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
zmo@google.com32e97312011-08-24 01:03:11 +00007#include "compiler/BuiltInFunctionEmulator.h"
zmo@google.comb1762df2011-07-30 02:04:23 +00008#include "compiler/DetectRecursion.h"
zmo@google.com0c6bb7a2011-08-17 19:39:58 +00009#include "compiler/ForLoopUnroll.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000010#include "compiler/Initialize.h"
alokp@chromium.org8b851c62012-06-15 16:25:11 +000011#include "compiler/InitializeParseContext.h"
zmo@google.comb9f64aa2012-01-20 00:35:15 +000012#include "compiler/MapLongVariableNames.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000013#include "compiler/ParseHelper.h"
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +000014#include "compiler/RenameFunction.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000015#include "compiler/ShHandle.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000016#include "compiler/ValidateLimitations.h"
gman@chromium.org8d804792012-10-17 21:33:48 +000017#include "compiler/VariablePacker.h"
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +000018#include "compiler/depgraph/DependencyGraph.h"
19#include "compiler/depgraph/DependencyGraphOutput.h"
20#include "compiler/timing/RestrictFragmentShaderTiming.h"
21#include "compiler/timing/RestrictVertexShaderTiming.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000022
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +000023bool isWebGLBasedSpec(ShShaderSpec spec)
24{
25 return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
26}
27
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000028namespace {
29bool InitializeSymbolTable(
30 const TBuiltInStrings& builtInStrings,
31 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
32 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000033{
34 TIntermediate intermediate(infoSink);
35 TExtensionBehavior extBehavior;
zmo@google.com09c323a2011-08-12 18:22:25 +000036 InitExtensionBehavior(resources, extBehavior);
zmo@google.comdc4b4f82011-06-17 00:42:53 +000037 // The builtins deliberately don't specify precisions for the function
38 // arguments and return types. For that reason we don't try to check them.
39 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000040
41 GlobalParseContext = &parseContext;
42
alokp@chromium.org07620a52010-09-23 17:53:56 +000043 assert(symbolTable.isEmpty());
44 //
45 // Parse the built-ins. This should only happen once per
46 // language symbol table.
47 //
48 // Push the symbol table to give it an initial scope. This
49 // push should not have a corresponding pop, so that built-ins
50 // are preserved, and the test for an empty table fails.
51 //
52 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000053
54 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
55 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000056 const char* builtInShaders = i->c_str();
57 int builtInLengths = static_cast<int>(i->size());
58 if (builtInLengths <= 0)
59 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000060
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000061 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000062 {
63 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
64 return false;
65 }
66 }
67
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000068 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000069
alokp@chromium.org07620a52010-09-23 17:53:56 +000070 return true;
71}
72
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000073class TScopedPoolAllocator {
74public:
75 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
76 : mAllocator(allocator), mPushPopAllocator(pushPop) {
77 if (mPushPopAllocator) mAllocator->push();
78 SetGlobalPoolAllocator(mAllocator);
79 }
80 ~TScopedPoolAllocator() {
81 SetGlobalPoolAllocator(NULL);
82 if (mPushPopAllocator) mAllocator->pop();
83 }
84
85private:
86 TPoolAllocator* mAllocator;
87 bool mPushPopAllocator;
88};
89} // namespace
90
91TShHandleBase::TShHandleBase() {
92 allocator.push();
93 SetGlobalPoolAllocator(&allocator);
94}
95
96TShHandleBase::~TShHandleBase() {
97 SetGlobalPoolAllocator(NULL);
98 allocator.popAll();
99}
100
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000101TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
102 : shaderType(type),
zmo@google.comf420c422011-09-12 18:27:59 +0000103 shaderSpec(spec),
zmo@google.com9996b8e2012-01-19 01:43:55 +0000104 builtInFunctionEmulator(type)
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000105{
zmo@google.comb9f64aa2012-01-20 00:35:15 +0000106 longNameMap = LongNameMap::GetInstance();
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000107}
108
109TCompiler::~TCompiler()
110{
zmo@google.comb9f64aa2012-01-20 00:35:15 +0000111 ASSERT(longNameMap);
112 longNameMap->Release();
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000113}
114
115bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000116{
gman@chromium.org8d804792012-10-17 21:33:48 +0000117 maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
118 resources.MaxVertexUniformVectors :
119 resources.MaxFragmentUniformVectors;
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000120 TScopedPoolAllocator scopedAlloc(&allocator, false);
121
alokp@chromium.org07620a52010-09-23 17:53:56 +0000122 // Generate built-in symbol table.
123 if (!InitBuiltInSymbolTable(resources))
124 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000125 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000126
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000127 hashFunction = resources.HashFunction;
128
alokp@chromium.org07620a52010-09-23 17:53:56 +0000129 return true;
130}
131
132bool TCompiler::compile(const char* const shaderStrings[],
133 const int numStrings,
134 int compileOptions)
135{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000136 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000137 clearResults();
138
139 if (numStrings == 0)
140 return true;
141
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000142 // If compiling for WebGL, validate loop and indexing as well.
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000143 if (isWebGLBasedSpec(shaderSpec))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000145
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000146 // First string is path of source file if flag is set. The actual source follows.
147 const char* sourcePath = NULL;
148 int firstSource = 0;
149 if (compileOptions & SH_SOURCE_PATH)
150 {
151 sourcePath = shaderStrings[0];
152 ++firstSource;
153 }
154
alokp@chromium.org07620a52010-09-23 17:53:56 +0000155 TIntermediate intermediate(infoSink);
156 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000157 shaderType, shaderSpec, compileOptions, true,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000158 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000159 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000160
161 // We preserve symbols at the built-in level from compile-to-compile.
162 // Start pushing the user-defined symbols at global level.
163 symbolTable.push();
164 if (!symbolTable.atGlobalLevel())
165 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
166
167 // Parse shader.
168 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000169 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000170 (parseContext.treeRoot != NULL);
171 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000172 TIntermNode* root = parseContext.treeRoot;
173 success = intermediate.postProcess(root);
174
zmo@google.comb1762df2011-07-30 02:04:23 +0000175 if (success)
176 success = detectRecursion(root);
177
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000178 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
179 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000180
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000181 if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000182 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000183
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000184 if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
185 rewriteCSSShader(root);
186
zmo@google.com0c6bb7a2011-08-17 19:39:58 +0000187 // Unroll for-loop markup needs to happen after validateLimitations pass.
188 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
189 ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
190
zmo@google.com32e97312011-08-24 01:03:11 +0000191 // Built-in function emulation needs to happen after validateLimitations pass.
192 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
193 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
194
zmo@google.comfd747b82011-04-23 01:30:07 +0000195 // Call mapLongVariableNames() before collectAttribsUniforms() so in
196 // collectAttribsUniforms() we already have the mapped symbol names and
197 // we could composite mapped and original variable names.
zmo@google.comb1762df2011-07-30 02:04:23 +0000198 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
zmo@google.comfd747b82011-04-23 01:30:07 +0000199 mapLongVariableNames(root);
200
gman@chromium.org8d804792012-10-17 21:33:48 +0000201 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
zmo@google.comfd747b82011-04-23 01:30:07 +0000202 collectAttribsUniforms(root);
gman@chromium.org8d804792012-10-17 21:33:48 +0000203 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
204 success = enforcePackingRestrictions();
205 if (!success) {
206 infoSink.info.message(EPrefixError, "too many uniforms");
207 }
208 }
209 }
zmo@google.comfd747b82011-04-23 01:30:07 +0000210
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000211 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000212 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000213
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000214 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000215 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000216 }
217
218 // Cleanup memory.
219 intermediate.remove(parseContext.treeRoot);
220 // Ensure symbol table is returned to the built-in level,
221 // throwing away all but the built-ins.
222 while (!symbolTable.atBuiltInLevel())
223 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000224
225 return success;
226}
227
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000228bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000229{
230 TBuiltIns builtIns;
231
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000232 builtIns.initialize(shaderType, shaderSpec, resources);
233 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
234 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000235}
236
237void TCompiler::clearResults()
238{
239 infoSink.info.erase();
240 infoSink.obj.erase();
241 infoSink.debug.erase();
242
243 attribs.clear();
244 uniforms.clear();
zmo@google.coma3b4ab42011-09-16 00:53:26 +0000245
246 builtInFunctionEmulator.Cleanup();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000247}
248
zmo@google.comb1762df2011-07-30 02:04:23 +0000249bool TCompiler::detectRecursion(TIntermNode* root)
250{
251 DetectRecursion detect;
252 root->traverse(&detect);
253 switch (detect.detectRecursion()) {
254 case DetectRecursion::kErrorNone:
255 return true;
256 case DetectRecursion::kErrorMissingMain:
257 infoSink.info.message(EPrefixError, "Missing main()");
258 return false;
259 case DetectRecursion::kErrorRecursion:
260 infoSink.info.message(EPrefixError, "Function recursion detected");
261 return false;
262 default:
263 UNREACHABLE();
264 return false;
265 }
266}
267
maxvujovic@gmail.com430f5e02012-06-08 17:47:59 +0000268void TCompiler::rewriteCSSShader(TIntermNode* root)
269{
270 RenameFunction renamer("main(", "css_main(");
271 root->traverse(&renamer);
272}
273
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000274bool TCompiler::validateLimitations(TIntermNode* root) {
275 ValidateLimitations validate(shaderType, infoSink.info);
276 root->traverse(&validate);
277 return validate.numErrors() == 0;
278}
279
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000280bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000281{
282 if (shaderSpec != SH_WEBGL_SPEC) {
283 infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
284 return false;
285 }
286
287 if (shaderType == SH_FRAGMENT_SHADER) {
288 TDependencyGraph graph(root);
289
290 // Output any errors first.
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000291 bool success = enforceFragmentShaderTimingRestrictions(graph);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000292
293 // Then, output the dependency graph.
294 if (outputGraph) {
295 TDependencyGraphOutput output(infoSink.info);
296 output.outputAllSpanningTrees(graph);
297 }
298
299 return success;
300 }
301 else {
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000302 return enforceVertexShaderTimingRestrictions(root);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000303 }
304}
305
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000306bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000307{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000308 RestrictFragmentShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000309 restrictor.enforceRestrictions(graph);
310 return restrictor.numErrors() == 0;
311}
312
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000313bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000314{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000315 RestrictVertexShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000316 restrictor.enforceRestrictions(root);
317 return restrictor.numErrors() == 0;
318}
319
alokp@chromium.org07620a52010-09-23 17:53:56 +0000320void TCompiler::collectAttribsUniforms(TIntermNode* root)
321{
322 CollectAttribsUniforms collect(attribs, uniforms);
323 root->traverse(&collect);
324}
zmo@google.comfd747b82011-04-23 01:30:07 +0000325
gman@chromium.org8d804792012-10-17 21:33:48 +0000326bool TCompiler::enforcePackingRestrictions()
327{
328 VariablePacker packer;
329 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
330}
331
zmo@google.comfd747b82011-04-23 01:30:07 +0000332void TCompiler::mapLongVariableNames(TIntermNode* root)
333{
zmo@google.comb9f64aa2012-01-20 00:35:15 +0000334 ASSERT(longNameMap);
335 MapLongVariableNames map(longNameMap);
zmo@google.com9996b8e2012-01-19 01:43:55 +0000336 root->traverse(&map);
zmo@google.comfd747b82011-04-23 01:30:07 +0000337}
338
339int TCompiler::getMappedNameMaxLength() const
340{
kbr@chromium.org22152112011-10-26 01:18:28 +0000341 return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
zmo@google.comfd747b82011-04-23 01:30:07 +0000342}
zmo@google.com5601ea02011-06-10 18:23:25 +0000343
344const TExtensionBehavior& TCompiler::getExtensionBehavior() const
345{
346 return extensionBehavior;
347}
zmo@google.com32e97312011-08-24 01:03:11 +0000348
349const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
350{
351 return builtInFunctionEmulator;
352}