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
70 MaxCallStackDepth = UINT_MAX;
71 }
72
TCompiler(GLenum type)73 TCompiler::TCompiler(GLenum type)
74 : shaderType(type),
75 maxCallStackDepth(UINT_MAX)
76 {
77 allocator.push();
78 SetGlobalPoolAllocator(&allocator);
79 }
80
~TCompiler()81 TCompiler::~TCompiler()
82 {
83 SetGlobalPoolAllocator(nullptr);
84 allocator.popAll();
85 }
86
Init(const ShBuiltInResources & resources)87 bool TCompiler::Init(const ShBuiltInResources& resources)
88 {
89 shaderVersion = 100;
90 maxCallStackDepth = resources.MaxCallStackDepth;
91 TScopedPoolAllocator scopedAlloc(&allocator, false);
92
93 // Generate built-in symbol table.
94 if (!InitBuiltInSymbolTable(resources))
95 return false;
96 InitExtensionBehavior(resources, extensionBehavior);
97
98 return true;
99 }
100
compile(const char * const shaderStrings[],const int numStrings,int compileOptions)101 bool TCompiler::compile(const char* const shaderStrings[],
102 const int numStrings,
103 int compileOptions)
104 {
105 TScopedPoolAllocator scopedAlloc(&allocator, true);
106 clearResults();
107
108 if (numStrings == 0)
109 return true;
110
111 // First string is path of source file if flag is set. The actual source follows.
112 const char* sourcePath = nullptr;
113 int firstSource = 0;
114 if (compileOptions & SH_SOURCE_PATH)
115 {
116 sourcePath = shaderStrings[0];
117 ++firstSource;
118 }
119
120 TIntermediate intermediate(infoSink);
121 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
122 shaderType, compileOptions, true,
123 sourcePath, infoSink);
124 SetGlobalParseContext(&parseContext);
125
126 // We preserve symbols at the built-in level from compile-to-compile.
127 // Start pushing the user-defined symbols at global level.
128 symbolTable.push();
129 if (!symbolTable.atGlobalLevel())
130 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
131
132 // Parse shader.
133 bool success =
134 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
135 (parseContext.getTreeRoot() != nullptr);
136
137 shaderVersion = parseContext.getShaderVersion();
138
139 if (success) {
140 TIntermNode* root = parseContext.getTreeRoot();
141 success = intermediate.postProcess(root);
142
143 if (success)
144 success = validateCallDepth(root, infoSink);
145
146 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
147 success = validateLimitations(root);
148
149 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
150 intermediate.outputTree(root);
151
152 if (success && (compileOptions & SH_OBJECT_CODE))
153 success = translate(root);
154 }
155
156 // Ensure symbol table is returned to the built-in level,
157 // throwing away all but the built-ins.
158 while (!symbolTable.atBuiltInLevel())
159 symbolTable.pop();
160
161 return success;
162 }
163
InitBuiltInSymbolTable(const ShBuiltInResources & resources)164 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
165 {
166 assert(symbolTable.isEmpty());
167 symbolTable.push(); // COMMON_BUILTINS
168 symbolTable.push(); // ESSL1_BUILTINS
169 symbolTable.push(); // ESSL3_BUILTINS
170
171 TPublicType integer;
172 integer.type = EbtInt;
173 integer.primarySize = 1;
174 integer.secondarySize = 1;
175 integer.array = false;
176
177 TPublicType floatingPoint;
178 floatingPoint.type = EbtFloat;
179 floatingPoint.primarySize = 1;
180 floatingPoint.secondarySize = 1;
181 floatingPoint.array = false;
182
183 switch(shaderType)
184 {
185 case GL_FRAGMENT_SHADER:
186 symbolTable.setDefaultPrecision(integer, EbpMedium);
187 break;
188 case GL_VERTEX_SHADER:
189 symbolTable.setDefaultPrecision(integer, EbpHigh);
190 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
191 break;
192 default: assert(false && "Language not supported");
193 }
194
195 InsertBuiltInFunctions(shaderType, resources, symbolTable);
196
197 IdentifyBuiltIns(shaderType, resources, symbolTable);
198
199 return true;
200 }
201
clearResults()202 void TCompiler::clearResults()
203 {
204 infoSink.info.erase();
205 infoSink.obj.erase();
206 infoSink.debug.erase();
207 }
208
validateCallDepth(TIntermNode * root,TInfoSink & infoSink)209 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
210 {
211 AnalyzeCallDepth validator(root);
212
213 unsigned int depth = validator.analyzeCallDepth();
214
215 if(depth == 0)
216 {
217 infoSink.info.prefix(EPrefixError);
218 infoSink.info << "Missing main()";
219 return false;
220 }
221 else if(depth == UINT_MAX)
222 {
223 infoSink.info.prefix(EPrefixError);
224 infoSink.info << "Function recursion detected";
225 return false;
226 }
227 else if(depth > maxCallStackDepth)
228 {
229 infoSink.info.prefix(EPrefixError);
230 infoSink.info << "Function call stack too deep";
231 return false;
232 }
233
234 return true;
235 }
236
validateLimitations(TIntermNode * root)237 bool TCompiler::validateLimitations(TIntermNode* root) {
238 ValidateLimitations validate(shaderType, infoSink.info);
239 root->traverse(&validate);
240 return validate.numErrors() == 0;
241 }
242
getExtensionBehavior() const243 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
244 {
245 return extensionBehavior;
246 }
247
InitCompilerGlobals()248 bool InitCompilerGlobals()
249 {
250 if(!InitializePoolIndex())
251 {
252 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
253 return false;
254 }
255
256 if(!InitializeParseContextIndex())
257 {
258 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
259 return false;
260 }
261
262 return true;
263 }
264
FreeCompilerGlobals()265 void FreeCompilerGlobals()
266 {
267 FreeParseContextIndex();
268 FreePoolIndex();
269 }
270