blob: d1b36c050a4ce11177d7a6b0320a98446d88ddec [file] [log] [blame]
John Bauman66b8ab22014-05-06 15:57:45 -04001//
John Baumand4ae8632014-05-06 16:18:33 -04002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
John Bauman66b8ab22014-05-06 15:57:45 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
John Baumand4ae8632014-05-06 16:18:33 -04007#include "compiler/AnalyzeCallDepth.h"
John Bauman66b8ab22014-05-06 15:57:45 -04008#include "compiler/Initialize.h"
9#include "compiler/InitializeParseContext.h"
10#include "compiler/ParseHelper.h"
11#include "compiler/ShHandle.h"
12#include "compiler/ValidateLimitations.h"
13
John Baumand4ae8632014-05-06 16:18:33 -040014namespace
John Bauman66b8ab22014-05-06 15:57:45 -040015{
John Bauman66b8ab22014-05-06 15:57:45 -040016class TScopedPoolAllocator {
17public:
18 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
19 : mAllocator(allocator), mPushPopAllocator(pushPop) {
20 if (mPushPopAllocator) mAllocator->push();
21 SetGlobalPoolAllocator(mAllocator);
22 }
23 ~TScopedPoolAllocator() {
24 SetGlobalPoolAllocator(NULL);
25 if (mPushPopAllocator) mAllocator->pop();
26 }
27
28private:
29 TPoolAllocator* mAllocator;
30 bool mPushPopAllocator;
31};
32} // namespace
33
34TShHandleBase::TShHandleBase() {
35 allocator.push();
36 SetGlobalPoolAllocator(&allocator);
37}
38
39TShHandleBase::~TShHandleBase() {
40 SetGlobalPoolAllocator(NULL);
41 allocator.popAll();
42}
43
44TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
45 : shaderType(type),
John Baumand4ae8632014-05-06 16:18:33 -040046 shaderSpec(spec),
47 maxCallStackDepth(UINT_MAX)
John Bauman66b8ab22014-05-06 15:57:45 -040048{
49}
50
51TCompiler::~TCompiler()
52{
53}
54
55bool TCompiler::Init(const ShBuiltInResources& resources)
56{
John Baumand4ae8632014-05-06 16:18:33 -040057 maxCallStackDepth = resources.MaxCallStackDepth;
John Bauman66b8ab22014-05-06 15:57:45 -040058 TScopedPoolAllocator scopedAlloc(&allocator, false);
59
60 // Generate built-in symbol table.
61 if (!InitBuiltInSymbolTable(resources))
62 return false;
63 InitExtensionBehavior(resources, extensionBehavior);
64
65 return true;
66}
67
68bool TCompiler::compile(const char* const shaderStrings[],
69 const int numStrings,
70 int compileOptions)
71{
72 TScopedPoolAllocator scopedAlloc(&allocator, true);
73 clearResults();
74
75 if (numStrings == 0)
76 return true;
77
78 // If compiling for WebGL, validate loop and indexing as well.
79 if (shaderSpec == SH_WEBGL_SPEC)
80 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
81
82 // First string is path of source file if flag is set. The actual source follows.
83 const char* sourcePath = NULL;
84 int firstSource = 0;
85 if (compileOptions & SH_SOURCE_PATH)
86 {
87 sourcePath = shaderStrings[0];
88 ++firstSource;
89 }
90
91 TIntermediate intermediate(infoSink);
92 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
93 shaderType, shaderSpec, compileOptions, true,
94 sourcePath, infoSink);
95 GlobalParseContext = &parseContext;
96
97 // We preserve symbols at the built-in level from compile-to-compile.
98 // Start pushing the user-defined symbols at global level.
99 symbolTable.push();
100 if (!symbolTable.atGlobalLevel())
101 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
102
103 // Parse shader.
104 bool success =
105 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
106 (parseContext.treeRoot != NULL);
107 if (success) {
108 TIntermNode* root = parseContext.treeRoot;
109 success = intermediate.postProcess(root);
110
111 if (success)
John Baumand4ae8632014-05-06 16:18:33 -0400112 success = validateCallDepth(root, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400113
114 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
115 success = validateLimitations(root);
116
117 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
118 collectAttribsUniforms(root);
119
120 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
121 intermediate.outputTree(root);
122
123 if (success && (compileOptions & SH_OBJECT_CODE))
Nicolas Capens014b9a62014-10-15 10:28:29 -0400124 success = translate(root);
John Bauman66b8ab22014-05-06 15:57:45 -0400125 }
126
127 // Cleanup memory.
128 intermediate.remove(parseContext.treeRoot);
129 // Ensure symbol table is returned to the built-in level,
130 // throwing away all but the built-ins.
131 while (!symbolTable.atBuiltInLevel())
132 symbolTable.pop();
133
134 return success;
135}
136
John Baumand4ae8632014-05-06 16:18:33 -0400137bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
John Bauman66b8ab22014-05-06 15:57:45 -0400138{
John Baumand4ae8632014-05-06 16:18:33 -0400139 assert(symbolTable.isEmpty());
140
141 //
142 // Push the symbol table to give it an initial scope. This
143 // push should not have a corresponding pop, so that built-ins
144 // are preserved, and the test for an empty table fails.
145 //
146 symbolTable.push();
John Bauman66b8ab22014-05-06 15:57:45 -0400147
John Baumand4ae8632014-05-06 16:18:33 -0400148 TPublicType integer;
149 integer.type = EbtInt;
150 integer.size = 1;
151 integer.matrix = false;
152 integer.array = false;
153
154 TPublicType floatingPoint;
155 floatingPoint.type = EbtFloat;
156 floatingPoint.size = 1;
157 floatingPoint.matrix = false;
158 floatingPoint.array = false;
159
160 switch(shaderType)
161 {
162 case SH_FRAGMENT_SHADER:
163 symbolTable.setDefaultPrecision(integer, EbpMedium);
164 break;
165 case SH_VERTEX_SHADER:
166 symbolTable.setDefaultPrecision(integer, EbpHigh);
167 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
168 break;
169 default: assert(false && "Language not supported");
170 }
171
172 InsertBuiltInFunctions(shaderType, resources, symbolTable);
173
174 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
175
176 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400177}
178
179void TCompiler::clearResults()
180{
181 infoSink.info.erase();
182 infoSink.obj.erase();
183 infoSink.debug.erase();
184
185 attribs.clear();
186 uniforms.clear();
187}
188
John Baumand4ae8632014-05-06 16:18:33 -0400189bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
John Bauman66b8ab22014-05-06 15:57:45 -0400190{
John Baumand4ae8632014-05-06 16:18:33 -0400191 AnalyzeCallDepth validator(root);
192
193 unsigned int depth = validator.analyzeCallDepth();
194
195 if(depth == 0)
196 {
197 infoSink.info.prefix(EPrefixError);
198 infoSink.info << "Missing main()";
199 return false;
200 }
201 else if(depth == UINT_MAX)
202 {
203 infoSink.info.prefix(EPrefixError);
204 infoSink.info << "Function recursion detected";
205 return false;
206 }
207 else if(depth > maxCallStackDepth)
208 {
209 infoSink.info.prefix(EPrefixError);
210 infoSink.info << "Function call stack too deep";
211 return false;
212 }
213
214 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400215}
216
217bool TCompiler::validateLimitations(TIntermNode* root) {
218 ValidateLimitations validate(shaderType, infoSink.info);
219 root->traverse(&validate);
220 return validate.numErrors() == 0;
221}
222
223void TCompiler::collectAttribsUniforms(TIntermNode* root)
224{
225 CollectAttribsUniforms collect(attribs, uniforms);
226 root->traverse(&collect);
227}
228
229const TExtensionBehavior& TCompiler::getExtensionBehavior() const
230{
231 return extensionBehavior;
232}