initial import
[vuplus_webkit] / Source / ThirdParty / ANGLE / src / libGLESv2 / Shader.cpp
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
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 = context->getMaximumVertexTextureImageUnits();
45             resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits();
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, SH_HLSL_OUTPUT, &resources);
52             mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
53         }
54     }
55
56     mRefCount = 0;
57     mDeleteStatus = false;
58 }
59
60 Shader::~Shader()
61 {
62     delete[] mSource;
63     delete[] mHlsl;
64     delete[] mInfoLog;
65 }
66
67 GLuint Shader::getHandle() const
68 {
69     return mHandle;
70 }
71
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
112 int Shader::getInfoLogLength() const
113 {
114     if (!mInfoLog)
115     {
116         return 0;
117     }
118     else
119     {
120        return strlen(mInfoLog) + 1;
121     }
122 }
123
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
148 int Shader::getSourceLength() const
149 {
150     if (!mSource)
151     {
152         return 0;
153     }
154     else
155     {
156        return strlen(mSource) + 1;
157     }
158 }
159
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
184 bool Shader::isCompiled()
185 {
186     return mHlsl != NULL;
187 }
188
189 const char *Shader::getHLSL()
190 {
191     return mHlsl;
192 }
193
194 void Shader::addRef()
195 {
196     mRefCount++;
197 }
198
199 void Shader::release()
200 {
201     mRefCount--;
202
203     if (mRefCount == 0 && mDeleteStatus)
204     {
205         mResourceManager->deleteShader(mHandle);
206     }
207 }
208
209 unsigned int Shader::getRefCount() const
210 {
211     return mRefCount;
212 }
213
214 bool Shader::isFlaggedForDeletion() const
215 {
216     return mDeleteStatus;
217 }
218
219 void Shader::flagForDeletion()
220 {
221     mDeleteStatus = true;
222 }
223
224 void Shader::releaseCompiler()
225 {
226     ShDestruct(mFragmentCompiler);
227     ShDestruct(mVertexCompiler);
228
229     mFragmentCompiler = NULL;
230     mVertexCompiler = NULL;
231
232     ShFinalize();
233 }
234
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
274 void Shader::compileToHLSL(void *compiler)
275 {
276     if (isCompiled() || !mSource)
277     {
278         return;
279     }
280
281     delete[] mInfoLog;
282     mInfoLog = NULL;
283
284     int compileOptions = SH_OBJECT_CODE;
285     std::string sourcePath;
286     if (perfActive())
287     {
288         sourcePath = getTempPath();
289         writeFile(sourcePath.c_str(), mSource, strlen(mSource));
290         compileOptions |= SH_LINE_DIRECTIVES;
291     }
292
293     int result;
294     if (sourcePath.empty())
295     {
296         result = ShCompile(compiler, &mSource, 1, compileOptions);
297     }
298     else
299     {
300         const char* sourceStrings[2] =
301         {
302             sourcePath.c_str(),
303             mSource
304         };
305
306         result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
307     }
308
309     if (result)
310     {
311         int objCodeLen = 0;
312         ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
313         mHlsl = new char[objCodeLen];
314         ShGetObjectCode(compiler, mHlsl);
315     }
316     else
317     {
318         int infoLogLen = 0;
319         ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
320         mInfoLog = new char[infoLogLen];
321         ShGetInfoLog(compiler, mInfoLog);
322
323         TRACE("\n%s", mInfoLog);
324     }
325 }
326
327 GLenum Shader::parseType(const std::string &type)
328 {
329     if (type == "float")
330     {
331         return GL_FLOAT;
332     }
333     else if (type == "float2")
334     {
335         return GL_FLOAT_VEC2;
336     }
337     else if (type == "float3")
338     {
339         return GL_FLOAT_VEC3;
340     }
341     else if (type == "float4")
342     {
343         return GL_FLOAT_VEC4;
344     }
345     else if (type == "float2x2")
346     {
347         return GL_FLOAT_MAT2;
348     }
349     else if (type == "float3x3")
350     {
351         return GL_FLOAT_MAT3;
352     }
353     else if (type == "float4x4")
354     {
355         return GL_FLOAT_MAT4;
356     }
357     else UNREACHABLE();
358
359     return GL_NONE;
360 }
361
362 // true if varying x has a higher priority in packing than y
363 bool Shader::compareVarying(const Varying &x, const Varying &y)
364 {
365     if(x.type == y.type)
366     {
367         return x.size > y.size;
368     }
369
370     switch (x.type)
371     {
372       case GL_FLOAT_MAT4: return true;
373       case GL_FLOAT_MAT2:
374         switch(y.type)
375         {
376           case GL_FLOAT_MAT4: return false;
377           case GL_FLOAT_MAT2: return true;
378           case GL_FLOAT_VEC4: return true;
379           case GL_FLOAT_MAT3: return true;
380           case GL_FLOAT_VEC3: return true;
381           case GL_FLOAT_VEC2: return true;
382           case GL_FLOAT:      return true;
383           default: UNREACHABLE();
384         }
385         break;
386       case GL_FLOAT_VEC4:
387         switch(y.type)
388         {
389           case GL_FLOAT_MAT4: return false;
390           case GL_FLOAT_MAT2: return false;
391           case GL_FLOAT_VEC4: return true;
392           case GL_FLOAT_MAT3: return true;
393           case GL_FLOAT_VEC3: return true;
394           case GL_FLOAT_VEC2: return true;
395           case GL_FLOAT:      return true;
396           default: UNREACHABLE();
397         }
398         break;
399       case GL_FLOAT_MAT3:
400         switch(y.type)
401         {
402           case GL_FLOAT_MAT4: return false;
403           case GL_FLOAT_MAT2: return false;
404           case GL_FLOAT_VEC4: return false;
405           case GL_FLOAT_MAT3: return true;
406           case GL_FLOAT_VEC3: return true;
407           case GL_FLOAT_VEC2: return true;
408           case GL_FLOAT:      return true;
409           default: UNREACHABLE();
410         }
411         break;
412       case GL_FLOAT_VEC3:
413         switch(y.type)
414         {
415           case GL_FLOAT_MAT4: return false;
416           case GL_FLOAT_MAT2: return false;
417           case GL_FLOAT_VEC4: return false;
418           case GL_FLOAT_MAT3: return false;
419           case GL_FLOAT_VEC3: return true;
420           case GL_FLOAT_VEC2: return true;
421           case GL_FLOAT:      return true;
422           default: UNREACHABLE();
423         }
424         break;
425       case GL_FLOAT_VEC2:
426         switch(y.type)
427         {
428           case GL_FLOAT_MAT4: return false;
429           case GL_FLOAT_MAT2: return false;
430           case GL_FLOAT_VEC4: return false;
431           case GL_FLOAT_MAT3: return false;
432           case GL_FLOAT_VEC3: return false;
433           case GL_FLOAT_VEC2: return true;
434           case GL_FLOAT:      return true;
435           default: UNREACHABLE();
436         }
437         break;
438       case GL_FLOAT: return false;
439       default: UNREACHABLE();
440     }
441
442     return false;
443 }
444
445 VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
446 {
447 }
448
449 VertexShader::~VertexShader()
450 {
451 }
452
453 GLenum VertexShader::getType()
454 {
455     return GL_VERTEX_SHADER;
456 }
457
458 void VertexShader::compile()
459 {
460     compileToHLSL(mVertexCompiler);
461     parseAttributes();
462     parseVaryings();
463 }
464
465 int VertexShader::getSemanticIndex(const std::string &attributeName)
466 {
467     if (!attributeName.empty())
468     {
469         int semanticIndex = 0;
470         for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
471         {
472             if (attribute->name == attributeName)
473             {
474                 return semanticIndex;
475             }
476
477             semanticIndex += VariableRowCount(attribute->type);
478         }
479     }
480
481     return -1;
482 }
483
484 void VertexShader::parseAttributes()
485 {
486     if (mHlsl)
487     {
488         const char *input = strstr(mHlsl, "// Attributes") + 14;
489
490         while(true)
491         {
492             char attributeType[256];
493             char attributeName[256];
494
495             int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
496
497             if (matches != 2)
498             {
499                 break;
500             }
501
502             mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
503
504             input = strstr(input, ";") + 2;
505         }
506     }
507 }
508
509 FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
510 {
511 }
512
513 FragmentShader::~FragmentShader()
514 {
515 }
516
517 GLenum FragmentShader::getType()
518 {
519     return GL_FRAGMENT_SHADER;
520 }
521
522 void FragmentShader::compile()
523 {
524     compileToHLSL(mFragmentCompiler);
525     parseVaryings();
526     varyings.sort(compareVarying);
527 }
528 }