blob: 245bf3596f05ea8de65febbd541bb6d51d1f7365 [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"
zmo@google.comb9f64aa2012-01-20 00:35:15 +000011#include "compiler/MapLongVariableNames.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000012#include "compiler/ParseHelper.h"
13#include "compiler/ShHandle.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000014#include "compiler/ValidateLimitations.h"
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +000015#include "compiler/depgraph/DependencyGraph.h"
16#include "compiler/depgraph/DependencyGraphOutput.h"
17#include "compiler/timing/RestrictFragmentShaderTiming.h"
18#include "compiler/timing/RestrictVertexShaderTiming.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000019
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000020namespace {
21bool InitializeSymbolTable(
22 const TBuiltInStrings& builtInStrings,
23 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
24 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000025{
26 TIntermediate intermediate(infoSink);
27 TExtensionBehavior extBehavior;
zmo@google.com09c323a2011-08-12 18:22:25 +000028 InitExtensionBehavior(resources, extBehavior);
zmo@google.comdc4b4f82011-06-17 00:42:53 +000029 // The builtins deliberately don't specify precisions for the function
30 // arguments and return types. For that reason we don't try to check them.
31 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000032
33 GlobalParseContext = &parseContext;
34
alokp@chromium.org07620a52010-09-23 17:53:56 +000035 assert(symbolTable.isEmpty());
36 //
37 // Parse the built-ins. This should only happen once per
38 // language symbol table.
39 //
40 // Push the symbol table to give it an initial scope. This
41 // push should not have a corresponding pop, so that built-ins
42 // are preserved, and the test for an empty table fails.
43 //
44 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000045
46 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
47 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000048 const char* builtInShaders = i->c_str();
49 int builtInLengths = static_cast<int>(i->size());
50 if (builtInLengths <= 0)
51 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000052
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000053 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000054 {
55 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
56 return false;
57 }
58 }
59
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000060 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000061
alokp@chromium.org07620a52010-09-23 17:53:56 +000062 return true;
63}
64
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000065class TScopedPoolAllocator {
66public:
67 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
68 : mAllocator(allocator), mPushPopAllocator(pushPop) {
69 if (mPushPopAllocator) mAllocator->push();
70 SetGlobalPoolAllocator(mAllocator);
71 }
72 ~TScopedPoolAllocator() {
73 SetGlobalPoolAllocator(NULL);
74 if (mPushPopAllocator) mAllocator->pop();
75 }
76
77private:
78 TPoolAllocator* mAllocator;
79 bool mPushPopAllocator;
80};
81} // namespace
82
83TShHandleBase::TShHandleBase() {
84 allocator.push();
85 SetGlobalPoolAllocator(&allocator);
86}
87
88TShHandleBase::~TShHandleBase() {
89 SetGlobalPoolAllocator(NULL);
90 allocator.popAll();
91}
92
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000093TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
94 : shaderType(type),
zmo@google.comf420c422011-09-12 18:27:59 +000095 shaderSpec(spec),
zmo@google.com9996b8e2012-01-19 01:43:55 +000096 builtInFunctionEmulator(type)
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000097{
zmo@google.comb9f64aa2012-01-20 00:35:15 +000098 longNameMap = LongNameMap::GetInstance();
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000099}
100
101TCompiler::~TCompiler()
102{
zmo@google.comb9f64aa2012-01-20 00:35:15 +0000103 ASSERT(longNameMap);
104 longNameMap->Release();
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000105}
106
107bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000108{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000109 TScopedPoolAllocator scopedAlloc(&allocator, false);
110
alokp@chromium.org07620a52010-09-23 17:53:56 +0000111 // Generate built-in symbol table.
112 if (!InitBuiltInSymbolTable(resources))
113 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000114 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000115
alokp@chromium.org07620a52010-09-23 17:53:56 +0000116 return true;
117}
118
119bool TCompiler::compile(const char* const shaderStrings[],
120 const int numStrings,
121 int compileOptions)
122{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000123 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000124 clearResults();
125
126 if (numStrings == 0)
127 return true;
128
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000129 // If compiling for WebGL, validate loop and indexing as well.
130 if (shaderSpec == SH_WEBGL_SPEC)
131 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000132
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000133 // First string is path of source file if flag is set. The actual source follows.
134 const char* sourcePath = NULL;
135 int firstSource = 0;
136 if (compileOptions & SH_SOURCE_PATH)
137 {
138 sourcePath = shaderStrings[0];
139 ++firstSource;
140 }
141
alokp@chromium.org07620a52010-09-23 17:53:56 +0000142 TIntermediate intermediate(infoSink);
143 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000144 shaderType, shaderSpec, compileOptions, true,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000145 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000146 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000147
148 // We preserve symbols at the built-in level from compile-to-compile.
149 // Start pushing the user-defined symbols at global level.
150 symbolTable.push();
151 if (!symbolTable.atGlobalLevel())
152 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
153
154 // Parse shader.
155 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000156 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000157 (parseContext.treeRoot != NULL);
158 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000159 TIntermNode* root = parseContext.treeRoot;
160 success = intermediate.postProcess(root);
161
zmo@google.comb1762df2011-07-30 02:04:23 +0000162 if (success)
163 success = detectRecursion(root);
164
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000165 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
166 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000167
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000168 if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000169 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000170
zmo@google.com0c6bb7a2011-08-17 19:39:58 +0000171 // Unroll for-loop markup needs to happen after validateLimitations pass.
172 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
173 ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
174
zmo@google.com32e97312011-08-24 01:03:11 +0000175 // Built-in function emulation needs to happen after validateLimitations pass.
176 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
177 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
178
zmo@google.comfd747b82011-04-23 01:30:07 +0000179 // Call mapLongVariableNames() before collectAttribsUniforms() so in
180 // collectAttribsUniforms() we already have the mapped symbol names and
181 // we could composite mapped and original variable names.
zmo@google.comb1762df2011-07-30 02:04:23 +0000182 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
zmo@google.comfd747b82011-04-23 01:30:07 +0000183 mapLongVariableNames(root);
184
185 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
186 collectAttribsUniforms(root);
187
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000188 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000189 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000190
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000191 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000192 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000193 }
194
195 // Cleanup memory.
196 intermediate.remove(parseContext.treeRoot);
197 // Ensure symbol table is returned to the built-in level,
198 // throwing away all but the built-ins.
199 while (!symbolTable.atBuiltInLevel())
200 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000201
202 return success;
203}
204
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000205bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000206{
207 TBuiltIns builtIns;
208
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000209 builtIns.initialize(shaderType, shaderSpec, resources);
210 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
211 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000212}
213
214void TCompiler::clearResults()
215{
216 infoSink.info.erase();
217 infoSink.obj.erase();
218 infoSink.debug.erase();
219
220 attribs.clear();
221 uniforms.clear();
zmo@google.coma3b4ab42011-09-16 00:53:26 +0000222
223 builtInFunctionEmulator.Cleanup();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000224}
225
zmo@google.comb1762df2011-07-30 02:04:23 +0000226bool TCompiler::detectRecursion(TIntermNode* root)
227{
228 DetectRecursion detect;
229 root->traverse(&detect);
230 switch (detect.detectRecursion()) {
231 case DetectRecursion::kErrorNone:
232 return true;
233 case DetectRecursion::kErrorMissingMain:
234 infoSink.info.message(EPrefixError, "Missing main()");
235 return false;
236 case DetectRecursion::kErrorRecursion:
237 infoSink.info.message(EPrefixError, "Function recursion detected");
238 return false;
239 default:
240 UNREACHABLE();
241 return false;
242 }
243}
244
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000245bool TCompiler::validateLimitations(TIntermNode* root) {
246 ValidateLimitations validate(shaderType, infoSink.info);
247 root->traverse(&validate);
248 return validate.numErrors() == 0;
249}
250
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000251bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000252{
253 if (shaderSpec != SH_WEBGL_SPEC) {
254 infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
255 return false;
256 }
257
258 if (shaderType == SH_FRAGMENT_SHADER) {
259 TDependencyGraph graph(root);
260
261 // Output any errors first.
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000262 bool success = enforceFragmentShaderTimingRestrictions(graph);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000263
264 // Then, output the dependency graph.
265 if (outputGraph) {
266 TDependencyGraphOutput output(infoSink.info);
267 output.outputAllSpanningTrees(graph);
268 }
269
270 return success;
271 }
272 else {
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000273 return enforceVertexShaderTimingRestrictions(root);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000274 }
275}
276
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000277bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000278{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000279 RestrictFragmentShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000280 restrictor.enforceRestrictions(graph);
281 return restrictor.numErrors() == 0;
282}
283
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000284bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000285{
maxvujovic@gmail.com77222c92012-06-04 21:06:05 +0000286 RestrictVertexShaderTiming restrictor(infoSink.info);
maxvujovic@gmail.com66ebd012012-05-30 22:18:11 +0000287 restrictor.enforceRestrictions(root);
288 return restrictor.numErrors() == 0;
289}
290
alokp@chromium.org07620a52010-09-23 17:53:56 +0000291void TCompiler::collectAttribsUniforms(TIntermNode* root)
292{
293 CollectAttribsUniforms collect(attribs, uniforms);
294 root->traverse(&collect);
295}
zmo@google.comfd747b82011-04-23 01:30:07 +0000296
297void TCompiler::mapLongVariableNames(TIntermNode* root)
298{
zmo@google.comb9f64aa2012-01-20 00:35:15 +0000299 ASSERT(longNameMap);
300 MapLongVariableNames map(longNameMap);
zmo@google.com9996b8e2012-01-19 01:43:55 +0000301 root->traverse(&map);
zmo@google.comfd747b82011-04-23 01:30:07 +0000302}
303
304int TCompiler::getMappedNameMaxLength() const
305{
kbr@chromium.org22152112011-10-26 01:18:28 +0000306 return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
zmo@google.comfd747b82011-04-23 01:30:07 +0000307}
zmo@google.com5601ea02011-06-10 18:23:25 +0000308
309const TExtensionBehavior& TCompiler::getExtensionBehavior() const
310{
311 return extensionBehavior;
312}
zmo@google.com32e97312011-08-24 01:03:11 +0000313
314const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
315{
316 return builtInFunctionEmulator;
317}