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 | |
27 | namespace es2 |
28 | { |
29 | std::mutex Shader::mutex; |
30 | bool Shader::compilerInitialized = false; |
31 | |
32 | Shader::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 | |
42 | Shader::~Shader() |
43 | { |
44 | delete[] mSource; |
45 | } |
46 | |
47 | GLuint Shader::getName() const |
48 | { |
49 | return mHandle; |
50 | } |
51 | |
52 | void 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 | |
92 | size_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 | |
104 | void 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 | |
125 | size_t Shader::getSourceLength() const |
126 | { |
127 | if(!mSource) |
128 | { |
129 | return 0; |
130 | } |
131 | else |
132 | { |
133 | return strlen(mSource) + 1; |
134 | } |
135 | } |
136 | |
137 | void 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 | |
158 | TranslatorASM *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 | |
199 | void Shader::clear() |
200 | { |
201 | infoLog.clear(); |
202 | |
203 | varyings.clear(); |
204 | activeUniforms.clear(); |
205 | activeAttributes.clear(); |
206 | } |
207 | |
208 | void 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 | |
265 | bool Shader::isCompiled() |
266 | { |
267 | return getShader() != 0; |
268 | } |
269 | |
270 | void Shader::addRef() |
271 | { |
272 | mRefCount++; |
273 | } |
274 | |
275 | void Shader::release() |
276 | { |
277 | mRefCount--; |
278 | |
279 | if(mRefCount == 0 && mDeleteStatus) |
280 | { |
281 | mResourceManager->deleteShader(mHandle); |
282 | } |
283 | } |
284 | |
285 | unsigned int Shader::getRefCount() const |
286 | { |
287 | return mRefCount; |
288 | } |
289 | |
290 | bool Shader::isFlaggedForDeletion() const |
291 | { |
292 | return mDeleteStatus; |
293 | } |
294 | |
295 | void Shader::flagForDeletion() |
296 | { |
297 | mDeleteStatus = true; |
298 | } |
299 | |
300 | void 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 |
310 | bool 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 | |
392 | VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) |
393 | { |
394 | vertexShader = 0; |
395 | } |
396 | |
397 | VertexShader::~VertexShader() |
398 | { |
399 | delete vertexShader; |
400 | } |
401 | |
402 | GLenum VertexShader::getType() const |
403 | { |
404 | return GL_VERTEX_SHADER; |
405 | } |
406 | |
407 | int 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 | |
423 | sw::Shader *VertexShader::getShader() const |
424 | { |
425 | return vertexShader; |
426 | } |
427 | |
428 | sw::VertexShader *VertexShader::getVertexShader() const |
429 | { |
430 | return vertexShader; |
431 | } |
432 | |
433 | void VertexShader::createShader() |
434 | { |
435 | delete vertexShader; |
436 | vertexShader = new sw::VertexShader(); |
437 | } |
438 | |
439 | void VertexShader::deleteShader() |
440 | { |
441 | delete vertexShader; |
442 | vertexShader = nullptr; |
443 | } |
444 | |
445 | FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle) |
446 | { |
447 | pixelShader = 0; |
448 | } |
449 | |
450 | FragmentShader::~FragmentShader() |
451 | { |
452 | delete pixelShader; |
453 | } |
454 | |
455 | GLenum FragmentShader::getType() const |
456 | { |
457 | return GL_FRAGMENT_SHADER; |
458 | } |
459 | |
460 | sw::Shader *FragmentShader::getShader() const |
461 | { |
462 | return pixelShader; |
463 | } |
464 | |
465 | sw::PixelShader *FragmentShader::getPixelShader() const |
466 | { |
467 | return pixelShader; |
468 | } |
469 | |
470 | void FragmentShader::createShader() |
471 | { |
472 | delete pixelShader; |
473 | pixelShader = new sw::PixelShader(); |
474 | } |
475 | |
476 | void FragmentShader::deleteShader() |
477 | { |
478 | delete pixelShader; |
479 | pixelShader = nullptr; |
480 | } |
481 | |
482 | } |
483 | |