blob: 865be18ffbefd6d50d0d3993056e401b87bd7f23 [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.org774d7062010-07-21 18:55:45 +0000100// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101//
102
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000103ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104{
105 if (!InitThread())
106 return 0;
107
alokp@chromium.org29cd91a2010-07-16 19:30:45 +0000108 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000109 TCompiler* compiler = base->getAsCompiler();
110 if (compiler == 0)
111 return 0;
112
113 // Generate built-in symbol table.
114 if (!GenerateBuiltInSymbolTable(language, spec, *resources, compiler->getInfoSink(), compiler->getSymbolTable())) {
115 ShDestruct(base);
116 return 0;
117 }
118
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000119 return reinterpret_cast<void*>(base);
120}
121
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122void ShDestruct(ShHandle handle)
123{
124 if (handle == 0)
125 return;
126
127 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
128
129 if (base->getAsCompiler())
130 DeleteCompiler(base->getAsCompiler());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131}
132
133//
134// Cleanup symbol tables
135//
alokp@chromium.orgc54bf502010-07-22 16:49:09 +0000136int ShFinalize()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137{
alokp@chromium.org34b99cd2010-07-27 18:37:55 +0000138 if (!DetachProcess())
139 return 0;
140
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000141 return 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000142}
143
144//
145// Do an actual compile on the given strings. The result is left
146// in the given compile object.
147//
148// Return: The return value of ShCompile is really boolean, indicating
149// success or failure.
150//
151int ShCompile(
152 const ShHandle handle,
153 const char* const shaderStrings[],
154 const int numStrings,
155 const EShOptimizationLevel optLevel,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156 int debugOptions
157 )
158{
159 if (!InitThread())
160 return 0;
161
162 if (handle == 0)
163 return 0;
164
165 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
166 TCompiler* compiler = base->getAsCompiler();
167 if (compiler == 0)
168 return 0;
169
170 GlobalPoolAllocator.push();
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000171 TInfoSink& infoSink = compiler->getInfoSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000172 infoSink.info.erase();
173 infoSink.debug.erase();
174 infoSink.obj.erase();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175
176 if (numStrings == 0)
177 return 1;
178
alokp@chromium.org76b82082010-03-24 17:59:39 +0000179 TIntermediate intermediate(infoSink);
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000180 TSymbolTable& symbolTable = compiler->getSymbolTable();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181
alokp@chromium.org613ef312010-07-21 18:54:22 +0000182 TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->getSpec(), infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000183 parseContext.initializeExtensionBehavior();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184 GlobalParseContext = &parseContext;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000185
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000186 setInitialState();
187
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000188 InitPreprocessor();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189 //
190 // Parse the application's shaders. All the following symbol table
191 // work will be throw-away, so push a new allocation scope that can
192 // be thrown away, then push a scope for the current shader's globals.
193 //
194 bool success = true;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000195
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 symbolTable.push();
197 if (!symbolTable.atGlobalLevel())
198 parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
199
200 int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext);
201 if (ret)
202 success = false;
203
204 if (success && parseContext.treeRoot) {
205 if (optLevel == EShOptNoGeneration)
alokp@chromium.org774d7062010-07-21 18:55:45 +0000206 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation was requested.");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207 else {
208 success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
209
210 if (success) {
211
212 if (debugOptions & EDebugOpIntermediate)
213 intermediate.outputTree(parseContext.treeRoot);
214
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 //
216 // Call the machine dependent compiler
217 //
alokp@chromium.org76b82082010-03-24 17:59:39 +0000218 if (!compiler->compile(parseContext.treeRoot))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000219 success = false;
220 }
221 }
222 } else if (!success) {
223 parseContext.infoSink.info.prefix(EPrefixError);
224 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
225 success = false;
226 if (debugOptions & EDebugOpIntermediate)
227 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.combb2e9632010-04-13 19:53:50 +0000228 } else if (!parseContext.treeRoot) {
229 parseContext.error(1, "Unexpected end of file.", "", "");
230 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
231 success = false;
232 if (debugOptions & EDebugOpIntermediate)
233 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000234 }
235
236 intermediate.remove(parseContext.treeRoot);
237
238 //
239 // Ensure symbol table is returned to the built-in level,
240 // throwing away all but the built-ins.
241 //
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000242 while (!symbolTable.atBuiltInLevel())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243 symbolTable.pop();
244
245 FinalizePreprocessor();
246 //
247 // Throw away all the temporary memory used by the compilation process.
248 //
249 GlobalPoolAllocator.pop();
250
251 return success ? 1 : 0;
252}
253
254//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000255// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256//
257const char* ShGetInfoLog(const ShHandle handle)
258{
259 if (!InitThread())
260 return 0;
261
262 if (handle == 0)
263 return 0;
264
265 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org774d7062010-07-21 18:55:45 +0000266 TInfoSink* infoSink = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267
268 if (base->getAsCompiler())
269 infoSink = &(base->getAsCompiler()->getInfoSink());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000270
271 infoSink->info << infoSink->debug.c_str();
272 return infoSink->info.c_str();
273}
274
275//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000276// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277//
278const char* ShGetObjectCode(const ShHandle handle)
279{
280 if (!InitThread())
281 return 0;
282
283 if (handle == 0)
284 return 0;
285
286 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
287 TInfoSink* infoSink;
288
289 if (base->getAsCompiler())
290 infoSink = &(base->getAsCompiler()->getInfoSink());
291
292 return infoSink->obj.c_str();
293}