blob: cbb04f54238e724e4f743bbd1f3fcd7bfb9e6537 [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;
Alexis Hetu6743bbf2015-04-21 17:06:14 -040050 MaxVertexOutputVectors = 16;
51 MaxFragmentInputVectors = 15;
52 MinProgramTexelOffset = -8;
53 MaxProgramTexelOffset = 7;
Nicolas Capens6407fe82015-02-10 16:27:49 -050054
55 // Extensions.
56 OES_standard_derivatives = 0;
57 OES_fragment_precision_high = 0;
58 OES_EGL_image_external = 0;
59
60 MaxCallStackDepth = UINT_MAX;
61}
62
Nicolas Capens08ca3c62015-02-13 16:06:45 -050063TCompiler::TCompiler(GLenum type)
John Bauman66b8ab22014-05-06 15:57:45 -040064 : shaderType(type),
John Baumand4ae8632014-05-06 16:18:33 -040065 maxCallStackDepth(UINT_MAX)
John Bauman66b8ab22014-05-06 15:57:45 -040066{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050067 allocator.push();
68 SetGlobalPoolAllocator(&allocator);
John Bauman66b8ab22014-05-06 15:57:45 -040069}
70
71TCompiler::~TCompiler()
72{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050073 SetGlobalPoolAllocator(NULL);
74 allocator.popAll();
John Bauman66b8ab22014-05-06 15:57:45 -040075}
76
77bool TCompiler::Init(const ShBuiltInResources& resources)
78{
Nicolas Capensb28964b2015-02-10 15:23:06 -050079 shaderVersion = 100;
John Baumand4ae8632014-05-06 16:18:33 -040080 maxCallStackDepth = resources.MaxCallStackDepth;
John Bauman66b8ab22014-05-06 15:57:45 -040081 TScopedPoolAllocator scopedAlloc(&allocator, false);
82
83 // Generate built-in symbol table.
84 if (!InitBuiltInSymbolTable(resources))
85 return false;
86 InitExtensionBehavior(resources, extensionBehavior);
87
88 return true;
89}
90
91bool TCompiler::compile(const char* const shaderStrings[],
92 const int numStrings,
93 int compileOptions)
94{
95 TScopedPoolAllocator scopedAlloc(&allocator, true);
96 clearResults();
97
98 if (numStrings == 0)
99 return true;
100
John Bauman66b8ab22014-05-06 15:57:45 -0400101 // First string is path of source file if flag is set. The actual source follows.
102 const char* sourcePath = NULL;
103 int firstSource = 0;
104 if (compileOptions & SH_SOURCE_PATH)
105 {
106 sourcePath = shaderStrings[0];
107 ++firstSource;
108 }
109
110 TIntermediate intermediate(infoSink);
111 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500112 shaderType, compileOptions, true,
John Bauman66b8ab22014-05-06 15:57:45 -0400113 sourcePath, infoSink);
Nicolas Capens978ddc52014-11-11 12:42:08 -0500114 SetGlobalParseContext(&parseContext);
John Bauman66b8ab22014-05-06 15:57:45 -0400115
116 // We preserve symbols at the built-in level from compile-to-compile.
117 // Start pushing the user-defined symbols at global level.
118 symbolTable.push();
119 if (!symbolTable.atGlobalLevel())
120 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
121
122 // Parse shader.
123 bool success =
124 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
Alexis Hetu0a655842015-06-22 16:52:11 -0400125 (parseContext.getTreeRoot() != NULL);
Nicolas Capensb28964b2015-02-10 15:23:06 -0500126
Nicolas Capensc6841852015-02-15 14:25:37 -0500127 shaderVersion = parseContext.getShaderVersion();
Nicolas Capensb28964b2015-02-10 15:23:06 -0500128
John Bauman66b8ab22014-05-06 15:57:45 -0400129 if (success) {
Alexis Hetu0a655842015-06-22 16:52:11 -0400130 TIntermNode* root = parseContext.getTreeRoot();
John Bauman66b8ab22014-05-06 15:57:45 -0400131 success = intermediate.postProcess(root);
132
133 if (success)
John Baumand4ae8632014-05-06 16:18:33 -0400134 success = validateCallDepth(root, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400135
136 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
137 success = validateLimitations(root);
138
John Bauman66b8ab22014-05-06 15:57:45 -0400139 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
140 intermediate.outputTree(root);
141
142 if (success && (compileOptions & SH_OBJECT_CODE))
Nicolas Capens014b9a62014-10-15 10:28:29 -0400143 success = translate(root);
John Bauman66b8ab22014-05-06 15:57:45 -0400144 }
145
John Bauman66b8ab22014-05-06 15:57:45 -0400146 // Ensure symbol table is returned to the built-in level,
147 // throwing away all but the built-ins.
148 while (!symbolTable.atBuiltInLevel())
149 symbolTable.pop();
150
151 return success;
152}
153
John Baumand4ae8632014-05-06 16:18:33 -0400154bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
John Bauman66b8ab22014-05-06 15:57:45 -0400155{
John Baumand4ae8632014-05-06 16:18:33 -0400156 assert(symbolTable.isEmpty());
Nicolas Capens3d7f6ed2015-02-18 16:34:50 -0500157 symbolTable.push(); // COMMON_BUILTINS
158 symbolTable.push(); // ESSL1_BUILTINS
159 symbolTable.push(); // ESSL3_BUILTINS
John Bauman66b8ab22014-05-06 15:57:45 -0400160
John Baumand4ae8632014-05-06 16:18:33 -0400161 TPublicType integer;
162 integer.type = EbtInt;
Alexis Hetub14178b2015-04-13 13:23:20 -0400163 integer.primarySize = 1;
164 integer.secondarySize = 1;
John Baumand4ae8632014-05-06 16:18:33 -0400165 integer.array = false;
166
167 TPublicType floatingPoint;
168 floatingPoint.type = EbtFloat;
Alexis Hetub14178b2015-04-13 13:23:20 -0400169 floatingPoint.primarySize = 1;
170 floatingPoint.secondarySize = 1;
John Baumand4ae8632014-05-06 16:18:33 -0400171 floatingPoint.array = false;
172
173 switch(shaderType)
174 {
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500175 case GL_FRAGMENT_SHADER:
John Baumand4ae8632014-05-06 16:18:33 -0400176 symbolTable.setDefaultPrecision(integer, EbpMedium);
177 break;
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500178 case GL_VERTEX_SHADER:
John Baumand4ae8632014-05-06 16:18:33 -0400179 symbolTable.setDefaultPrecision(integer, EbpHigh);
180 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
181 break;
182 default: assert(false && "Language not supported");
183 }
184
185 InsertBuiltInFunctions(shaderType, resources, symbolTable);
186
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500187 IdentifyBuiltIns(shaderType, resources, symbolTable);
John Baumand4ae8632014-05-06 16:18:33 -0400188
189 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400190}
191
192void TCompiler::clearResults()
193{
194 infoSink.info.erase();
195 infoSink.obj.erase();
196 infoSink.debug.erase();
John Bauman66b8ab22014-05-06 15:57:45 -0400197}
198
John Baumand4ae8632014-05-06 16:18:33 -0400199bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
John Bauman66b8ab22014-05-06 15:57:45 -0400200{
John Baumand4ae8632014-05-06 16:18:33 -0400201 AnalyzeCallDepth validator(root);
202
203 unsigned int depth = validator.analyzeCallDepth();
204
205 if(depth == 0)
206 {
207 infoSink.info.prefix(EPrefixError);
208 infoSink.info << "Missing main()";
209 return false;
210 }
211 else if(depth == UINT_MAX)
212 {
213 infoSink.info.prefix(EPrefixError);
214 infoSink.info << "Function recursion detected";
215 return false;
216 }
217 else if(depth > maxCallStackDepth)
218 {
219 infoSink.info.prefix(EPrefixError);
220 infoSink.info << "Function call stack too deep";
221 return false;
222 }
223
224 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400225}
226
227bool TCompiler::validateLimitations(TIntermNode* root) {
228 ValidateLimitations validate(shaderType, infoSink.info);
229 root->traverse(&validate);
230 return validate.numErrors() == 0;
231}
232
John Bauman66b8ab22014-05-06 15:57:45 -0400233const TExtensionBehavior& TCompiler::getExtensionBehavior() const
234{
235 return extensionBehavior;
236}
Nicolas Capens6407fe82015-02-10 16:27:49 -0500237
238bool InitCompilerGlobals()
239{
240 if(!InitializePoolIndex())
241 {
242 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
243 return false;
244 }
245
246 if(!InitializeParseContextIndex())
247 {
248 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
249 return false;
250 }
251
252 return true;
253}
254
255void FreeCompilerGlobals()
256{
257 FreeParseContextIndex();
258 FreePoolIndex();
Nicolas Capensb28964b2015-02-10 15:23:06 -0500259}