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// Shader.cpp: Implements the Shader class and its  derived classes
16// VertexShader and FragmentShader. Implements GL shader objects and related
17// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
18
19#include "Shader.h"
20
21#include "main.h"
22#include "utilities.h"
23
24#include <string>
25#include <algorithm>
26
27namespace es2
28{
29bool Shader::compilerInitialized = false;
30
31Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
32{
33	mSource = nullptr;
34
35	clear();
36
37	mRefCount = 0;
38	mDeleteStatus = false;
39}
40
41Shader::~Shader()
42{
43	delete[] mSource;
44}
45
46GLuint Shader::getName() const
47{
48	return mHandle;
49}
50
51void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
52{
53	delete[] mSource;
54	int totalLength = 0;
55
56	for(int i = 0; i < count; i++)
57	{
58		if(length && length[i] >= 0)
59		{
60			totalLength += length[i];
61		}
62		else
63		{
64			totalLength += (int)strlen(string[i]);
65		}
66	}
67
68	mSource = new char[totalLength + 1];
69	char *code = mSource;
70
71	for(int i = 0; i < count; i++)
72	{
73		int stringLength;
74
75		if(length && length[i] >= 0)
76		{
77			stringLength = length[i];
78		}
79		else
80		{
81			stringLength = (int)strlen(string[i]);
82		}
83
84		strncpy(code, string[i], stringLength);
85		code += stringLength;
86	}
87
88	mSource[totalLength] = '\0';
89}
90
91size_t Shader::getInfoLogLength() const
92{
93	if(infoLog.empty())
94	{
95		return 0;
96	}
97	else
98	{
99	   return infoLog.size() + 1;
100	}
101}
102
103void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLogOut)
104{
105	int index = 0;
106
107	if(bufSize > 0)
108	{
109		if(!infoLog.empty())
110		{
111			index = std::min(bufSize - 1, (GLsizei)infoLog.size());
112			memcpy(infoLogOut, infoLog.c_str(), index);
113		}
114
115		infoLogOut[index] = '\0';
116	}
117
118	if(length)
119	{
120		*length = index;
121	}
122}
123
124size_t Shader::getSourceLength() const
125{
126	if(!mSource)
127	{
128		return 0;
129	}
130	else
131	{
132	   return strlen(mSource) + 1;
133	}
134}
135
136void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
137{
138	int index = 0;
139
140	if(bufSize > 0)
141	{
142		if(mSource)
143		{
144			index = std::min(bufSize - 1, (int)strlen(mSource));
145			memcpy(source, mSource, index);
146		}
147
148		source[index] = '\0';
149	}
150
151	if(length)
152	{
153		*length = index;
154	}
155}
156
157TranslatorASM *Shader::createCompiler(GLenum shaderType)
158{
159	if(!compilerInitialized)
160	{
161		InitCompilerGlobals();
162		compilerInitialized = true;
163	}
164
165	TranslatorASM *assembler = new TranslatorASM(this, shaderType);
166
167	ShBuiltInResources resources;
168	resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
169	resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
170	resources.MaxVaryingVectors = MAX_VARYING_VECTORS;
171	resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
172	resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
173	resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
174	resources.MaxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS;
175	resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
176	resources.MaxVertexOutputVectors = MAX_VERTEX_OUTPUT_VECTORS;
177	resources.MaxFragmentInputVectors = MAX_FRAGMENT_INPUT_VECTORS;
178	resources.MinProgramTexelOffset = MIN_PROGRAM_TEXEL_OFFSET;
179	resources.MaxProgramTexelOffset = MAX_PROGRAM_TEXEL_OFFSET;
180	resources.OES_standard_derivatives = 1;
181	resources.OES_fragment_precision_high = 1;
182	resources.OES_EGL_image_external = 1;
183	resources.EXT_draw_buffers = 1;
184	resources.ARB_texture_rectangle = 1;
185	resources.MaxCallStackDepth = 64;
186	assembler->Init(resources);
187
188	return assembler;
189}
190
191void Shader::clear()
192{
193	infoLog.clear();
194
195	varyings.clear();
196	activeUniforms.clear();
197	activeAttributes.clear();
198}
199
200void Shader::compile()
201{
202	clear();
203
204	createShader();
205	TranslatorASM *compiler = createCompiler(getType());
206
207	// Ensure we don't pass a nullptr source to the compiler
208	const char *source = "\0";
209	if(mSource)
210	{
211		source = mSource;
212	}
213
214	bool success = compiler->compile(&source, 1, SH_OBJECT_CODE);
215
216	if(false)
217	{
218		static int serial = 1;
219
220		if(false)
221		{
222			char buffer[256];
223			sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial);
224			FILE *file = fopen(buffer, "wt");
225			fprintf(file, "%s", mSource);
226			fclose(file);
227		}
228
229		getShader()->print("shader-output-%d-%d.txt", getName(), serial);
230
231		serial++;
232	}
233
234	shaderVersion = compiler->getShaderVersion();
235	int clientVersion = es2::getContext()->getClientVersion();
236
237	if(shaderVersion >= 300 && clientVersion < 3)
238	{
239		infoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts";
240		success = false;
241	}
242
243	if(!success)
244	{
245		deleteShader();
246
247		infoLog += compiler->getInfoSink().info.c_str();
248		TRACE("\n%s", infoLog.c_str());
249	}
250
251	delete compiler;
252}
253
254bool Shader::isCompiled()
255{
256	return getShader() != 0;
257}
258
259void Shader::addRef()
260{
261	mRefCount++;
262}
263
264void Shader::release()
265{
266	mRefCount--;
267
268	if(mRefCount == 0 && mDeleteStatus)
269	{
270		mResourceManager->deleteShader(mHandle);
271	}
272}
273
274unsigned int Shader::getRefCount() const
275{
276	return mRefCount;
277}
278
279bool Shader::isFlaggedForDeletion() const
280{
281	return mDeleteStatus;
282}
283
284void Shader::flagForDeletion()
285{
286	mDeleteStatus = true;
287}
288
289void Shader::releaseCompiler()
290{
291	FreeCompilerGlobals();
292	compilerInitialized = false;
293}
294
295// true if varying x has a higher priority in packing than y
296bool Shader::compareVarying(const glsl::Varying &x, const glsl::Varying &y)
297{
298	if(x.type == y.type)
299	{
300		return x.size() > y.size();
301	}
302
303	switch(x.type)
304	{
305	case GL_FLOAT_MAT4: return true;
306	case GL_FLOAT_MAT2:
307		switch(y.type)
308		{
309		case GL_FLOAT_MAT4: return false;
310		case GL_FLOAT_MAT2: return true;
311		case GL_FLOAT_VEC4: return true;
312		case GL_FLOAT_MAT3: return true;
313		case GL_FLOAT_VEC3: return true;
314		case GL_FLOAT_VEC2: return true;
315		case GL_FLOAT:      return true;
316		default: UNREACHABLE(y.type);
317		}
318		break;
319	case GL_FLOAT_VEC4:
320		switch(y.type)
321		{
322		case GL_FLOAT_MAT4: return false;
323		case GL_FLOAT_MAT2: return false;
324		case GL_FLOAT_VEC4: return true;
325		case GL_FLOAT_MAT3: return true;
326		case GL_FLOAT_VEC3: return true;
327		case GL_FLOAT_VEC2: return true;
328		case GL_FLOAT:      return true;
329		default: UNREACHABLE(y.type);
330		}
331		break;
332	case GL_FLOAT_MAT3:
333		switch(y.type)
334		{
335		case GL_FLOAT_MAT4: return false;
336		case GL_FLOAT_MAT2: return false;
337		case GL_FLOAT_VEC4: return false;
338		case GL_FLOAT_MAT3: return true;
339		case GL_FLOAT_VEC3: return true;
340		case GL_FLOAT_VEC2: return true;
341		case GL_FLOAT:      return true;
342		default: UNREACHABLE(y.type);
343		}
344		break;
345	case GL_FLOAT_VEC3:
346		switch(y.type)
347		{
348		case GL_FLOAT_MAT4: return false;
349		case GL_FLOAT_MAT2: return false;
350		case GL_FLOAT_VEC4: return false;
351		case GL_FLOAT_MAT3: return false;
352		case GL_FLOAT_VEC3: return true;
353		case GL_FLOAT_VEC2: return true;
354		case GL_FLOAT:      return true;
355		default: UNREACHABLE(y.type);
356		}
357		break;
358	case GL_FLOAT_VEC2:
359		switch(y.type)
360		{
361		case GL_FLOAT_MAT4: return false;
362		case GL_FLOAT_MAT2: return false;
363		case GL_FLOAT_VEC4: return false;
364		case GL_FLOAT_MAT3: return false;
365		case GL_FLOAT_VEC3: return false;
366		case GL_FLOAT_VEC2: return true;
367		case GL_FLOAT:      return true;
368		default: UNREACHABLE(y.type);
369		}
370		break;
371	case GL_FLOAT: return false;
372	default: UNREACHABLE(x.type);
373	}
374
375	return false;
376}
377
378VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
379{
380	vertexShader = 0;
381}
382
383VertexShader::~VertexShader()
384{
385	delete vertexShader;
386}
387
388GLenum VertexShader::getType() const
389{
390	return GL_VERTEX_SHADER;
391}
392
393int VertexShader::getSemanticIndex(const std::string &attributeName) const
394{
395	if(!attributeName.empty())
396	{
397		for(const auto &attribute : activeAttributes)
398		{
399			if(attribute.name == attributeName)
400			{
401				return attribute.registerIndex;
402			}
403		}
404	}
405
406	return -1;
407}
408
409sw::Shader *VertexShader::getShader() const
410{
411	return vertexShader;
412}
413
414sw::VertexShader *VertexShader::getVertexShader() const
415{
416	return vertexShader;
417}
418
419void VertexShader::createShader()
420{
421	delete vertexShader;
422	vertexShader = new sw::VertexShader();
423}
424
425void VertexShader::deleteShader()
426{
427	delete vertexShader;
428	vertexShader = nullptr;
429}
430
431FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
432{
433	pixelShader = 0;
434}
435
436FragmentShader::~FragmentShader()
437{
438	delete pixelShader;
439}
440
441GLenum FragmentShader::getType() const
442{
443	return GL_FRAGMENT_SHADER;
444}
445
446sw::Shader *FragmentShader::getShader() const
447{
448	return pixelShader;
449}
450
451sw::PixelShader *FragmentShader::getPixelShader() const
452{
453	return pixelShader;
454}
455
456void FragmentShader::createShader()
457{
458	delete pixelShader;
459	pixelShader = new sw::PixelShader();
460}
461
462void FragmentShader::deleteShader()
463{
464	delete pixelShader;
465	pixelShader = nullptr;
466}
467
468}
469