1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Compiler.h"
16
17 #include "AnalyzeCallDepth.h"
18 #include "Initialize.h"
19 #include "InitializeParseContext.h"
20 #include "InitializeGlobals.h"
21 #include "ParseHelper.h"
22 #include "ValidateLimitations.h"
23
24 namespace
25 {
26 class TScopedPoolAllocator {
27 public:
TScopedPoolAllocator(TPoolAllocator * allocator,bool pushPop)28 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
29 : mAllocator(allocator), mPushPopAllocator(pushPop)
30 {
31 if (mPushPopAllocator) mAllocator->push();
32 SetGlobalPoolAllocator(mAllocator);
33 }
~TScopedPoolAllocator()34 ~TScopedPoolAllocator()
35 {
36 SetGlobalPoolAllocator(nullptr);
37 if (mPushPopAllocator) mAllocator->pop();
38 }
39
40 private:
41 TPoolAllocator* mAllocator;
42 bool mPushPopAllocator;
43 };
44 } // namespace
45
46 //
47 // Initialize built-in resources with minimum expected values.
48 //
ShBuiltInResources()49 ShBuiltInResources::ShBuiltInResources()
50 {
51 // Constants.
52 MaxVertexAttribs = 8;
53 MaxVertexUniformVectors = 128;
54 MaxVaryingVectors = 8;
55 MaxVertexTextureImageUnits = 0;
56 MaxCombinedTextureImageUnits = 8;
57 MaxTextureImageUnits = 8;
58 MaxFragmentUniformVectors = 16;
59 MaxDrawBuffers = 1;
60 MaxVertexOutputVectors = 16;
61 MaxFragmentInputVectors = 15;
62 MinProgramTexelOffset = -8;
63 MaxProgramTexelOffset = 7;
64
65 // Extensions.
66 OES_standard_derivatives = 0;
67 OES_fragment_precision_high = 0;
68 OES_EGL_image_external = 0;
69 OES_EGL_image_external_essl3 = 0;
70
71 MaxCallStackDepth = UINT_MAX;
72 }
73
TCompiler(GLenum type)74 TCompiler::TCompiler(GLenum type)
75 : shaderType(type),
76 maxCallStackDepth(UINT_MAX)
77 {
78 allocator.push();
79 SetGlobalPoolAllocator(&allocator);
80 }
81
~TCompiler()82 TCompiler::~TCompiler()
83 {
84 SetGlobalPoolAllocator(nullptr);
85 allocator.popAll();
86 }
87
Init(const ShBuiltInResources & resources)88 bool TCompiler::Init(const ShBuiltInResources& resources)
89 {
90 shaderVersion = 100;
91 maxCallStackDepth = resources.MaxCallStackDepth;
92 TScopedPoolAllocator scopedAlloc(&allocator, false);
93
94 // Generate built-in symbol table.
95 if (!InitBuiltInSymbolTable(resources))
96 return false;
97 InitExtensionBehavior(resources, extensionBehavior);
98
99 return true;
100 }
101
compile(const char * const shaderStrings[],const int numStrings,int compileOptions)102 bool TCompiler::compile(const char* const shaderStrings[],
103 const int numStrings,
104 int compileOptions)
105 {
106 TScopedPoolAllocator scopedAlloc(&allocator, true);
107 clearResults();
108
109 if (numStrings == 0)
110 return true;
111
112 // First string is path of source file if flag is set. The actual source follows.
113 const char* sourcePath = nullptr;
114 int firstSource = 0;
115 if (compileOptions & SH_SOURCE_PATH)
116 {
117 sourcePath = shaderStrings[0];
118 ++firstSource;
119 }
120
121 TIntermediate intermediate(infoSink);
122 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
123 shaderType, compileOptions, true,
124 sourcePath, infoSink);
125 SetGlobalParseContext(&parseContext);
126
127 // We preserve symbols at the built-in level from compile-to-compile.
128 // Start pushing the user-defined symbols at global level.
129 symbolTable.push();
130 if (!symbolTable.atGlobalLevel())
131 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
132
133 // Parse shader.
134 bool success =
135 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
136 (parseContext.getTreeRoot() != nullptr);
137
138 shaderVersion = parseContext.getShaderVersion();
139
140 if (success) {
141 TIntermNode* root = parseContext.getTreeRoot();
142 success = intermediate.postProcess(root);
143
144 if (success)
145 success = validateCallDepth(root, infoSink);
146
147 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
148 success = validateLimitations(root);
149
150 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
151 intermediate.outputTree(root);
152
153 if (success && (compileOptions & SH_OBJECT_CODE))
154 success = translate(root);
155 }
156
157 // Ensure symbol table is returned to the built-in level,
158 // throwing away all but the built-ins.
159 while (!symbolTable.atBuiltInLevel())
160 symbolTable.pop();
161
162 return success;
163 }
164
InitBuiltInSymbolTable(const ShBuiltInResources & resources)165 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
166 {
167 assert(symbolTable.isEmpty());
168 symbolTable.push(); // COMMON_BUILTINS
169 symbolTable.push(); // ESSL1_BUILTINS
170 symbolTable.push(); // ESSL3_BUILTINS
171
172 TPublicType integer;
173 integer.type = EbtInt;
174 integer.primarySize = 1;
175 integer.secondarySize = 1;
176 integer.array = false;
177
178 TPublicType floatingPoint;
179 floatingPoint.type = EbtFloat;
180 floatingPoint.primarySize = 1;
181 floatingPoint.secondarySize = 1;
182 floatingPoint.array = false;
183
184 switch(shaderType)
185 {
186 case GL_FRAGMENT_SHADER:
187 symbolTable.setDefaultPrecision(integer, EbpMedium);
188 break;
189 case GL_VERTEX_SHADER:
190 symbolTable.setDefaultPrecision(integer, EbpHigh);
191 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
192 break;
193 default: assert(false && "Language not supported");
194 }
195
196 InsertBuiltInFunctions(shaderType, resources, symbolTable);
197
198 IdentifyBuiltIns(shaderType, resources, symbolTable);
199
200 return true;
201 }
202
clearResults()203 void TCompiler::clearResults()
204 {
205 infoSink.info.erase();
206 infoSink.obj.erase();
207 infoSink.debug.erase();
208 }
209
validateCallDepth(TIntermNode * root,TInfoSink & infoSink)210 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
211 {
212 AnalyzeCallDepth validator(root);
213
214 unsigned int depth = validator.analyzeCallDepth();
215
216 if(depth == 0)
217 {
218 infoSink.info.prefix(EPrefixError);
219 infoSink.info << "Missing main()";
220 return false;
221 }
222 else if(depth == UINT_MAX)
223 {
224 infoSink.info.prefix(EPrefixError);
225 infoSink.info << "Function recursion detected";
226 return false;
227 }
228 else if(depth > maxCallStackDepth)
229 {
230 infoSink.info.prefix(EPrefixError);
231 infoSink.info << "Function call stack too deep (depth was ";
232 infoSink.info << depth;
233 infoSink.info << " while maximum call stack depth is ";
234 infoSink.info << maxCallStackDepth;
235 infoSink.info << ")";
236 return false;
237 }
238
239 return true;
240 }
241
validateLimitations(TIntermNode * root)242 bool TCompiler::validateLimitations(TIntermNode* root) {
243 ValidateLimitations validate(shaderType, infoSink.info);
244 root->traverse(&validate);
245 return validate.numErrors() == 0;
246 }
247
getExtensionBehavior() const248 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
249 {
250 return extensionBehavior;
251 }
252
InitCompilerGlobals()253 bool InitCompilerGlobals()
254 {
255 if(!InitializePoolIndex())
256 {
257 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
258 return false;
259 }
260
261 if(!InitializeParseContextIndex())
262 {
263 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
264 return false;
265 }
266
267 return true;
268 }
269
FreeCompilerGlobals()270 void FreeCompilerGlobals()
271 {
272 FreeParseContextIndex();
273 FreePoolIndex();
274 }
275