blob: 3c41bc964f2f76a8f408e983306e167e3f56eb4f [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"
alokp@chromium.org07620a52010-09-23 17:53:56 +000011
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000012namespace {
13bool InitializeSymbolTable(
14 const TBuiltInStrings& builtInStrings,
15 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
16 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000017{
18 TIntermediate intermediate(infoSink);
19 TExtensionBehavior extBehavior;
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +000020 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000021
22 GlobalParseContext = &parseContext;
23
alokp@chromium.org07620a52010-09-23 17:53:56 +000024 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();
alokp@chromium.org07620a52010-09-23 17:53:56 +000034
35 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
36 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000037 const char* builtInShaders = i->c_str();
38 int builtInLengths = static_cast<int>(i->size());
39 if (builtInLengths <= 0)
40 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000041
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000042 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000043 {
44 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
45 return false;
46 }
47 }
48
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000049 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000050
alokp@chromium.org07620a52010-09-23 17:53:56 +000051 return true;
52}
53
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000054class TScopedPoolAllocator {
55public:
56 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
57 : mAllocator(allocator), mPushPopAllocator(pushPop) {
58 if (mPushPopAllocator) mAllocator->push();
59 SetGlobalPoolAllocator(mAllocator);
60 }
61 ~TScopedPoolAllocator() {
62 SetGlobalPoolAllocator(NULL);
63 if (mPushPopAllocator) mAllocator->pop();
64 }
65
66private:
67 TPoolAllocator* mAllocator;
68 bool mPushPopAllocator;
69};
70} // namespace
71
72TShHandleBase::TShHandleBase() {
73 allocator.push();
74 SetGlobalPoolAllocator(&allocator);
75}
76
77TShHandleBase::~TShHandleBase() {
78 SetGlobalPoolAllocator(NULL);
79 allocator.popAll();
80}
81
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000082TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
83 : shaderType(type),
84 shaderSpec(spec)
85{
86}
87
88TCompiler::~TCompiler()
89{
90}
91
92bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +000093{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000094 TScopedPoolAllocator scopedAlloc(&allocator, false);
95
alokp@chromium.org07620a52010-09-23 17:53:56 +000096 // Generate built-in symbol table.
97 if (!InitBuiltInSymbolTable(resources))
98 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +000099 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000100
alokp@chromium.org07620a52010-09-23 17:53:56 +0000101 return true;
102}
103
104bool TCompiler::compile(const char* const shaderStrings[],
105 const int numStrings,
106 int compileOptions)
107{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000108 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000109 clearResults();
110
111 if (numStrings == 0)
112 return true;
113
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000114 // If compiling for WebGL, validate loop and indexing as well.
115 if (shaderSpec == SH_WEBGL_SPEC)
116 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000117
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000118 // First string is path of source file if flag is set. The actual source follows.
119 const char* sourcePath = NULL;
120 int firstSource = 0;
121 if (compileOptions & SH_SOURCE_PATH)
122 {
123 sourcePath = shaderStrings[0];
124 ++firstSource;
125 }
126
alokp@chromium.org07620a52010-09-23 17:53:56 +0000127 TIntermediate intermediate(infoSink);
128 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000129 shaderType, shaderSpec, compileOptions,
130 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000131 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000132
133 // We preserve symbols at the built-in level from compile-to-compile.
134 // Start pushing the user-defined symbols at global level.
135 symbolTable.push();
136 if (!symbolTable.atGlobalLevel())
137 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
138
139 // Parse shader.
140 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000141 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000142 (parseContext.treeRoot != NULL);
143 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000144 TIntermNode* root = parseContext.treeRoot;
145 success = intermediate.postProcess(root);
146
147 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
148 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000149
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000150 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000151 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000152
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000153 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000155
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000156 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000157 collectAttribsUniforms(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000158 }
159
160 // Cleanup memory.
161 intermediate.remove(parseContext.treeRoot);
162 // Ensure symbol table is returned to the built-in level,
163 // throwing away all but the built-ins.
164 while (!symbolTable.atBuiltInLevel())
165 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000166
167 return success;
168}
169
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000170bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000171{
172 TBuiltIns builtIns;
173
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000174 builtIns.initialize(shaderType, shaderSpec, resources);
175 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
176 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000177}
178
179void TCompiler::clearResults()
180{
181 infoSink.info.erase();
182 infoSink.obj.erase();
183 infoSink.debug.erase();
184
185 attribs.clear();
186 uniforms.clear();
187}
188
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000189bool TCompiler::validateLimitations(TIntermNode* root) {
190 ValidateLimitations validate(shaderType, infoSink.info);
191 root->traverse(&validate);
192 return validate.numErrors() == 0;
193}
194
alokp@chromium.org07620a52010-09-23 17:53:56 +0000195void TCompiler::collectAttribsUniforms(TIntermNode* root)
196{
197 CollectAttribsUniforms collect(attribs, uniforms);
198 root->traverse(&collect);
199}