Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / Program.cpp
1 //
2 // Copyright (c) 2002-2014 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 // Program.cpp: Implements the gl::Program class. Implements GL program objects
8 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
10 #include "libGLESv2/Program.h"
11 #include "libGLESv2/ProgramBinary.h"
12 #include "libGLESv2/ResourceManager.h"
13 #include "libGLESv2/renderer/Renderer.h"
14
15 namespace gl
16 {
17 const char * const g_fakepath = "C:\\fakepath";
18
19 AttributeBindings::AttributeBindings()
20 {
21 }
22
23 AttributeBindings::~AttributeBindings()
24 {
25 }
26
27 InfoLog::InfoLog() : mInfoLog(NULL)
28 {
29 }
30
31 InfoLog::~InfoLog()
32 {
33     delete[] mInfoLog;
34 }
35
36
37 int InfoLog::getLength() const
38 {
39     if (!mInfoLog)
40     {
41         return 0;
42     }
43     else
44     {
45        return strlen(mInfoLog) + 1;
46     }
47 }
48
49 void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
50 {
51     int index = 0;
52
53     if (bufSize > 0)
54     {
55         if (mInfoLog)
56         {
57             index = std::min(bufSize - 1, (int)strlen(mInfoLog));
58             memcpy(infoLog, mInfoLog, index);
59         }
60
61         infoLog[index] = '\0';
62     }
63
64     if (length)
65     {
66         *length = index;
67     }
68 }
69
70 // append a santized message to the program info log.
71 // The D3D compiler includes a fake file path in some of the warning or error 
72 // messages, so lets remove all occurrences of this fake file path from the log.
73 void InfoLog::appendSanitized(const char *message)
74 {
75     std::string msg(message);
76
77     size_t found;
78     do
79     {
80         found = msg.find(g_fakepath);
81         if (found != std::string::npos)
82         {
83             msg.erase(found, strlen(g_fakepath));
84         }
85     }
86     while (found != std::string::npos);
87
88     append("%s", msg.c_str());
89 }
90
91 void InfoLog::append(const char *format, ...)
92 {
93     if (!format)
94     {
95         return;
96     }
97
98     va_list vararg;
99     va_start(vararg, format);
100     size_t infoLength = vsnprintf(NULL, 0, format, vararg);
101     va_end(vararg);
102
103     char *logPointer = NULL;
104
105     if (!mInfoLog)
106     {
107         mInfoLog = new char[infoLength + 2];
108         logPointer = mInfoLog;
109     }
110     else
111     {
112         size_t currentlogLength = strlen(mInfoLog);
113         char *newLog = new char[currentlogLength + infoLength + 2];
114         strcpy(newLog, mInfoLog);
115
116         delete[] mInfoLog;
117         mInfoLog = newLog;
118
119         logPointer = mInfoLog + currentlogLength;
120     }
121
122     va_start(vararg, format);
123     vsnprintf(logPointer, infoLength, format, vararg);
124     va_end(vararg);
125
126     logPointer[infoLength] = 0;
127     strcpy(logPointer + infoLength, "\n");
128 }
129
130 void InfoLog::reset()
131 {
132     if (mInfoLog)
133     {
134         delete [] mInfoLog;
135         mInfoLog = NULL;
136     }
137 }
138
139 Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
140 {
141     mFragmentShader = NULL;
142     mVertexShader = NULL;
143     mProgramBinary.set(NULL);
144     mDeleteStatus = false;
145     mLinked = false;
146     mRefCount = 0;
147     mRenderer = renderer;
148
149     resetUniformBlockBindings();
150 }
151
152 Program::~Program()
153 {
154     unlink(true);
155
156     if (mVertexShader != NULL)
157     {
158         mVertexShader->release();
159     }
160
161     if (mFragmentShader != NULL)
162     {
163         mFragmentShader->release();
164     }
165 }
166
167 bool Program::attachShader(Shader *shader)
168 {
169     if (shader->getType() == GL_VERTEX_SHADER)
170     {
171         if (mVertexShader)
172         {
173             return false;
174         }
175
176         mVertexShader = shader;
177         mVertexShader->addRef();
178     }
179     else if (shader->getType() == GL_FRAGMENT_SHADER)
180     {
181         if (mFragmentShader)
182         {
183             return false;
184         }
185
186         mFragmentShader = shader;
187         mFragmentShader->addRef();
188     }
189     else UNREACHABLE();
190
191     return true;
192 }
193
194 bool Program::detachShader(Shader *shader)
195 {
196     if (shader->getType() == GL_VERTEX_SHADER)
197     {
198         if (mVertexShader != shader)
199         {
200             return false;
201         }
202
203         mVertexShader->release();
204         mVertexShader = NULL;
205     }
206     else if (shader->getType() == GL_FRAGMENT_SHADER)
207     {
208         if (mFragmentShader != shader)
209         {
210             return false;
211         }
212
213         mFragmentShader->release();
214         mFragmentShader = NULL;
215     }
216     else UNREACHABLE();
217
218     return true;
219 }
220
221 int Program::getAttachedShadersCount() const
222 {
223     return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
224 }
225
226 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
227 {
228     if (index < MAX_VERTEX_ATTRIBS)
229     {
230         for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
231         {
232             mAttributeBinding[i].erase(name);
233         }
234
235         mAttributeBinding[index].insert(name);
236     }
237 }
238
239 void Program::bindAttributeLocation(GLuint index, const char *name)
240 {
241     mAttributeBindings.bindAttributeLocation(index, name);
242 }
243
244 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
245 // compiling them into binaries, determining the attribute mappings, and collecting
246 // a list of uniforms
247 Error Program::link(const Caps &caps)
248 {
249     unlink(false);
250
251     mInfoLog.reset();
252     resetUniformBlockBindings();
253
254     mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
255     LinkResult result = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader,
256                                              mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps);
257     if (result.error.isError())
258     {
259         return result.error;
260     }
261
262     mLinked = result.linkSuccess;
263     return gl::Error(GL_NO_ERROR);
264 }
265
266 int AttributeBindings::getAttributeBinding(const std::string &name) const
267 {
268     for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
269     {
270         if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
271         {
272             return location;
273         }
274     }
275
276     return -1;
277 }
278
279 // Returns the program object to an unlinked state, before re-linking, or at destruction
280 void Program::unlink(bool destroy)
281 {
282     if (destroy)   // Object being destructed
283     {
284         if (mFragmentShader)
285         {
286             mFragmentShader->release();
287             mFragmentShader = NULL;
288         }
289
290         if (mVertexShader)
291         {
292             mVertexShader->release();
293             mVertexShader = NULL;
294         }
295     }
296
297     mProgramBinary.set(NULL);
298     mLinked = false;
299 }
300
301 bool Program::isLinked()
302 {
303     return mLinked;
304 }
305
306 ProgramBinary* Program::getProgramBinary() const
307 {
308     return mProgramBinary.get();
309 }
310
311 Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length)
312 {
313     unlink(false);
314
315     mInfoLog.reset();
316
317     mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
318     LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length);
319     if (result.error.isError())
320     {
321         mProgramBinary.set(NULL);
322         return result.error;
323     }
324
325     mLinked = result.linkSuccess;
326     return Error(GL_NO_ERROR);
327 }
328
329 void Program::release()
330 {
331     mRefCount--;
332
333     if (mRefCount == 0 && mDeleteStatus)
334     {
335         mResourceManager->deleteProgram(mHandle);
336     }
337 }
338
339 void Program::addRef()
340 {
341     mRefCount++;
342 }
343
344 unsigned int Program::getRefCount() const
345 {
346     return mRefCount;
347 }
348
349 GLint Program::getProgramBinaryLength() const
350 {
351     ProgramBinary *programBinary = mProgramBinary.get();
352     if (programBinary)
353     {
354         return programBinary->getLength();
355     }
356     else
357     {
358         return 0;
359     }
360 }
361
362 int Program::getInfoLogLength() const
363 {
364     return mInfoLog.getLength();
365 }
366
367 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
368 {
369     return mInfoLog.getLog(bufSize, length, infoLog);
370 }
371
372 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
373 {
374     int total = 0;
375
376     if (mVertexShader)
377     {
378         if (total < maxCount)
379         {
380             shaders[total] = mVertexShader->getHandle();
381         }
382
383         total++;
384     }
385
386     if (mFragmentShader)
387     {
388         if (total < maxCount)
389         {
390             shaders[total] = mFragmentShader->getHandle();
391         }
392
393         total++;
394     }
395
396     if (count)
397     {
398         *count = total;
399     }
400 }
401
402 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
403 {
404     ProgramBinary *programBinary = getProgramBinary();
405     if (programBinary)
406     {
407         programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
408     }
409     else
410     {
411         if (bufsize > 0)
412         {
413             name[0] = '\0';
414         }
415         
416         if (length)
417         {
418             *length = 0;
419         }
420
421         *type = GL_NONE;
422         *size = 1;
423     }
424 }
425
426 GLint Program::getActiveAttributeCount()
427 {
428     ProgramBinary *programBinary = getProgramBinary();
429     if (programBinary)
430     {
431         return programBinary->getActiveAttributeCount();
432     }
433     else
434     {
435         return 0;
436     }
437 }
438
439 GLint Program::getActiveAttributeMaxLength()
440 {
441     ProgramBinary *programBinary = getProgramBinary();
442     if (programBinary)
443     {
444         return programBinary->getActiveAttributeMaxLength();
445     }
446     else
447     {
448         return 0;
449     }
450 }
451
452 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
453 {
454     ProgramBinary *programBinary = getProgramBinary();
455     if (programBinary)
456     {
457         return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
458     }
459     else
460     {
461         if (bufsize > 0)
462         {
463             name[0] = '\0';
464         }
465
466         if (length)
467         {
468             *length = 0;
469         }
470
471         *size = 0;
472         *type = GL_NONE;
473     }
474 }
475
476 GLint Program::getActiveUniformCount()
477 {
478     ProgramBinary *programBinary = getProgramBinary();
479     if (programBinary)
480     {
481         return programBinary->getActiveUniformCount();
482     }
483     else
484     {
485         return 0;
486     }
487 }
488
489 GLint Program::getActiveUniformMaxLength()
490 {
491     ProgramBinary *programBinary = getProgramBinary();
492     if (programBinary)
493     {
494         return programBinary->getActiveUniformMaxLength();
495     }
496     else
497     {
498         return 0;
499     }
500 }
501
502 void Program::flagForDeletion()
503 {
504     mDeleteStatus = true;
505 }
506
507 bool Program::isFlaggedForDeletion() const
508 {
509     return mDeleteStatus;
510 }
511
512 void Program::validate(const Caps &caps)
513 {
514     mInfoLog.reset();
515
516     ProgramBinary *programBinary = getProgramBinary();
517     if (isLinked() && programBinary)
518     {
519         programBinary->validate(mInfoLog, caps);
520     }
521     else
522     {
523         mInfoLog.append("Program has not been successfully linked.");
524     }
525 }
526
527 bool Program::isValidated() const
528 {
529     ProgramBinary *programBinary = mProgramBinary.get();
530     if (programBinary)
531     {
532         return programBinary->isValidated();
533     }
534     else
535     {
536         return false;
537     }
538 }
539
540 GLint Program::getActiveUniformBlockCount()
541 {
542     ProgramBinary *programBinary = getProgramBinary();
543     if (programBinary)
544     {
545         return static_cast<GLint>(programBinary->getActiveUniformBlockCount());
546     }
547     else
548     {
549         return 0;
550     }
551 }
552
553 GLint Program::getActiveUniformBlockMaxLength()
554 {
555     ProgramBinary *programBinary = getProgramBinary();
556     if (programBinary)
557     {
558         return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength());
559     }
560     else
561     {
562         return 0;
563     }
564 }
565
566 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
567 {
568     mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
569 }
570
571 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
572 {
573     return mUniformBlockBindings[uniformBlockIndex];
574 }
575
576 void Program::resetUniformBlockBindings()
577 {
578     for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++)
579     {
580         mUniformBlockBindings[blockId] = 0;
581     }
582 }
583
584 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
585 {
586     mTransformFeedbackVaryings.resize(count);
587     for (GLsizei i = 0; i < count; i++)
588     {
589         mTransformFeedbackVaryings[i] = varyings[i];
590     }
591
592     mTransformFeedbackBufferMode = bufferMode;
593 }
594
595 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
596 {
597     ProgramBinary *programBinary = getProgramBinary();
598     if (programBinary && index < programBinary->getTransformFeedbackVaryingCount())
599     {
600         const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index);
601         GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
602         if (length)
603         {
604             *length = lastNameIdx;
605         }
606         if (size)
607         {
608             *size = varying.size;
609         }
610         if (type)
611         {
612             *type = varying.type;
613         }
614         if (name)
615         {
616             memcpy(name, varying.name.c_str(), lastNameIdx);
617             name[lastNameIdx] = '\0';
618         }
619     }
620 }
621
622 GLsizei Program::getTransformFeedbackVaryingCount() const
623 {
624     ProgramBinary *programBinary = getProgramBinary();
625     if (programBinary)
626     {
627         return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount());
628     }
629     else
630     {
631         return 0;
632     }
633 }
634
635 GLsizei Program::getTransformFeedbackVaryingMaxLength() const
636 {
637     ProgramBinary *programBinary = getProgramBinary();
638     if (programBinary)
639     {
640         GLsizei maxSize = 0;
641         for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++)
642         {
643             const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i);
644             maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
645         }
646
647         return maxSize;
648     }
649     else
650     {
651         return 0;
652     }
653 }
654
655 GLenum Program::getTransformFeedbackBufferMode() const
656 {
657     ProgramBinary *programBinary = getProgramBinary();
658     if (programBinary)
659     {
660         return programBinary->getTransformFeedbackBufferMode();
661     }
662     else
663     {
664         return mTransformFeedbackBufferMode;
665     }
666 }
667
668 }