blob: e0c646ae46e76f6213590dfede1cd157a3c0578b [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);
26 TParseContext parseContext(symbolTable, intermediate, language, spec, infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027
alokp@chromium.orge4249f02010-07-26 18:13:52 +000028 GlobalParseContext = &parseContext;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000029
alokp@chromium.orge4249f02010-07-26 18:13:52 +000030 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
72static 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000082//
83// This is the platform independent interface between an OGL driver
alokp@chromium.org774d7062010-07-21 18:55:45 +000084// and the shading language compiler.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000085//
86
87//
88// Driver must call this first, once, before doing any other
alokp@chromium.org774d7062010-07-21 18:55:45 +000089// compiler operations.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000090//
91int ShInitialize()
92{
alokp@chromium.org34b99cd2010-07-27 18:37:55 +000093 if (!InitProcess())
94 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095
alokp@chromium.org34b99cd2010-07-27 18:37:55 +000096 return 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000097}
98
99//
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000100// Cleanup symbol tables
101//
102int 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//
113void 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//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000130// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131//
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000132ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000133{
134 if (!InitThread())
135 return 0;
136
alokp@chromium.org29cd91a2010-07-16 19:30:45 +0000137 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000138 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148 return reinterpret_cast<void*>(base);
149}
150
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151void 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());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160}
161
162//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163// 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//
169int ShCompile(
170 const ShHandle handle,
171 const char* const shaderStrings[],
172 const int numStrings,
173 const EShOptimizationLevel optLevel,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174 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();
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000189 TInfoSink& infoSink = compiler->getInfoSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000190 infoSink.info.erase();
191 infoSink.debug.erase();
192 infoSink.obj.erase();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193
194 if (numStrings == 0)
195 return 1;
196
alokp@chromium.org76b82082010-03-24 17:59:39 +0000197 TIntermediate intermediate(infoSink);
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000198 TSymbolTable& symbolTable = compiler->getSymbolTable();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000199
alokp@chromium.org613ef312010-07-21 18:54:22 +0000200 TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->getSpec(), infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 parseContext.initializeExtensionBehavior();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 GlobalParseContext = &parseContext;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000203
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000204 setInitialState();
205
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000206 InitPreprocessor();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207 //
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;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000213
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000214 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)
alokp@chromium.org774d7062010-07-21 18:55:45 +0000224 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation was requested.");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000225 else {
226 success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
227
228 if (success) {
229
230 if (debugOptions & EDebugOpIntermediate)
231 intermediate.outputTree(parseContext.treeRoot);
232
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233 //
234 // Call the machine dependent compiler
235 //
alokp@chromium.org76b82082010-03-24 17:59:39 +0000236 if (!compiler->compile(parseContext.treeRoot))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000237 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);
daniel@transgaming.combb2e9632010-04-13 19:53:50 +0000246 } 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);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252 }
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 //
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000260 while (!symbolTable.atBuiltInLevel())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261 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//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000273// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274//
275const 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);
alokp@chromium.org774d7062010-07-21 18:55:45 +0000284 TInfoSink* infoSink = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285
286 if (base->getAsCompiler())
287 infoSink = &(base->getAsCompiler()->getInfoSink());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288
289 infoSink->info << infoSink->debug.c_str();
290 return infoSink->info.c_str();
291}
292
293//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000294// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295//
296const 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}