blob: 655d62d70c1c117f02031fd2387d1911f720ee0e [file] [log] [blame]
alokp@chromium.org07620a52010-09-23 17:53:56 +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#include "compiler/Initialize.h"
8#include "compiler/ParseHelper.h"
9#include "compiler/ShHandle.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000010#include "compiler/ValidateLimitations.h"
zmo@google.comfd747b82011-04-23 01:30:07 +000011#include "compiler/MapLongVariableNames.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000012
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000013namespace {
14bool InitializeSymbolTable(
15 const TBuiltInStrings& builtInStrings,
16 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
17 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000018{
19 TIntermediate intermediate(infoSink);
20 TExtensionBehavior extBehavior;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000021 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000022
23 GlobalParseContext = &parseContext;
24
alokp@chromium.org07620a52010-09-23 17:53:56 +000025 assert(symbolTable.isEmpty());
26 //
27 // Parse the built-ins. This should only happen once per
28 // language symbol table.
29 //
30 // Push the symbol table to give it an initial scope. This
31 // push should not have a corresponding pop, so that built-ins
32 // are preserved, and the test for an empty table fails.
33 //
34 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000035
36 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
37 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000038 const char* builtInShaders = i->c_str();
39 int builtInLengths = static_cast<int>(i->size());
40 if (builtInLengths <= 0)
41 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000042
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000043 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000044 {
45 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
46 return false;
47 }
48 }
49
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000050 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000051
alokp@chromium.org07620a52010-09-23 17:53:56 +000052 return true;
53}
54
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000055class TScopedPoolAllocator {
56public:
57 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
58 : mAllocator(allocator), mPushPopAllocator(pushPop) {
59 if (mPushPopAllocator) mAllocator->push();
60 SetGlobalPoolAllocator(mAllocator);
61 }
62 ~TScopedPoolAllocator() {
63 SetGlobalPoolAllocator(NULL);
64 if (mPushPopAllocator) mAllocator->pop();
65 }
66
67private:
68 TPoolAllocator* mAllocator;
69 bool mPushPopAllocator;
70};
71} // namespace
72
73TShHandleBase::TShHandleBase() {
74 allocator.push();
75 SetGlobalPoolAllocator(&allocator);
76}
77
78TShHandleBase::~TShHandleBase() {
79 SetGlobalPoolAllocator(NULL);
80 allocator.popAll();
81}
82
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000083TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
84 : shaderType(type),
85 shaderSpec(spec)
86{
87}
88
89TCompiler::~TCompiler()
90{
91}
92
93bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +000094{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000095 TScopedPoolAllocator scopedAlloc(&allocator, false);
96
alokp@chromium.org07620a52010-09-23 17:53:56 +000097 // Generate built-in symbol table.
98 if (!InitBuiltInSymbolTable(resources))
99 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000100 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000101
alokp@chromium.org07620a52010-09-23 17:53:56 +0000102 return true;
103}
104
105bool TCompiler::compile(const char* const shaderStrings[],
106 const int numStrings,
107 int compileOptions)
108{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000109 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000110 clearResults();
111
112 if (numStrings == 0)
113 return true;
114
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000115 // If compiling for WebGL, validate loop and indexing as well.
116 if (shaderSpec == SH_WEBGL_SPEC)
117 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000118
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000119 // First string is path of source file if flag is set. The actual source follows.
120 const char* sourcePath = NULL;
121 int firstSource = 0;
122 if (compileOptions & SH_SOURCE_PATH)
123 {
124 sourcePath = shaderStrings[0];
125 ++firstSource;
126 }
127
alokp@chromium.org07620a52010-09-23 17:53:56 +0000128 TIntermediate intermediate(infoSink);
129 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000130 shaderType, shaderSpec, compileOptions,
131 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000132 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000133
134 // We preserve symbols at the built-in level from compile-to-compile.
135 // Start pushing the user-defined symbols at global level.
136 symbolTable.push();
137 if (!symbolTable.atGlobalLevel())
138 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
139
140 // Parse shader.
141 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000142 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000143 (parseContext.treeRoot != NULL);
144 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000145 TIntermNode* root = parseContext.treeRoot;
146 success = intermediate.postProcess(root);
147
148 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
149 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000150
zmo@google.comfd747b82011-04-23 01:30:07 +0000151 // Call mapLongVariableNames() before collectAttribsUniforms() so in
152 // collectAttribsUniforms() we already have the mapped symbol names and
153 // we could composite mapped and original variable names.
154 if (compileOptions & SH_MAP_LONG_VARIABLE_NAMES)
155 mapLongVariableNames(root);
156
157 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
158 collectAttribsUniforms(root);
159
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000160 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000161 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000162
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000163 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000164 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000165 }
166
167 // Cleanup memory.
168 intermediate.remove(parseContext.treeRoot);
169 // Ensure symbol table is returned to the built-in level,
170 // throwing away all but the built-ins.
171 while (!symbolTable.atBuiltInLevel())
172 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000173
174 return success;
175}
176
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000177bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000178{
179 TBuiltIns builtIns;
180
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000181 builtIns.initialize(shaderType, shaderSpec, resources);
182 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
183 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000184}
185
186void TCompiler::clearResults()
187{
188 infoSink.info.erase();
189 infoSink.obj.erase();
190 infoSink.debug.erase();
191
192 attribs.clear();
193 uniforms.clear();
194}
195
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000196bool TCompiler::validateLimitations(TIntermNode* root) {
197 ValidateLimitations validate(shaderType, infoSink.info);
198 root->traverse(&validate);
199 return validate.numErrors() == 0;
200}
201
alokp@chromium.org07620a52010-09-23 17:53:56 +0000202void TCompiler::collectAttribsUniforms(TIntermNode* root)
203{
204 CollectAttribsUniforms collect(attribs, uniforms);
205 root->traverse(&collect);
206}
zmo@google.comfd747b82011-04-23 01:30:07 +0000207
208void TCompiler::mapLongVariableNames(TIntermNode* root)
209{
zmo@google.com24c08c42011-05-27 17:40:48 +0000210 MapLongVariableNames map(varyingLongNameMap);
zmo@google.comfd747b82011-04-23 01:30:07 +0000211 root->traverse(&map);
212}
213
214int TCompiler::getMappedNameMaxLength() const
215{
216 return MAX_IDENTIFIER_NAME_SIZE + 1;
217}
zmo@google.com5601ea02011-06-10 18:23:25 +0000218
219const TExtensionBehavior& TCompiler::getExtensionBehavior() const
220{
221 return extensionBehavior;
222}