• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Shader.cpp: Implements the gl::Shader class and its  derived classes
8 // VertexShader and FragmentShader. Implements GL shader objects and related
9 // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
10 
11 #include "libGLESv2/Shader.h"
12 
13 #include <string>
14 
15 #include "GLSLANG/Shaderlang.h"
16 #include "libGLESv2/main.h"
17 #include "libGLESv2/utilities.h"
18 
19 namespace gl
20 {
21 void *Shader::mFragmentCompiler = NULL;
22 void *Shader::mVertexCompiler = NULL;
23 
Shader(ResourceManager * manager,GLuint handle)24 Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
25 {
26     mSource = NULL;
27     mHlsl = NULL;
28     mInfoLog = NULL;
29 
30     // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
31     if (!mFragmentCompiler)
32     {
33         int result = ShInitialize();
34 
35         if (result)
36         {
37             ShBuiltInResources resources;
38             ShInitBuiltInResources(&resources);
39             Context *context = getContext();
40 
41             resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
42             resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
43             resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
44             resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
45             resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
46             resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
47             resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
48             resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
49             resources.OES_standard_derivatives = 1;
50 
51             mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
52             mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
53         }
54     }
55 
56     mRefCount = 0;
57     mDeleteStatus = false;
58 }
59 
~Shader()60 Shader::~Shader()
61 {
62     delete[] mSource;
63     delete[] mHlsl;
64     delete[] mInfoLog;
65 }
66 
getHandle() const67 GLuint Shader::getHandle() const
68 {
69     return mHandle;
70 }
71 
setSource(GLsizei count,const char ** string,const GLint * length)72 void Shader::setSource(GLsizei count, const char **string, const GLint *length)
73 {
74     delete[] mSource;
75     int totalLength = 0;
76 
77     for (int i = 0; i < count; i++)
78     {
79         if (length && length[i] >= 0)
80         {
81             totalLength += length[i];
82         }
83         else
84         {
85             totalLength += (int)strlen(string[i]);
86         }
87     }
88 
89     mSource = new char[totalLength + 1];
90     char *code = mSource;
91 
92     for (int i = 0; i < count; i++)
93     {
94         int stringLength;
95 
96         if (length && length[i] >= 0)
97         {
98             stringLength = length[i];
99         }
100         else
101         {
102             stringLength = (int)strlen(string[i]);
103         }
104 
105         strncpy(code, string[i], stringLength);
106         code += stringLength;
107     }
108 
109     mSource[totalLength] = '\0';
110 }
111 
getInfoLogLength() const112 int Shader::getInfoLogLength() const
113 {
114     if (!mInfoLog)
115     {
116         return 0;
117     }
118     else
119     {
120        return strlen(mInfoLog) + 1;
121     }
122 }
123 
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog)124 void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
125 {
126     int index = 0;
127 
128     if (mInfoLog)
129     {
130         while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
131         {
132             infoLog[index] = mInfoLog[index];
133             index++;
134         }
135     }
136 
137     if (bufSize)
138     {
139         infoLog[index] = '\0';
140     }
141 
142     if (length)
143     {
144         *length = index;
145     }
146 }
147 
getSourceLength() const148 int Shader::getSourceLength() const
149 {
150     if (!mSource)
151     {
152         return 0;
153     }
154     else
155     {
156        return strlen(mSource) + 1;
157     }
158 }
159 
getSource(GLsizei bufSize,GLsizei * length,char * source)160 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
161 {
162     int index = 0;
163 
164     if (mSource)
165     {
166         while (index < bufSize - 1 && index < (int)strlen(mSource))
167         {
168             source[index] = mSource[index];
169             index++;
170         }
171     }
172 
173     if (bufSize)
174     {
175         source[index] = '\0';
176     }
177 
178     if (length)
179     {
180         *length = index;
181     }
182 }
183 
isCompiled()184 bool Shader::isCompiled()
185 {
186     return mHlsl != NULL;
187 }
188 
getHLSL()189 const char *Shader::getHLSL()
190 {
191     return mHlsl;
192 }
193 
addRef()194 void Shader::addRef()
195 {
196     mRefCount++;
197 }
198 
release()199 void Shader::release()
200 {
201     mRefCount--;
202 
203     if (mRefCount == 0 && mDeleteStatus)
204     {
205         mResourceManager->deleteShader(mHandle);
206     }
207 }
208 
getRefCount() const209 unsigned int Shader::getRefCount() const
210 {
211     return mRefCount;
212 }
213 
isFlaggedForDeletion() const214 bool Shader::isFlaggedForDeletion() const
215 {
216     return mDeleteStatus;
217 }
218 
flagForDeletion()219 void Shader::flagForDeletion()
220 {
221     mDeleteStatus = true;
222 }
223 
releaseCompiler()224 void Shader::releaseCompiler()
225 {
226     ShDestruct(mFragmentCompiler);
227     ShDestruct(mVertexCompiler);
228 
229     mFragmentCompiler = NULL;
230     mVertexCompiler = NULL;
231 
232     ShFinalize();
233 }
234 
parseVaryings()235 void Shader::parseVaryings()
236 {
237     if (mHlsl)
238     {
239         const char *input = strstr(mHlsl, "// Varyings") + 12;
240 
241         while(true)
242         {
243             char varyingType[256];
244             char varyingName[256];
245 
246             int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
247 
248             if (matches != 2)
249             {
250                 break;
251             }
252 
253             char *array = strstr(varyingName, "[");
254             int size = 1;
255 
256             if (array)
257             {
258                 size = atoi(array + 1);
259                 *array = '\0';
260             }
261 
262             varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
263 
264             input = strstr(input, ";") + 2;
265         }
266 
267         mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
268         mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
269         mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
270         mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
271     }
272 }
273 
compileToHLSL(void * compiler)274 void Shader::compileToHLSL(void *compiler)
275 {
276     if (isCompiled() || !mSource)
277     {
278         return;
279     }
280 
281     TRACE("\n%s", mSource);
282 
283     delete[] mInfoLog;
284     mInfoLog = NULL;
285 
286     int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE);
287 
288     if (result)
289     {
290         int objCodeLen = 0;
291         ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
292         mHlsl = new char[objCodeLen];
293         ShGetObjectCode(compiler, mHlsl);
294 
295         TRACE("\n%s", mHlsl);
296     }
297     else
298     {
299         int infoLogLen = 0;
300         ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
301         mInfoLog = new char[infoLogLen];
302         ShGetInfoLog(compiler, mInfoLog);
303 
304         TRACE("\n%s", mInfoLog);
305     }
306 }
307 
parseType(const std::string & type)308 GLenum Shader::parseType(const std::string &type)
309 {
310     if (type == "float")
311     {
312         return GL_FLOAT;
313     }
314     else if (type == "float2")
315     {
316         return GL_FLOAT_VEC2;
317     }
318     else if (type == "float3")
319     {
320         return GL_FLOAT_VEC3;
321     }
322     else if (type == "float4")
323     {
324         return GL_FLOAT_VEC4;
325     }
326     else if (type == "float2x2")
327     {
328         return GL_FLOAT_MAT2;
329     }
330     else if (type == "float3x3")
331     {
332         return GL_FLOAT_MAT3;
333     }
334     else if (type == "float4x4")
335     {
336         return GL_FLOAT_MAT4;
337     }
338     else UNREACHABLE();
339 
340     return GL_NONE;
341 }
342 
343 // true if varying x has a higher priority in packing than y
compareVarying(const Varying & x,const Varying & y)344 bool Shader::compareVarying(const Varying &x, const Varying &y)
345 {
346     if(x.type == y.type)
347     {
348         return x.size > y.size;
349     }
350 
351     switch (x.type)
352     {
353       case GL_FLOAT_MAT4: return true;
354       case GL_FLOAT_MAT2:
355         switch(y.type)
356         {
357           case GL_FLOAT_MAT4: return false;
358           case GL_FLOAT_MAT2: return true;
359           case GL_FLOAT_VEC4: return true;
360           case GL_FLOAT_MAT3: return true;
361           case GL_FLOAT_VEC3: return true;
362           case GL_FLOAT_VEC2: return true;
363           case GL_FLOAT:      return true;
364           default: UNREACHABLE();
365         }
366         break;
367       case GL_FLOAT_VEC4:
368         switch(y.type)
369         {
370           case GL_FLOAT_MAT4: return false;
371           case GL_FLOAT_MAT2: return false;
372           case GL_FLOAT_VEC4: return true;
373           case GL_FLOAT_MAT3: return true;
374           case GL_FLOAT_VEC3: return true;
375           case GL_FLOAT_VEC2: return true;
376           case GL_FLOAT:      return true;
377           default: UNREACHABLE();
378         }
379         break;
380       case GL_FLOAT_MAT3:
381         switch(y.type)
382         {
383           case GL_FLOAT_MAT4: return false;
384           case GL_FLOAT_MAT2: return false;
385           case GL_FLOAT_VEC4: return false;
386           case GL_FLOAT_MAT3: return true;
387           case GL_FLOAT_VEC3: return true;
388           case GL_FLOAT_VEC2: return true;
389           case GL_FLOAT:      return true;
390           default: UNREACHABLE();
391         }
392         break;
393       case GL_FLOAT_VEC3:
394         switch(y.type)
395         {
396           case GL_FLOAT_MAT4: return false;
397           case GL_FLOAT_MAT2: return false;
398           case GL_FLOAT_VEC4: return false;
399           case GL_FLOAT_MAT3: return false;
400           case GL_FLOAT_VEC3: return true;
401           case GL_FLOAT_VEC2: return true;
402           case GL_FLOAT:      return true;
403           default: UNREACHABLE();
404         }
405         break;
406       case GL_FLOAT_VEC2:
407         switch(y.type)
408         {
409           case GL_FLOAT_MAT4: return false;
410           case GL_FLOAT_MAT2: return false;
411           case GL_FLOAT_VEC4: return false;
412           case GL_FLOAT_MAT3: return false;
413           case GL_FLOAT_VEC3: return false;
414           case GL_FLOAT_VEC2: return true;
415           case GL_FLOAT:      return true;
416           default: UNREACHABLE();
417         }
418         break;
419       case GL_FLOAT: return false;
420       default: UNREACHABLE();
421     }
422 
423     return false;
424 }
425 
VertexShader(ResourceManager * manager,GLuint handle)426 VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
427 {
428 }
429 
~VertexShader()430 VertexShader::~VertexShader()
431 {
432 }
433 
getType()434 GLenum VertexShader::getType()
435 {
436     return GL_VERTEX_SHADER;
437 }
438 
compile()439 void VertexShader::compile()
440 {
441     compileToHLSL(mVertexCompiler);
442     parseAttributes();
443     parseVaryings();
444 }
445 
getSemanticIndex(const std::string & attributeName)446 int VertexShader::getSemanticIndex(const std::string &attributeName)
447 {
448     if (!attributeName.empty())
449     {
450         int semanticIndex = 0;
451         for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
452         {
453             if (attribute->name == attributeName)
454             {
455                 return semanticIndex;
456             }
457 
458             semanticIndex += VariableRowCount(attribute->type);
459         }
460     }
461 
462     return -1;
463 }
464 
parseAttributes()465 void VertexShader::parseAttributes()
466 {
467     if (mHlsl)
468     {
469         const char *input = strstr(mHlsl, "// Attributes") + 14;
470 
471         while(true)
472         {
473             char attributeType[256];
474             char attributeName[256];
475 
476             int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
477 
478             if (matches != 2)
479             {
480                 break;
481             }
482 
483             mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
484 
485             input = strstr(input, ";") + 2;
486         }
487     }
488 }
489 
FragmentShader(ResourceManager * manager,GLuint handle)490 FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
491 {
492 }
493 
~FragmentShader()494 FragmentShader::~FragmentShader()
495 {
496 }
497 
getType()498 GLenum FragmentShader::getType()
499 {
500     return GL_FRAGMENT_SHADER;
501 }
502 
compile()503 void FragmentShader::compile()
504 {
505     compileToHLSL(mFragmentCompiler);
506     parseVaryings();
507     varyings.sort(compareVarying);
508 }
509 }
510