1 //
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"
10 #include "compiler/ValidateLimitations.h"
11
12 namespace {
InitializeSymbolTable(const TBuiltInStrings & builtInStrings,ShShaderType type,ShShaderSpec spec,const ShBuiltInResources & resources,TInfoSink & infoSink,TSymbolTable & symbolTable)13 bool InitializeSymbolTable(
14 const TBuiltInStrings& builtInStrings,
15 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
16 TInfoSink& infoSink, TSymbolTable& symbolTable)
17 {
18 TIntermediate intermediate(infoSink);
19 TExtensionBehavior extBehavior;
20 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, infoSink);
21
22 GlobalParseContext = &parseContext;
23
24 assert(symbolTable.isEmpty());
25 //
26 // Parse the built-ins. This should only happen once per
27 // language symbol table.
28 //
29 // Push the symbol table to give it an initial scope. This
30 // push should not have a corresponding pop, so that built-ins
31 // are preserved, and the test for an empty table fails.
32 //
33 symbolTable.push();
34
35 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
36 {
37 const char* builtInShaders = i->c_str();
38 int builtInLengths = static_cast<int>(i->size());
39 if (builtInLengths <= 0)
40 continue;
41
42 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
43 {
44 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
45 return false;
46 }
47 }
48
49 IdentifyBuiltIns(type, spec, resources, symbolTable);
50
51 return true;
52 }
53
54 class TScopedPoolAllocator {
55 public:
TScopedPoolAllocator(TPoolAllocator * allocator,bool pushPop)56 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
57 : mAllocator(allocator), mPushPopAllocator(pushPop) {
58 if (mPushPopAllocator) mAllocator->push();
59 SetGlobalPoolAllocator(mAllocator);
60 }
~TScopedPoolAllocator()61 ~TScopedPoolAllocator() {
62 SetGlobalPoolAllocator(NULL);
63 if (mPushPopAllocator) mAllocator->pop();
64 }
65
66 private:
67 TPoolAllocator* mAllocator;
68 bool mPushPopAllocator;
69 };
70 } // namespace
71
TShHandleBase()72 TShHandleBase::TShHandleBase() {
73 allocator.push();
74 SetGlobalPoolAllocator(&allocator);
75 }
76
~TShHandleBase()77 TShHandleBase::~TShHandleBase() {
78 SetGlobalPoolAllocator(NULL);
79 allocator.popAll();
80 }
81
TCompiler(ShShaderType type,ShShaderSpec spec)82 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
83 : shaderType(type),
84 shaderSpec(spec)
85 {
86 }
87
~TCompiler()88 TCompiler::~TCompiler()
89 {
90 }
91
Init(const ShBuiltInResources & resources)92 bool TCompiler::Init(const ShBuiltInResources& resources)
93 {
94 TScopedPoolAllocator scopedAlloc(&allocator, false);
95
96 // Generate built-in symbol table.
97 if (!InitBuiltInSymbolTable(resources))
98 return false;
99 InitExtensionBehavior(resources, extensionBehavior);
100
101 return true;
102 }
103
compile(const char * const shaderStrings[],const int numStrings,int compileOptions)104 bool TCompiler::compile(const char* const shaderStrings[],
105 const int numStrings,
106 int compileOptions)
107 {
108 TScopedPoolAllocator scopedAlloc(&allocator, true);
109 clearResults();
110
111 if (numStrings == 0)
112 return true;
113
114 // If compiling for WebGL, validate loop and indexing as well.
115 if (shaderSpec == SH_WEBGL_SPEC)
116 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
117
118 TIntermediate intermediate(infoSink);
119 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
120 shaderType, shaderSpec, infoSink);
121 GlobalParseContext = &parseContext;
122
123 // We preserve symbols at the built-in level from compile-to-compile.
124 // Start pushing the user-defined symbols at global level.
125 symbolTable.push();
126 if (!symbolTable.atGlobalLevel())
127 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
128
129 // Parse shader.
130 bool success =
131 (PaParseStrings(numStrings, shaderStrings, NULL, &parseContext) == 0) &&
132 (parseContext.treeRoot != NULL);
133 if (success) {
134 TIntermNode* root = parseContext.treeRoot;
135 success = intermediate.postProcess(root);
136
137 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
138 success = validateLimitations(root);
139
140 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
141 intermediate.outputTree(root);
142
143 if (success && (compileOptions & SH_OBJECT_CODE))
144 translate(root);
145
146 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
147 collectAttribsUniforms(root);
148 }
149
150 // Cleanup memory.
151 intermediate.remove(parseContext.treeRoot);
152 // Ensure symbol table is returned to the built-in level,
153 // throwing away all but the built-ins.
154 while (!symbolTable.atBuiltInLevel())
155 symbolTable.pop();
156
157 return success;
158 }
159
InitBuiltInSymbolTable(const ShBuiltInResources & resources)160 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
161 {
162 TBuiltIns builtIns;
163
164 builtIns.initialize(shaderType, shaderSpec, resources);
165 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
166 shaderType, shaderSpec, resources, infoSink, symbolTable);
167 }
168
clearResults()169 void TCompiler::clearResults()
170 {
171 infoSink.info.erase();
172 infoSink.obj.erase();
173 infoSink.debug.erase();
174
175 attribs.clear();
176 uniforms.clear();
177 }
178
validateLimitations(TIntermNode * root)179 bool TCompiler::validateLimitations(TIntermNode* root) {
180 ValidateLimitations validate(shaderType, infoSink.info);
181 root->traverse(&validate);
182 return validate.numErrors() == 0;
183 }
184
collectAttribsUniforms(TIntermNode * root)185 void TCompiler::collectAttribsUniforms(TIntermNode* root)
186 {
187 CollectAttribsUniforms collect(attribs, uniforms);
188 root->traverse(&collect);
189 }
190