blob: e34bee9637b62f081fc3ed989e5933300cb383e8 [file] [log] [blame]
John Bauman66b8ab22014-05-06 15:57:45 -04001//
John Baumand4ae8632014-05-06 16:18:33 -04002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
John Bauman66b8ab22014-05-06 15:57:45 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Nicolas Capenscc863da2015-01-21 15:50:55 -05007#include "AnalyzeCallDepth.h"
8#include "Initialize.h"
9#include "InitializeParseContext.h"
10#include "ParseHelper.h"
Nicolas Capensd8cbf392015-02-10 15:35:11 -050011#include "Compiler.h"
Nicolas Capenscc863da2015-01-21 15:50:55 -050012#include "ValidateLimitations.h"
John Bauman66b8ab22014-05-06 15:57:45 -040013
John Baumand4ae8632014-05-06 16:18:33 -040014namespace
John Bauman66b8ab22014-05-06 15:57:45 -040015{
John Bauman66b8ab22014-05-06 15:57:45 -040016class TScopedPoolAllocator {
17public:
18 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
19 : mAllocator(allocator), mPushPopAllocator(pushPop) {
20 if (mPushPopAllocator) mAllocator->push();
21 SetGlobalPoolAllocator(mAllocator);
22 }
23 ~TScopedPoolAllocator() {
24 SetGlobalPoolAllocator(NULL);
25 if (mPushPopAllocator) mAllocator->pop();
26 }
27
28private:
29 TPoolAllocator* mAllocator;
30 bool mPushPopAllocator;
31};
32} // namespace
33
John Bauman66b8ab22014-05-06 15:57:45 -040034TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
35 : shaderType(type),
John Baumand4ae8632014-05-06 16:18:33 -040036 shaderSpec(spec),
37 maxCallStackDepth(UINT_MAX)
John Bauman66b8ab22014-05-06 15:57:45 -040038{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050039 allocator.push();
40 SetGlobalPoolAllocator(&allocator);
John Bauman66b8ab22014-05-06 15:57:45 -040041}
42
43TCompiler::~TCompiler()
44{
Nicolas Capens7a8ccc42015-02-10 15:42:31 -050045 SetGlobalPoolAllocator(NULL);
46 allocator.popAll();
John Bauman66b8ab22014-05-06 15:57:45 -040047}
48
49bool TCompiler::Init(const ShBuiltInResources& resources)
50{
John Baumand4ae8632014-05-06 16:18:33 -040051 maxCallStackDepth = resources.MaxCallStackDepth;
John Bauman66b8ab22014-05-06 15:57:45 -040052 TScopedPoolAllocator scopedAlloc(&allocator, false);
53
54 // Generate built-in symbol table.
55 if (!InitBuiltInSymbolTable(resources))
56 return false;
57 InitExtensionBehavior(resources, extensionBehavior);
58
59 return true;
60}
61
62bool TCompiler::compile(const char* const shaderStrings[],
63 const int numStrings,
64 int compileOptions)
65{
66 TScopedPoolAllocator scopedAlloc(&allocator, true);
67 clearResults();
68
69 if (numStrings == 0)
70 return true;
71
72 // If compiling for WebGL, validate loop and indexing as well.
73 if (shaderSpec == SH_WEBGL_SPEC)
74 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
75
76 // First string is path of source file if flag is set. The actual source follows.
77 const char* sourcePath = NULL;
78 int firstSource = 0;
79 if (compileOptions & SH_SOURCE_PATH)
80 {
81 sourcePath = shaderStrings[0];
82 ++firstSource;
83 }
84
85 TIntermediate intermediate(infoSink);
86 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
87 shaderType, shaderSpec, compileOptions, true,
88 sourcePath, infoSink);
Nicolas Capens978ddc52014-11-11 12:42:08 -050089 SetGlobalParseContext(&parseContext);
John Bauman66b8ab22014-05-06 15:57:45 -040090
91 // We preserve symbols at the built-in level from compile-to-compile.
92 // Start pushing the user-defined symbols at global level.
93 symbolTable.push();
94 if (!symbolTable.atGlobalLevel())
95 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
96
97 // Parse shader.
98 bool success =
99 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
100 (parseContext.treeRoot != NULL);
101 if (success) {
102 TIntermNode* root = parseContext.treeRoot;
103 success = intermediate.postProcess(root);
104
105 if (success)
John Baumand4ae8632014-05-06 16:18:33 -0400106 success = validateCallDepth(root, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400107
108 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
109 success = validateLimitations(root);
110
John Bauman66b8ab22014-05-06 15:57:45 -0400111 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
112 intermediate.outputTree(root);
113
114 if (success && (compileOptions & SH_OBJECT_CODE))
Nicolas Capens014b9a62014-10-15 10:28:29 -0400115 success = translate(root);
John Bauman66b8ab22014-05-06 15:57:45 -0400116 }
117
John Bauman66b8ab22014-05-06 15:57:45 -0400118 // Ensure symbol table is returned to the built-in level,
119 // throwing away all but the built-ins.
120 while (!symbolTable.atBuiltInLevel())
121 symbolTable.pop();
122
123 return success;
124}
125
John Baumand4ae8632014-05-06 16:18:33 -0400126bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
John Bauman66b8ab22014-05-06 15:57:45 -0400127{
John Baumand4ae8632014-05-06 16:18:33 -0400128 assert(symbolTable.isEmpty());
129
130 //
131 // Push the symbol table to give it an initial scope. This
132 // push should not have a corresponding pop, so that built-ins
133 // are preserved, and the test for an empty table fails.
134 //
135 symbolTable.push();
John Bauman66b8ab22014-05-06 15:57:45 -0400136
John Baumand4ae8632014-05-06 16:18:33 -0400137 TPublicType integer;
138 integer.type = EbtInt;
139 integer.size = 1;
140 integer.matrix = false;
141 integer.array = false;
142
143 TPublicType floatingPoint;
144 floatingPoint.type = EbtFloat;
145 floatingPoint.size = 1;
146 floatingPoint.matrix = false;
147 floatingPoint.array = false;
148
149 switch(shaderType)
150 {
151 case SH_FRAGMENT_SHADER:
152 symbolTable.setDefaultPrecision(integer, EbpMedium);
153 break;
154 case SH_VERTEX_SHADER:
155 symbolTable.setDefaultPrecision(integer, EbpHigh);
156 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
157 break;
158 default: assert(false && "Language not supported");
159 }
160
161 InsertBuiltInFunctions(shaderType, resources, symbolTable);
162
163 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
164
165 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400166}
167
168void TCompiler::clearResults()
169{
170 infoSink.info.erase();
171 infoSink.obj.erase();
172 infoSink.debug.erase();
John Bauman66b8ab22014-05-06 15:57:45 -0400173}
174
John Baumand4ae8632014-05-06 16:18:33 -0400175bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
John Bauman66b8ab22014-05-06 15:57:45 -0400176{
John Baumand4ae8632014-05-06 16:18:33 -0400177 AnalyzeCallDepth validator(root);
178
179 unsigned int depth = validator.analyzeCallDepth();
180
181 if(depth == 0)
182 {
183 infoSink.info.prefix(EPrefixError);
184 infoSink.info << "Missing main()";
185 return false;
186 }
187 else if(depth == UINT_MAX)
188 {
189 infoSink.info.prefix(EPrefixError);
190 infoSink.info << "Function recursion detected";
191 return false;
192 }
193 else if(depth > maxCallStackDepth)
194 {
195 infoSink.info.prefix(EPrefixError);
196 infoSink.info << "Function call stack too deep";
197 return false;
198 }
199
200 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400201}
202
203bool TCompiler::validateLimitations(TIntermNode* root) {
204 ValidateLimitations validate(shaderType, infoSink.info);
205 root->traverse(&validate);
206 return validate.numErrors() == 0;
207}
208
John Bauman66b8ab22014-05-06 15:57:45 -0400209const TExtensionBehavior& TCompiler::getExtensionBehavior() const
210{
211 return extensionBehavior;
212}