blob: 3c36ef82f649a4e384b5660df535cd230a0f286f [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.orge4249f02010-07-26 18:13:52 +000093 bool ret = InitProcess();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000094
95 return ret ? 1 : 0;
96}
97
98//
alokp@chromium.org774d7062010-07-21 18:55:45 +000099// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100//
101
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000102ShHandle ShConstructCompiler(EShLanguage language, EShSpec spec, const TBuiltInResource* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000103{
104 if (!InitThread())
105 return 0;
106
alokp@chromium.org29cd91a2010-07-16 19:30:45 +0000107 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(language, spec));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000108 TCompiler* compiler = base->getAsCompiler();
109 if (compiler == 0)
110 return 0;
111
112 // Generate built-in symbol table.
113 if (!GenerateBuiltInSymbolTable(language, spec, *resources, compiler->getInfoSink(), compiler->getSymbolTable())) {
114 ShDestruct(base);
115 return 0;
116 }
117
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118 return reinterpret_cast<void*>(base);
119}
120
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000121void ShDestruct(ShHandle handle)
122{
123 if (handle == 0)
124 return;
125
126 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
127
128 if (base->getAsCompiler())
129 DeleteCompiler(base->getAsCompiler());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000130}
131
132//
133// Cleanup symbol tables
134//
alokp@chromium.orgc54bf502010-07-22 16:49:09 +0000135int ShFinalize()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136{
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000137 return 1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138}
139
140//
141// Do an actual compile on the given strings. The result is left
142// in the given compile object.
143//
144// Return: The return value of ShCompile is really boolean, indicating
145// success or failure.
146//
147int ShCompile(
148 const ShHandle handle,
149 const char* const shaderStrings[],
150 const int numStrings,
151 const EShOptimizationLevel optLevel,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152 int debugOptions
153 )
154{
155 if (!InitThread())
156 return 0;
157
158 if (handle == 0)
159 return 0;
160
161 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
162 TCompiler* compiler = base->getAsCompiler();
163 if (compiler == 0)
164 return 0;
165
166 GlobalPoolAllocator.push();
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000167 TInfoSink& infoSink = compiler->getInfoSink();
alokp@chromium.org76b82082010-03-24 17:59:39 +0000168 infoSink.info.erase();
169 infoSink.debug.erase();
170 infoSink.obj.erase();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171
172 if (numStrings == 0)
173 return 1;
174
alokp@chromium.org76b82082010-03-24 17:59:39 +0000175 TIntermediate intermediate(infoSink);
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000176 TSymbolTable& symbolTable = compiler->getSymbolTable();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177
alokp@chromium.org613ef312010-07-21 18:54:22 +0000178 TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->getSpec(), infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 parseContext.initializeExtensionBehavior();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 GlobalParseContext = &parseContext;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000181
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 setInitialState();
183
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000184 InitPreprocessor();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000185 //
186 // Parse the application's shaders. All the following symbol table
187 // work will be throw-away, so push a new allocation scope that can
188 // be thrown away, then push a scope for the current shader's globals.
189 //
190 bool success = true;
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000191
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192 symbolTable.push();
193 if (!symbolTable.atGlobalLevel())
194 parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
195
196 int ret = PaParseStrings(const_cast<char**>(shaderStrings), 0, numStrings, parseContext);
197 if (ret)
198 success = false;
199
200 if (success && parseContext.treeRoot) {
201 if (optLevel == EShOptNoGeneration)
alokp@chromium.org774d7062010-07-21 18:55:45 +0000202 parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation was requested.");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 else {
204 success = intermediate.postProcess(parseContext.treeRoot, parseContext.language);
205
206 if (success) {
207
208 if (debugOptions & EDebugOpIntermediate)
209 intermediate.outputTree(parseContext.treeRoot);
210
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 //
212 // Call the machine dependent compiler
213 //
alokp@chromium.org76b82082010-03-24 17:59:39 +0000214 if (!compiler->compile(parseContext.treeRoot))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215 success = false;
216 }
217 }
218 } else if (!success) {
219 parseContext.infoSink.info.prefix(EPrefixError);
220 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
221 success = false;
222 if (debugOptions & EDebugOpIntermediate)
223 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.combb2e9632010-04-13 19:53:50 +0000224 } else if (!parseContext.treeRoot) {
225 parseContext.error(1, "Unexpected end of file.", "", "");
226 parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n";
227 success = false;
228 if (debugOptions & EDebugOpIntermediate)
229 intermediate.outputTree(parseContext.treeRoot);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000230 }
231
232 intermediate.remove(parseContext.treeRoot);
233
234 //
235 // Ensure symbol table is returned to the built-in level,
236 // throwing away all but the built-ins.
237 //
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000238 while (!symbolTable.atBuiltInLevel())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239 symbolTable.pop();
240
241 FinalizePreprocessor();
242 //
243 // Throw away all the temporary memory used by the compilation process.
244 //
245 GlobalPoolAllocator.pop();
246
247 return success ? 1 : 0;
248}
249
250//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000251// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000252//
253const char* ShGetInfoLog(const ShHandle handle)
254{
255 if (!InitThread())
256 return 0;
257
258 if (handle == 0)
259 return 0;
260
261 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org774d7062010-07-21 18:55:45 +0000262 TInfoSink* infoSink = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000263
264 if (base->getAsCompiler())
265 infoSink = &(base->getAsCompiler()->getInfoSink());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
267 infoSink->info << infoSink->debug.c_str();
268 return infoSink->info.c_str();
269}
270
271//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000272// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273//
274const char* ShGetObjectCode(const ShHandle handle)
275{
276 if (!InitThread())
277 return 0;
278
279 if (handle == 0)
280 return 0;
281
282 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
283 TInfoSink* infoSink;
284
285 if (base->getAsCompiler())
286 infoSink = &(base->getAsCompiler()->getInfoSink());
287
288 return infoSink->obj.c_str();
289}