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
24namespace
25{
26class TScopedPoolAllocator {
27public:
28 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
29 : mAllocator(allocator), mPushPopAllocator(pushPop)
30 {
31 if (mPushPopAllocator) mAllocator->push();
32 SetGlobalPoolAllocator(mAllocator);
33 }
34 ~TScopedPoolAllocator()
35 {
36 SetGlobalPoolAllocator(nullptr);
37 if (mPushPopAllocator) mAllocator->pop();
38 }
39
40private:
41 TPoolAllocator* mAllocator;
42 bool mPushPopAllocator;
43};
44} // namespace
45
46//
47// Initialize built-in resources with minimum expected values.
48//
49ShBuiltInResources::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
74TCompiler::TCompiler(GLenum type)
75 : shaderType(type),
76 maxCallStackDepth(UINT_MAX)
77{
78 allocator.push();
79 SetGlobalPoolAllocator(&allocator);
80}
81
82TCompiler::~TCompiler()
83{
84 SetGlobalPoolAllocator(nullptr);
85 allocator.popAll();
86}
87
88bool 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
102bool 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
165bool 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
203void TCompiler::clearResults()
204{
205 infoSink.info.erase();
206 infoSink.obj.erase();
207 infoSink.debug.erase();
208}
209
210bool 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
242bool TCompiler::validateLimitations(TIntermNode* root) {
243 ValidateLimitations validate(shaderType, infoSink.info);
244 root->traverse(&validate);
245 return validate.numErrors() == 0;
246}
247
248const TExtensionBehavior& TCompiler::getExtensionBehavior() const
249{
250 return extensionBehavior;
251}
252
253bool 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
270void FreeCompilerGlobals()
271{
272 FreeParseContextIndex();
273 FreePoolIndex();
274}
275