Move ANGLE to Sources/ThirdParty
[WebKit.git] / Sources / ThirdParty / ANGLE / src / compiler / ShaderLang.cpp
1 //
2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 //
8 // Implement the top-level of interface to the compiler,
9 // as defined in ShaderLang.h
10 //
11
12 #include "GLSLANG/ShaderLang.h"
13
14 #include "compiler/Initialize.h"
15 #include "compiler/InitializeDll.h"
16 #include "compiler/ParseHelper.h"
17 #include "compiler/ShHandle.h"
18 #include "compiler/SymbolTable.h"
19
20 static bool InitializeSymbolTable(
21         const TBuiltInStrings& builtInStrings,
22         EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
23         TInfoSink& infoSink, TSymbolTable& symbolTable)
24 {
25     TIntermediate intermediate(infoSink);
26     TParseContext parseContext(symbolTable, intermediate, language, spec, infoSink);
27
28     GlobalParseContext = &parseContext;
29
30     setInitialState();
31
32     assert(symbolTable.isEmpty());       
33     //
34     // Parse the built-ins.  This should only happen once per
35     // language symbol table.
36     //
37     // Push the symbol table to give it an initial scope.  This
38     // push should not have a corresponding pop, so that built-ins
39     // are preserved, and the test for an empty table fails.
40     //
41     symbolTable.push();
42     
43     //Initialize the Preprocessor
44     if (InitPreprocessor())
45     {
46         infoSink.info.message(EPrefixInternalError,  "Unable to intialize the Preprocessor");
47         return false;
48     }
49
50     for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
51     {
52         const char* builtInShaders[1];
53         int builtInLengths[1];
54
55         builtInShaders[0] = (*i).c_str();
56         builtInLengths[0] = (int) (*i).size();
57
58         if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0)
59         {
60             infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
61             return false;
62         }
63     }
64
65     IdentifyBuiltIns(language, spec, resources, symbolTable);
66
67     FinalizePreprocessor();
68
69     return true;
70 }
71
72 static bool GenerateBuiltInSymbolTable(
73         EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
74         TInfoSink& infoSink, TSymbolTable& symbolTable)
75 {
76     TBuiltIns builtIns;
77
78     builtIns.initialize(language, spec, resources);
79     return InitializeSymbolTable(builtIns.getBuiltInStrings(), language, spec, resources, infoSink, symbolTable);
80 }
81
82 //
83 // This is the platform independent interface between an OGL driver
84 // and the shading language compiler.
85 //
86
87 //
88 // Driver must call this first, once, before doing any other
89 // compiler operations.
90 //
91 int ShInitialize()
92 {
93     if (!InitProcess())
94         return 0;
95
96     return 1;
97 }
98
99 //
100 // Cleanup symbol tables
101 //
102 int ShFinalize()
103 {
104     if (!DetachProcess())
105         return 0;
106
107     return 1;
108 }
109
110 //
111 // Initialize built-in resources with minimum expected values.
112 //
113 void ShInitBuiltInResource(TBuiltInResource* resources)
114 {
115     // Constants.
116     resources->MaxVertexAttribs = 8;
117     resources->MaxVertexUniformVectors = 128;
118     resources->MaxVaryingVectors = 8;
119     resources->MaxVertexTextureImageUnits = 0;
120     resources->MaxCombinedTextureImageUnits = 8;
121     resources->MaxTextureImageUnits = 8;
122     resources->MaxFragmentUniformVectors = 16;
123     resources->MaxDrawBuffers = 1;
124
125     // Extensions.
126     resources->OES_standard_derivatives = 0;
127 }
128
129 //
130 // Driver calls these to create and destroy compiler objects.
131 //
132 ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
133 {
134     if (!InitThread())
135         return 0;
136
137     TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
138     TCompiler* compiler = base->getAsCompiler();
139     if (compiler == 0)
140         return 0;
141
142     // Generate built-in symbol table.
143     if (!GenerateBuiltInSymbolTable(language, spec, *resources, compiler->getInfoSink(), compiler->getSymbolTable())) {
144         ShDestruct(base);
145         return 0;
146     }
147
148     return reinterpret_cast<void*>(base);
149 }
150
151 void ShDestruct(ShHandle handle)
152 {
153     if (handle == 0)
154         return;
155
156     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
157
158     if (base->getAsCompiler())
159         DeleteCompiler(base->getAsCompiler());
160 }
161
162 //
163 // Do an actual compile on the given strings.  The result is left 
164 // in the given compile object.
165 //
166 // Return:  The return value of ShCompile is really boolean, indicating
167 // success or failure.
168 //
169 int ShCompile(
170     const ShHandle handle,
171     const char* const shaderStrings[],
172     const int numStrings,
173     const EShOptimizationLevel optLevel,
174     int debugOptions
175     )
176 {
177     if (!InitThread())
178         return 0;
179
180     if (handle == 0)
181         return 0;
182
183     TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
184     TCompiler* compiler = base->getAsCompiler();
185     if (compiler == 0)
186         return 0;
187     
188     GlobalPoolAllocator.push();
189     TInfoSink& infoSink = compiler->getInfoSink();
190     infoSink.info.erase();
191     infoSink.debug.erase();
192     infoSink.obj.erase();
193
194     if (numStrings == 0)
195         return 1;
196
197     TIntermediate intermediate(infoSink);
198     TSymbolTable& symbolTable = compiler->getSymbolTable();
199
200     TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->getSpec(), infoSink);
201     parseContext.initializeExtensionBehavior();
202     GlobalParseContext = &parseContext;
203  
204     setInitialState();
205
206     InitPreprocessor();
207     //
208     // Parse the application's shaders.  All the following symbol table
209     // work will be throw-away, so push a new allocation scope that can
210     // be thrown away, then push a scope for the current shader's globals.
211     //
212     bool success = true;
213
214     symbolTable.push();
215     if (!symbolTable.atGlobalLevel())
216         parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
217
218     int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext);
219     if (ret)
220         success = false;
221
222     if (success && parseContext.treeRoot) {
223         if (optLevel == EShOptNoGeneration)
224             parseContext.infoSink.info.message(EPrefixNone, "No errors.  No code generation was requested.");
225         else {
226             success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
227
228             if (success) {
229
230                 if (debugOptions & EDebugOpIntermediate)
231                     intermediate.outputTree(parseContext.treeRoot);
232
233                 //
234                 // Call the machine dependent compiler
235                 //
236                 if (!compiler->compile(parseContext.treeRoot))
237                     success = false;
238             }
239         }
240     } else if (!success) {
241         parseContext.infoSink.info.prefix(EPrefixError);
242         parseContext.infoSink.info << parseContext.numErrors << " compilation errors.  No code generated.\n\n";
243         success = false;
244         if (debugOptions & EDebugOpIntermediate)
245             intermediate.outputTree(parseContext.treeRoot);
246     } else if (!parseContext.treeRoot) {
247         parseContext.error(1, "Unexpected end of file.", "", "");
248         parseContext.infoSink.info << parseContext.numErrors << " compilation errors.  No code generated.\n\n";
249         success = false;
250         if (debugOptions & EDebugOpIntermediate)
251             intermediate.outputTree(parseContext.treeRoot);
252     }
253
254     intermediate.remove(parseContext.treeRoot);
255
256     //
257     // Ensure symbol table is returned to the built-in level,
258     // throwing away all but the built-ins.
259     //
260     while (!symbolTable.atBuiltInLevel())
261         symbolTable.pop();
262
263     FinalizePreprocessor();
264     //
265     // Throw away all the temporary memory used by the compilation process.
266     //
267     GlobalPoolAllocator.pop();
268
269     return success ? 1 : 0;
270 }
271
272 //
273 // Return any compiler log of messages for the application.
274 //
275 const char* ShGetInfoLog(const ShHandle handle)
276 {
277     if (!InitThread())
278         return 0;
279
280     if (handle == 0)
281         return 0;
282
283     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
284     TInfoSink* infoSink = 0;
285
286     if (base->getAsCompiler())
287         infoSink = &(base->getAsCompiler()->getInfoSink());
288
289     infoSink->info << infoSink->debug.c_str();
290     return infoSink->info.c_str();
291 }
292
293 //
294 // Return any object code.
295 //
296 const char* ShGetObjectCode(const ShHandle handle)
297 {
298     if (!InitThread())
299         return 0;
300
301     if (handle == 0)
302         return 0;
303
304     TShHandleBase* base = static_cast<TShHandleBase*>(handle);
305     TInfoSink* infoSink;
306
307     if (base->getAsCompiler())
308         infoSink = &(base->getAsCompiler()->getInfoSink());
309
310     return infoSink->obj.c_str();
311 }