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
19namespace gl
20{
21void *Shader::mFragmentCompiler = NULL;
22void *Shader::mVertexCompiler = NULL;
23
24Shader::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
60Shader::~Shader()
61{
62    delete[] mSource;
63    delete[] mHlsl;
64    delete[] mInfoLog;
65}
66
67GLuint Shader::getHandle() const
68{
69    return mHandle;
70}
71
72void 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
112int Shader::getInfoLogLength() const
113{
114    if (!mInfoLog)
115    {
116        return 0;
117    }
118    else
119    {
120       return strlen(mInfoLog) + 1;
121    }
122}
123
124void 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
148int Shader::getSourceLength() const
149{
150    if (!mSource)
151    {
152        return 0;
153    }
154    else
155    {
156       return strlen(mSource) + 1;
157    }
158}
159
160void 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
184bool Shader::isCompiled()
185{
186    return mHlsl != NULL;
187}
188
189const char *Shader::getHLSL()
190{
191    return mHlsl;
192}
193
194void Shader::addRef()
195{
196    mRefCount++;
197}
198
199void Shader::release()
200{
201    mRefCount--;
202
203    if (mRefCount == 0 && mDeleteStatus)
204    {
205        mResourceManager->deleteShader(mHandle);
206    }
207}
208
209unsigned int Shader::getRefCount() const
210{
211    return mRefCount;
212}
213
214bool Shader::isFlaggedForDeletion() const
215{
216    return mDeleteStatus;
217}
218
219void Shader::flagForDeletion()
220{
221    mDeleteStatus = true;
222}
223
224void Shader::releaseCompiler()
225{
226    ShDestruct(mFragmentCompiler);
227    ShDestruct(mVertexCompiler);
228
229    mFragmentCompiler = NULL;
230    mVertexCompiler = NULL;
231
232    ShFinalize();
233}
234
235void 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
274void 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
308GLenum 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
344bool 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
426VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
427{
428}
429
430VertexShader::~VertexShader()
431{
432}
433
434GLenum VertexShader::getType()
435{
436    return GL_VERTEX_SHADER;
437}
438
439void VertexShader::compile()
440{
441    compileToHLSL(mVertexCompiler);
442    parseAttributes();
443    parseVaryings();
444}
445
446int 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
465void 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
490FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
491{
492}
493
494FragmentShader::~FragmentShader()
495{
496}
497
498GLenum FragmentShader::getType()
499{
500    return GL_FRAGMENT_SHADER;
501}
502
503void FragmentShader::compile()
504{
505    compileToHLSL(mFragmentCompiler);
506    parseVaryings();
507    varyings.sort(compareVarying);
508}
509}
510