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