1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "Compiler.h"
16
17#include "AnalyzeCallDepth.h"
18#include "Initialize.h"
19#include "InitializeParseContext.h"
20#include "InitializeGlobals.h"
21#include "ParseHelper.h"
22#include "ValidateLimitations.h"
23
24namespace
25{
26class TScopedPoolAllocator {
27public:
28	TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
29		: mAllocator(allocator), mPushPopAllocator(pushPop)
30	{
31		if (mPushPopAllocator) mAllocator->push();
32		SetGlobalPoolAllocator(mAllocator);
33	}
34	~TScopedPoolAllocator()
35	{
36		SetGlobalPoolAllocator(nullptr);
37		if (mPushPopAllocator) mAllocator->pop();
38	}
39
40private:
41	TPoolAllocator* mAllocator;
42	bool mPushPopAllocator;
43};
44}  // namespace
45
46//
47// Initialize built-in resources with minimum expected values.
48//
49ShBuiltInResources::ShBuiltInResources()
50{
51	// Constants.
52	MaxVertexAttribs = 8;
53	MaxVertexUniformVectors = 128;
54	MaxVaryingVectors = 8;
55	MaxVertexTextureImageUnits = 0;
56	MaxCombinedTextureImageUnits = 8;
57	MaxTextureImageUnits = 8;
58	MaxFragmentUniformVectors = 16;
59	MaxDrawBuffers = 1;
60	MaxVertexOutputVectors = 16;
61	MaxFragmentInputVectors = 15;
62	MinProgramTexelOffset = -8;
63	MaxProgramTexelOffset = 7;
64
65	// Extensions.
66	OES_standard_derivatives = 0;
67	OES_fragment_precision_high = 0;
68	OES_EGL_image_external = 0;
69
70	MaxCallStackDepth = UINT_MAX;
71}
72
73TCompiler::TCompiler(GLenum type)
74	: shaderType(type),
75	  maxCallStackDepth(UINT_MAX)
76{
77	allocator.push();
78	SetGlobalPoolAllocator(&allocator);
79}
80
81TCompiler::~TCompiler()
82{
83	SetGlobalPoolAllocator(nullptr);
84	allocator.popAll();
85}
86
87bool TCompiler::Init(const ShBuiltInResources& resources)
88{
89	shaderVersion = 100;
90	maxCallStackDepth = resources.MaxCallStackDepth;
91	TScopedPoolAllocator scopedAlloc(&allocator, false);
92
93	// Generate built-in symbol table.
94	if (!InitBuiltInSymbolTable(resources))
95		return false;
96	InitExtensionBehavior(resources, extensionBehavior);
97
98	return true;
99}
100
101bool TCompiler::compile(const char* const shaderStrings[],
102                        const int numStrings,
103                        int compileOptions)
104{
105	TScopedPoolAllocator scopedAlloc(&allocator, true);
106	clearResults();
107
108	if (numStrings == 0)
109		return true;
110
111	// First string is path of source file if flag is set. The actual source follows.
112	const char* sourcePath = nullptr;
113	int firstSource = 0;
114	if (compileOptions & SH_SOURCE_PATH)
115	{
116		sourcePath = shaderStrings[0];
117		++firstSource;
118	}
119
120	TIntermediate intermediate(infoSink);
121	TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
122	                           shaderType, compileOptions, true,
123	                           sourcePath, infoSink);
124	SetGlobalParseContext(&parseContext);
125
126	// We preserve symbols at the built-in level from compile-to-compile.
127	// Start pushing the user-defined symbols at global level.
128	symbolTable.push();
129	if (!symbolTable.atGlobalLevel())
130		infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
131
132	// Parse shader.
133	bool success =
134		(PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
135		(parseContext.getTreeRoot() != nullptr);
136
137	shaderVersion = parseContext.getShaderVersion();
138
139	if (success) {
140		TIntermNode* root = parseContext.getTreeRoot();
141		success = intermediate.postProcess(root);
142
143		if (success)
144			success = validateCallDepth(root, infoSink);
145
146		if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
147			success = validateLimitations(root);
148
149		if (success && (compileOptions & SH_INTERMEDIATE_TREE))
150			intermediate.outputTree(root);
151
152		if (success && (compileOptions & SH_OBJECT_CODE))
153			success = translate(root);
154	}
155
156	// Ensure symbol table is returned to the built-in level,
157	// throwing away all but the built-ins.
158	while (!symbolTable.atBuiltInLevel())
159		symbolTable.pop();
160
161	return success;
162}
163
164bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
165{
166	assert(symbolTable.isEmpty());
167	symbolTable.push();   // COMMON_BUILTINS
168	symbolTable.push();   // ESSL1_BUILTINS
169	symbolTable.push();   // ESSL3_BUILTINS
170
171	TPublicType integer;
172	integer.type = EbtInt;
173	integer.primarySize = 1;
174	integer.secondarySize = 1;
175	integer.array = false;
176
177	TPublicType floatingPoint;
178	floatingPoint.type = EbtFloat;
179	floatingPoint.primarySize = 1;
180	floatingPoint.secondarySize = 1;
181	floatingPoint.array = false;
182
183	switch(shaderType)
184	{
185	case GL_FRAGMENT_SHADER:
186		symbolTable.setDefaultPrecision(integer, EbpMedium);
187		break;
188	case GL_VERTEX_SHADER:
189		symbolTable.setDefaultPrecision(integer, EbpHigh);
190		symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
191		break;
192	default: assert(false && "Language not supported");
193	}
194
195	InsertBuiltInFunctions(shaderType, resources, symbolTable);
196
197	IdentifyBuiltIns(shaderType, resources, symbolTable);
198
199	return true;
200}
201
202void TCompiler::clearResults()
203{
204	infoSink.info.erase();
205	infoSink.obj.erase();
206	infoSink.debug.erase();
207}
208
209bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
210{
211	AnalyzeCallDepth validator(root);
212
213	unsigned int depth = validator.analyzeCallDepth();
214
215	if(depth == 0)
216	{
217		infoSink.info.prefix(EPrefixError);
218		infoSink.info << "Missing main()";
219		return false;
220	}
221	else if(depth == UINT_MAX)
222	{
223		infoSink.info.prefix(EPrefixError);
224		infoSink.info << "Function recursion detected";
225		return false;
226	}
227	else if(depth > maxCallStackDepth)
228	{
229		infoSink.info.prefix(EPrefixError);
230		infoSink.info << "Function call stack too deep";
231		return false;
232	}
233
234	return true;
235}
236
237bool TCompiler::validateLimitations(TIntermNode* root) {
238	ValidateLimitations validate(shaderType, infoSink.info);
239	root->traverse(&validate);
240	return validate.numErrors() == 0;
241}
242
243const TExtensionBehavior& TCompiler::getExtensionBehavior() const
244{
245	return extensionBehavior;
246}
247
248bool InitCompilerGlobals()
249{
250	if(!InitializePoolIndex())
251	{
252		assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
253		return false;
254	}
255
256	if(!InitializeParseContextIndex())
257	{
258		assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
259		return false;
260	}
261
262	return true;
263}
264
265void FreeCompilerGlobals()
266{
267	FreeParseContextIndex();
268	FreePoolIndex();
269}
270