blob: 361152af3a0309f457b377bec27e66af16a4f2fe [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
Nicolas Capens6407fe82015-02-10 16:27:49 -05007#include "Compiler.h"
8
Nicolas Capenscc863da2015-01-21 15:50:55 -05009#include "AnalyzeCallDepth.h"
10#include "Initialize.h"
11#include "InitializeParseContext.h"
Nicolas Capens6407fe82015-02-10 16:27:49 -050012#include "InitializeGlobals.h"
Nicolas Capenscc863da2015-01-21 15:50:55 -050013#include "ParseHelper.h"
Nicolas Capenscc863da2015-01-21 15:50:55 -050014#include "ValidateLimitations.h"
John Bauman66b8ab22014-05-06 15:57:45 -040015
John Baumand4ae8632014-05-06 16:18:33 -040016namespace
John Bauman66b8ab22014-05-06 15:57:45 -040017{
John Bauman66b8ab22014-05-06 15:57:45 -040018class TScopedPoolAllocator {
19public:
20 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
21 : mAllocator(allocator), mPushPopAllocator(pushPop) {
22 if (mPushPopAllocator) mAllocator->push();
23 SetGlobalPoolAllocator(mAllocator);
24 }
25 ~TScopedPoolAllocator() {
26 SetGlobalPoolAllocator(NULL);
27 if (mPushPopAllocator) mAllocator->pop();
28 }
29
30private:
31 TPoolAllocator* mAllocator;
32 bool mPushPopAllocator;
33};
34} // namespace
35
Nicolas Capens6407fe82015-02-10 16:27:49 -050036//
37// Initialize built-in resources with minimum expected values.
38//
39ShBuiltInResources::ShBuiltInResources()
40{
41 // Constants.
42 MaxVertexAttribs = 8;
43 MaxVertexUniformVectors = 128;
44 MaxVaryingVectors = 8;
45 MaxVertexTextureImageUnits = 0;
46 MaxCombinedTextureImageUnits = 8;
47 MaxTextureImageUnits = 8;
48 MaxFragmentUniformVectors = 16;
49 MaxDrawBuffers = 1;
50
51 // Extensions.
52 OES_standard_derivatives = 0;
53 OES_fragment_precision_high = 0;
54 OES_EGL_image_external = 0;
55
56 MaxCallStackDepth = UINT_MAX;
57}
58
John Bauman66b8ab22014-05-06 15:57:45 -040059TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
60 : shaderType(type),
John Baumand4ae8632014-05-06 16:18:33 -040061 shaderSpec(spec),
62 maxCallStackDepth(UINT_MAX)
John Bauman66b8ab22014-05-06 15:57:45 -040063{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050064 allocator.push();
65 SetGlobalPoolAllocator(&allocator);
John Bauman66b8ab22014-05-06 15:57:45 -040066}
67
68TCompiler::~TCompiler()
69{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050070 SetGlobalPoolAllocator(NULL);
71 allocator.popAll();
John Bauman66b8ab22014-05-06 15:57:45 -040072}
73
74bool TCompiler::Init(const ShBuiltInResources& resources)
75{
Nicolas Capensb28964b2015-02-10 15:23:06 -050076 shaderVersion = 100;
John Baumand4ae8632014-05-06 16:18:33 -040077 maxCallStackDepth = resources.MaxCallStackDepth;
John Bauman66b8ab22014-05-06 15:57:45 -040078 TScopedPoolAllocator scopedAlloc(&allocator, false);
79
80 // Generate built-in symbol table.
81 if (!InitBuiltInSymbolTable(resources))
82 return false;
83 InitExtensionBehavior(resources, extensionBehavior);
84
85 return true;
86}
87
88bool TCompiler::compile(const char* const shaderStrings[],
89 const int numStrings,
90 int compileOptions)
91{
92 TScopedPoolAllocator scopedAlloc(&allocator, true);
93 clearResults();
94
95 if (numStrings == 0)
96 return true;
97
98 // If compiling for WebGL, validate loop and indexing as well.
99 if (shaderSpec == SH_WEBGL_SPEC)
100 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
101
102 // First string is path of source file if flag is set. The actual source follows.
103 const char* sourcePath = NULL;
104 int firstSource = 0;
105 if (compileOptions & SH_SOURCE_PATH)
106 {
107 sourcePath = shaderStrings[0];
108 ++firstSource;
109 }
110
111 TIntermediate intermediate(infoSink);
112 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
113 shaderType, shaderSpec, compileOptions, true,
114 sourcePath, infoSink);
Nicolas Capens978ddc52014-11-11 12:42:08 -0500115 SetGlobalParseContext(&parseContext);
John Bauman66b8ab22014-05-06 15:57:45 -0400116
117 // We preserve symbols at the built-in level from compile-to-compile.
118 // Start pushing the user-defined symbols at global level.
119 symbolTable.push();
120 if (!symbolTable.atGlobalLevel())
121 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
122
123 // Parse shader.
124 bool success =
125 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
126 (parseContext.treeRoot != NULL);
Nicolas Capensb28964b2015-02-10 15:23:06 -0500127
128 shaderVersion = parseContext.shaderVersion();
129
John Bauman66b8ab22014-05-06 15:57:45 -0400130 if (success) {
131 TIntermNode* root = parseContext.treeRoot;
132 success = intermediate.postProcess(root);
133
134 if (success)
John Baumand4ae8632014-05-06 16:18:33 -0400135 success = validateCallDepth(root, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400136
137 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
138 success = validateLimitations(root);
139
John Bauman66b8ab22014-05-06 15:57:45 -0400140 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
141 intermediate.outputTree(root);
142
143 if (success && (compileOptions & SH_OBJECT_CODE))
Nicolas Capens014b9a62014-10-15 10:28:29 -0400144 success = translate(root);
John Bauman66b8ab22014-05-06 15:57:45 -0400145 }
146
John Bauman66b8ab22014-05-06 15:57:45 -0400147 // Ensure symbol table is returned to the built-in level,
148 // throwing away all but the built-ins.
149 while (!symbolTable.atBuiltInLevel())
150 symbolTable.pop();
151
152 return success;
153}
154
John Baumand4ae8632014-05-06 16:18:33 -0400155bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
John Bauman66b8ab22014-05-06 15:57:45 -0400156{
John Baumand4ae8632014-05-06 16:18:33 -0400157 assert(symbolTable.isEmpty());
158
159 //
160 // Push the symbol table to give it an initial scope. This
161 // push should not have a corresponding pop, so that built-ins
162 // are preserved, and the test for an empty table fails.
163 //
164 symbolTable.push();
John Bauman66b8ab22014-05-06 15:57:45 -0400165
John Baumand4ae8632014-05-06 16:18:33 -0400166 TPublicType integer;
167 integer.type = EbtInt;
168 integer.size = 1;
169 integer.matrix = false;
170 integer.array = false;
171
172 TPublicType floatingPoint;
173 floatingPoint.type = EbtFloat;
174 floatingPoint.size = 1;
175 floatingPoint.matrix = false;
176 floatingPoint.array = false;
177
178 switch(shaderType)
179 {
180 case SH_FRAGMENT_SHADER:
181 symbolTable.setDefaultPrecision(integer, EbpMedium);
182 break;
183 case SH_VERTEX_SHADER:
184 symbolTable.setDefaultPrecision(integer, EbpHigh);
185 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
186 break;
187 default: assert(false && "Language not supported");
188 }
189
190 InsertBuiltInFunctions(shaderType, resources, symbolTable);
191
192 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
193
194 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400195}
196
197void TCompiler::clearResults()
198{
199 infoSink.info.erase();
200 infoSink.obj.erase();
201 infoSink.debug.erase();
John Bauman66b8ab22014-05-06 15:57:45 -0400202}
203
John Baumand4ae8632014-05-06 16:18:33 -0400204bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
John Bauman66b8ab22014-05-06 15:57:45 -0400205{
John Baumand4ae8632014-05-06 16:18:33 -0400206 AnalyzeCallDepth validator(root);
207
208 unsigned int depth = validator.analyzeCallDepth();
209
210 if(depth == 0)
211 {
212 infoSink.info.prefix(EPrefixError);
213 infoSink.info << "Missing main()";
214 return false;
215 }
216 else if(depth == UINT_MAX)
217 {
218 infoSink.info.prefix(EPrefixError);
219 infoSink.info << "Function recursion detected";
220 return false;
221 }
222 else if(depth > maxCallStackDepth)
223 {
224 infoSink.info.prefix(EPrefixError);
225 infoSink.info << "Function call stack too deep";
226 return false;
227 }
228
229 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400230}
231
232bool TCompiler::validateLimitations(TIntermNode* root) {
233 ValidateLimitations validate(shaderType, infoSink.info);
234 root->traverse(&validate);
235 return validate.numErrors() == 0;
236}
237
John Bauman66b8ab22014-05-06 15:57:45 -0400238const TExtensionBehavior& TCompiler::getExtensionBehavior() const
239{
240 return extensionBehavior;
241}
Nicolas Capens6407fe82015-02-10 16:27:49 -0500242
243bool InitCompilerGlobals()
244{
245 if(!InitializePoolIndex())
246 {
247 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
248 return false;
249 }
250
251 if(!InitializeParseContextIndex())
252 {
253 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
254 return false;
255 }
256
257 return true;
258}
259
260void FreeCompilerGlobals()
261{
262 FreeParseContextIndex();
263 FreePoolIndex();
Nicolas Capensb28964b2015-02-10 15:23:06 -0500264}