blob: 5bb5865b28c9c72240d1d30c1ebf23e8883e9f63 [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
Nicolas Capens08ca3c62015-02-13 16:06:45 -050059TCompiler::TCompiler(GLenum type)
John Bauman66b8ab22014-05-06 15:57:45 -040060 : shaderType(type),
John Baumand4ae8632014-05-06 16:18:33 -040061 maxCallStackDepth(UINT_MAX)
John Bauman66b8ab22014-05-06 15:57:45 -040062{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050063 allocator.push();
64 SetGlobalPoolAllocator(&allocator);
John Bauman66b8ab22014-05-06 15:57:45 -040065}
66
67TCompiler::~TCompiler()
68{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050069 SetGlobalPoolAllocator(NULL);
70 allocator.popAll();
John Bauman66b8ab22014-05-06 15:57:45 -040071}
72
73bool TCompiler::Init(const ShBuiltInResources& resources)
74{
Nicolas Capensb28964b2015-02-10 15:23:06 -050075 shaderVersion = 100;
John Baumand4ae8632014-05-06 16:18:33 -040076 maxCallStackDepth = resources.MaxCallStackDepth;
John Bauman66b8ab22014-05-06 15:57:45 -040077 TScopedPoolAllocator scopedAlloc(&allocator, false);
78
79 // Generate built-in symbol table.
80 if (!InitBuiltInSymbolTable(resources))
81 return false;
82 InitExtensionBehavior(resources, extensionBehavior);
83
84 return true;
85}
86
87bool TCompiler::compile(const char* const shaderStrings[],
88 const int numStrings,
89 int compileOptions)
90{
91 TScopedPoolAllocator scopedAlloc(&allocator, true);
92 clearResults();
93
94 if (numStrings == 0)
95 return true;
96
John Bauman66b8ab22014-05-06 15:57:45 -040097 // First string is path of source file if flag is set. The actual source follows.
98 const char* sourcePath = NULL;
99 int firstSource = 0;
100 if (compileOptions & SH_SOURCE_PATH)
101 {
102 sourcePath = shaderStrings[0];
103 ++firstSource;
104 }
105
106 TIntermediate intermediate(infoSink);
107 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500108 shaderType, compileOptions, true,
John Bauman66b8ab22014-05-06 15:57:45 -0400109 sourcePath, infoSink);
Nicolas Capens978ddc52014-11-11 12:42:08 -0500110 SetGlobalParseContext(&parseContext);
John Bauman66b8ab22014-05-06 15:57:45 -0400111
112 // We preserve symbols at the built-in level from compile-to-compile.
113 // Start pushing the user-defined symbols at global level.
114 symbolTable.push();
115 if (!symbolTable.atGlobalLevel())
116 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
117
118 // Parse shader.
119 bool success =
120 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
121 (parseContext.treeRoot != NULL);
Nicolas Capensb28964b2015-02-10 15:23:06 -0500122
Nicolas Capensc6841852015-02-15 14:25:37 -0500123 shaderVersion = parseContext.getShaderVersion();
Nicolas Capensb28964b2015-02-10 15:23:06 -0500124
John Bauman66b8ab22014-05-06 15:57:45 -0400125 if (success) {
126 TIntermNode* root = parseContext.treeRoot;
127 success = intermediate.postProcess(root);
128
129 if (success)
John Baumand4ae8632014-05-06 16:18:33 -0400130 success = validateCallDepth(root, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400131
132 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
133 success = validateLimitations(root);
134
John Bauman66b8ab22014-05-06 15:57:45 -0400135 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
136 intermediate.outputTree(root);
137
138 if (success && (compileOptions & SH_OBJECT_CODE))
Nicolas Capens014b9a62014-10-15 10:28:29 -0400139 success = translate(root);
John Bauman66b8ab22014-05-06 15:57:45 -0400140 }
141
John Bauman66b8ab22014-05-06 15:57:45 -0400142 // Ensure symbol table is returned to the built-in level,
143 // throwing away all but the built-ins.
144 while (!symbolTable.atBuiltInLevel())
145 symbolTable.pop();
146
147 return success;
148}
149
John Baumand4ae8632014-05-06 16:18:33 -0400150bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
John Bauman66b8ab22014-05-06 15:57:45 -0400151{
John Baumand4ae8632014-05-06 16:18:33 -0400152 assert(symbolTable.isEmpty());
Nicolas Capens3d7f6ed2015-02-18 16:34:50 -0500153 symbolTable.push(); // COMMON_BUILTINS
154 symbolTable.push(); // ESSL1_BUILTINS
155 symbolTable.push(); // ESSL3_BUILTINS
John Bauman66b8ab22014-05-06 15:57:45 -0400156
John Baumand4ae8632014-05-06 16:18:33 -0400157 TPublicType integer;
158 integer.type = EbtInt;
Alexis Hetub14178b2015-04-13 13:23:20 -0400159 integer.primarySize = 1;
160 integer.secondarySize = 1;
John Baumand4ae8632014-05-06 16:18:33 -0400161 integer.array = false;
162
163 TPublicType floatingPoint;
164 floatingPoint.type = EbtFloat;
Alexis Hetub14178b2015-04-13 13:23:20 -0400165 floatingPoint.primarySize = 1;
166 floatingPoint.secondarySize = 1;
John Baumand4ae8632014-05-06 16:18:33 -0400167 floatingPoint.array = false;
168
169 switch(shaderType)
170 {
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500171 case GL_FRAGMENT_SHADER:
John Baumand4ae8632014-05-06 16:18:33 -0400172 symbolTable.setDefaultPrecision(integer, EbpMedium);
173 break;
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500174 case GL_VERTEX_SHADER:
John Baumand4ae8632014-05-06 16:18:33 -0400175 symbolTable.setDefaultPrecision(integer, EbpHigh);
176 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
177 break;
178 default: assert(false && "Language not supported");
179 }
180
181 InsertBuiltInFunctions(shaderType, resources, symbolTable);
182
Nicolas Capens08ca3c62015-02-13 16:06:45 -0500183 IdentifyBuiltIns(shaderType, resources, symbolTable);
John Baumand4ae8632014-05-06 16:18:33 -0400184
185 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400186}
187
188void TCompiler::clearResults()
189{
190 infoSink.info.erase();
191 infoSink.obj.erase();
192 infoSink.debug.erase();
John Bauman66b8ab22014-05-06 15:57:45 -0400193}
194
John Baumand4ae8632014-05-06 16:18:33 -0400195bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
John Bauman66b8ab22014-05-06 15:57:45 -0400196{
John Baumand4ae8632014-05-06 16:18:33 -0400197 AnalyzeCallDepth validator(root);
198
199 unsigned int depth = validator.analyzeCallDepth();
200
201 if(depth == 0)
202 {
203 infoSink.info.prefix(EPrefixError);
204 infoSink.info << "Missing main()";
205 return false;
206 }
207 else if(depth == UINT_MAX)
208 {
209 infoSink.info.prefix(EPrefixError);
210 infoSink.info << "Function recursion detected";
211 return false;
212 }
213 else if(depth > maxCallStackDepth)
214 {
215 infoSink.info.prefix(EPrefixError);
216 infoSink.info << "Function call stack too deep";
217 return false;
218 }
219
220 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400221}
222
223bool TCompiler::validateLimitations(TIntermNode* root) {
224 ValidateLimitations validate(shaderType, infoSink.info);
225 root->traverse(&validate);
226 return validate.numErrors() == 0;
227}
228
John Bauman66b8ab22014-05-06 15:57:45 -0400229const TExtensionBehavior& TCompiler::getExtensionBehavior() const
230{
231 return extensionBehavior;
232}
Nicolas Capens6407fe82015-02-10 16:27:49 -0500233
234bool InitCompilerGlobals()
235{
236 if(!InitializePoolIndex())
237 {
238 assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
239 return false;
240 }
241
242 if(!InitializeParseContextIndex())
243 {
244 assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
245 return false;
246 }
247
248 return true;
249}
250
251void FreeCompilerGlobals()
252{
253 FreeParseContextIndex();
254 FreePoolIndex();
Nicolas Capensb28964b2015-02-10 15:23:06 -0500255}