blob: de213d89d2fea6543f70db3047a67fa8b857d781 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
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//
alokp@chromium.org774d7062010-07-21 18:55:45 +00008// Implement the top-level of interface to the compiler,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009// as defined in ShaderLang.h
10//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "GLSLANG/ShaderLang.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "compiler/Initialize.h"
15#include "compiler/InitializeDll.h"
16#include "compiler/ParseHelper.h"
17#include "compiler/ShHandle.h"
18#include "compiler/SymbolTable.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019
alokp@chromium.orge4249f02010-07-26 18:13:52 +000020static bool InitializeSymbolTable(
21 const TBuiltInStrings& builtInStrings,
22 EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
23 TInfoSink& infoSink, TSymbolTable& symbolTable)
24{
25 TIntermediate intermediate(infoSink);
alokp@chromium.orgad771eb2010-09-07 17:36:23 +000026 TExtensionBehavior extBehavior;
27 TParseContext parseContext(symbolTable, extBehavior, intermediate, language, spec, infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028
alokp@chromium.orge4249f02010-07-26 18:13:52 +000029 GlobalParseContext = &parseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000030
alokp@chromium.orge4249f02010-07-26 18:13:52 +000031 setInitialState();
32
33 assert(symbolTable.isEmpty());
34 //
35 // Parse the built-ins. This should only happen once per
36 // language symbol table.
37 //
38 // Push the symbol table to give it an initial scope. This
39 // push should not have a corresponding pop, so that built-ins
40 // are preserved, and the test for an empty table fails.
41 //
42 symbolTable.push();
43
44 //Initialize the Preprocessor
45 if (InitPreprocessor())
46 {
47 infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor");
48 return false;
49 }
50
51 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
52 {
53 const char* builtInShaders[1];
54 int builtInLengths[1];
55
56 builtInShaders[0] = (*i).c_str();
57 builtInLengths[0] = (int) (*i).size();
58
59 if (PaParseStrings(const_cast<char**>(builtInShaders), builtInLengths, 1, parseContext) != 0)
60 {
61 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
62 return false;
63 }
64 }
65
66 IdentifyBuiltIns(language, spec, resources, symbolTable);
67
68 FinalizePreprocessor();
69
70 return true;
71}
72
73static bool GenerateBuiltInSymbolTable(
74 EShLanguage language, EShSpec spec, const TBuiltInResource& resources,
75 TInfoSink& infoSink, TSymbolTable& symbolTable)
76{
77 TBuiltIns builtIns;
78
79 builtIns.initialize(language, spec, resources);
80 return InitializeSymbolTable(builtIns.getBuiltInStrings(), language, spec, resources, infoSink, symbolTable);
81}
82
alokp@chromium.orgad771eb2010-09-07 17:36:23 +000083static void DefineExtensionMacros(const TExtensionBehavior& extBehavior)
84{
85 for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
86 iter != extBehavior.end(); ++iter) {
87 PredefineIntMacro(iter->first.c_str(), 1);
88 }
89}
90
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000091//
92// This is the platform independent interface between an OGL driver
alokp@chromium.org774d7062010-07-21 18:55:45 +000093// and the shading language compiler.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094//
95
96//
97// Driver must call this first, once, before doing any other
alokp@chromium.org774d7062010-07-21 18:55:45 +000098// compiler operations.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099//
100int ShInitialize()
101{
alokp@chromium.org34b99cd2010-07-27 18:37:55 +0000102 if (!InitProcess())
103 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104
alokp@chromium.org34b99cd2010-07-27 18:37:55 +0000105 return 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000106}
107
108//
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000109// Cleanup symbol tables
110//
111int ShFinalize()
112{
113 if (!DetachProcess())
114 return 0;
115
116 return 1;
117}
118
119//
120// Initialize built-in resources with minimum expected values.
121//
122void ShInitBuiltInResource(TBuiltInResource* resources)
123{
124 // Constants.
125 resources->MaxVertexAttribs = 8;
126 resources->MaxVertexUniformVectors = 128;
127 resources->MaxVaryingVectors = 8;
128 resources->MaxVertexTextureImageUnits = 0;
129 resources->MaxCombinedTextureImageUnits = 8;
130 resources->MaxTextureImageUnits = 8;
131 resources->MaxFragmentUniformVectors = 16;
132 resources->MaxDrawBuffers = 1;
133
134 // Extensions.
135 resources->OES_standard_derivatives = 0;
136}
137
138//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000139// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140//
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000141ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142{
143 if (!InitThread())
144 return 0;
145
alokp@chromium.org29cd91a2010-07-16 19:30:45 +0000146 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000147 TCompiler* compiler = base->getAsCompiler();
148 if (compiler == 0)
149 return 0;
150
151 // Generate built-in symbol table.
152 if (!GenerateBuiltInSymbolTable(language, spec, *resources, compiler->getInfoSink(), compiler->getSymbolTable())) {
153 ShDestruct(base);
154 return 0;
155 }
alokp@chromium.orgad771eb2010-09-07 17:36:23 +0000156 InitExtensionBehavior(*resources, compiler->getExtensionBehavior());
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000157
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158 return reinterpret_cast<void*>(base);
159}
160
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161void ShDestruct(ShHandle handle)
162{
163 if (handle == 0)
164 return;
165
166 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
167
168 if (base->getAsCompiler())
169 DeleteCompiler(base->getAsCompiler());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000170}
171
172//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173// Do an actual compile on the given strings. The result is left
174// in the given compile object.
175//
176// Return: The return value of ShCompile is really boolean, indicating
177// success or failure.
178//
179int ShCompile(
180 const ShHandle handle,
181 const char* const shaderStrings[],
182 const int numStrings,
183 const EShOptimizationLevel optLevel,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184 int debugOptions
185 )
186{
187 if (!InitThread())
188 return 0;
189
190 if (handle == 0)
191 return 0;
192
193 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
194 TCompiler* compiler = base->getAsCompiler();
195 if (compiler == 0)
196 return 0;
197
198 GlobalPoolAllocator.push();
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000199 TInfoSink& infoSink = compiler->getInfoSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000200 infoSink.info.erase();
201 infoSink.debug.erase();
202 infoSink.obj.erase();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203
204 if (numStrings == 0)
205 return 1;
206
alokp@chromium.org76b82082010-03-24 17:59:39 +0000207 TIntermediate intermediate(infoSink);
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000208 TSymbolTable& symbolTable = compiler->getSymbolTable();
alokp@chromium.orgad771eb2010-09-07 17:36:23 +0000209 const TExtensionBehavior& extBehavior = compiler->getExtensionBehavior();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210
alokp@chromium.orgad771eb2010-09-07 17:36:23 +0000211 TParseContext parseContext(symbolTable, extBehavior, intermediate,
212 compiler->getLanguage(), compiler->getSpec(), infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213 GlobalParseContext = &parseContext;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000214
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 setInitialState();
216
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000217 InitPreprocessor();
alokp@chromium.orgad771eb2010-09-07 17:36:23 +0000218 DefineExtensionMacros(extBehavior);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219 //
220 // Parse the application's shaders. All the following symbol table
221 // work will be throw-away, so push a new allocation scope that can
222 // be thrown away, then push a scope for the current shader's globals.
223 //
224 bool success = true;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000225
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000226 symbolTable.push();
227 if (!symbolTable.atGlobalLevel())
228 parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
229
230 int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext);
231 if (ret)
232 success = false;
233
234 if (success && parseContext.treeRoot) {
235 if (optLevel == EShOptNoGeneration)
alokp@chromium.org774d7062010-07-21 18:55:45 +0000236 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation was requested.");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000237 else {
238 success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
239
240 if (success) {
241
242 if (debugOptions & EDebugOpIntermediate)
243 intermediate.outputTree(parseContext.treeRoot);
244
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000245 //
246 // Call the machine dependent compiler
247 //
alokp@chromium.org76b82082010-03-24 17:59:39 +0000248 if (!compiler->compile(parseContext.treeRoot))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249 success = false;
250 }
251 }
252 } else if (!success) {
253 parseContext.infoSink.info.prefix(EPrefixError);
254 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
255 success = false;
256 if (debugOptions & EDebugOpIntermediate)
257 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.combb2e9632010-04-13 19:53:50 +0000258 } else if (!parseContext.treeRoot) {
259 parseContext.error(1, "Unexpected end of file.", "", "");
260 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
261 success = false;
262 if (debugOptions & EDebugOpIntermediate)
263 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264 }
265
266 intermediate.remove(parseContext.treeRoot);
267
268 //
269 // Ensure symbol table is returned to the built-in level,
270 // throwing away all but the built-ins.
271 //
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000272 while (!symbolTable.atBuiltInLevel())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273 symbolTable.pop();
274
275 FinalizePreprocessor();
276 //
277 // Throw away all the temporary memory used by the compilation process.
278 //
279 GlobalPoolAllocator.pop();
280
281 return success ? 1 : 0;
282}
283
284//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000285// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000286//
287const char* ShGetInfoLog(const ShHandle handle)
288{
289 if (!InitThread())
290 return 0;
291
292 if (handle == 0)
293 return 0;
294
295 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org774d7062010-07-21 18:55:45 +0000296 TInfoSink* infoSink = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000297
298 if (base->getAsCompiler())
299 infoSink = &(base->getAsCompiler()->getInfoSink());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300
301 infoSink->info << infoSink->debug.c_str();
302 return infoSink->info.c_str();
303}
304
305//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000306// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307//
308const char* ShGetObjectCode(const ShHandle handle)
309{
310 if (!InitThread())
311 return 0;
312
313 if (handle == 0)
314 return 0;
315
316 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
317 TInfoSink* infoSink;
318
319 if (base->getAsCompiler())
320 infoSink = &(base->getAsCompiler()->getInfoSink());
321
322 return infoSink->obj.c_str();
323}