1#include "precompiled.h"
2//
3// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
11#include "libGLESv2/Program.h"
12#include "libGLESv2/ProgramBinary.h"
13#include "libGLESv2/ResourceManager.h"
14
15namespace gl
16{
17const char * const g_fakepath = "C:\\fakepath";
18
19AttributeBindings::AttributeBindings()
20{
21}
22
23AttributeBindings::~AttributeBindings()
24{
25}
26
27InfoLog::InfoLog() : mInfoLog(NULL)
28{
29}
30
31InfoLog::~InfoLog()
32{
33    delete[] mInfoLog;
34}
35
36
37int InfoLog::getLength() const
38{
39    if (!mInfoLog)
40    {
41        return 0;
42    }
43    else
44    {
45       return strlen(mInfoLog) + 1;
46    }
47}
48
49void 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.
73void 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
91void InfoLog::append(const char *format, ...)
92{
93    if (!format)
94    {
95        return;
96    }
97
98    char info[1024];
99
100    va_list vararg;
101    va_start(vararg, format);
102    vsnprintf(info, sizeof(info), format, vararg);
103    va_end(vararg);
104
105    size_t infoLength = strlen(info);
106
107    if (!mInfoLog)
108    {
109        mInfoLog = new char[infoLength + 2];
110        strcpy(mInfoLog, info);
111        strcpy(mInfoLog + infoLength, "\n");
112    }
113    else
114    {
115        size_t logLength = strlen(mInfoLog);
116        char *newLog = new char[logLength + infoLength + 2];
117        strcpy(newLog, mInfoLog);
118        strcpy(newLog + logLength, info);
119        strcpy(newLog + logLength + infoLength, "\n");
120
121        delete[] mInfoLog;
122        mInfoLog = newLog;
123    }
124}
125
126void InfoLog::reset()
127{
128    if (mInfoLog)
129    {
130        delete [] mInfoLog;
131        mInfoLog = NULL;
132    }
133}
134
135Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
136{
137    mFragmentShader = NULL;
138    mVertexShader = NULL;
139    mProgramBinary.set(NULL);
140    mDeleteStatus = false;
141    mLinked = false;
142    mRefCount = 0;
143    mRenderer = renderer;
144}
145
146Program::~Program()
147{
148    unlink(true);
149
150    if (mVertexShader != NULL)
151    {
152        mVertexShader->release();
153    }
154
155    if (mFragmentShader != NULL)
156    {
157        mFragmentShader->release();
158    }
159}
160
161bool Program::attachShader(Shader *shader)
162{
163    if (shader->getType() == GL_VERTEX_SHADER)
164    {
165        if (mVertexShader)
166        {
167            return false;
168        }
169
170        mVertexShader = (VertexShader*)shader;
171        mVertexShader->addRef();
172    }
173    else if (shader->getType() == GL_FRAGMENT_SHADER)
174    {
175        if (mFragmentShader)
176        {
177            return false;
178        }
179
180        mFragmentShader = (FragmentShader*)shader;
181        mFragmentShader->addRef();
182    }
183    else UNREACHABLE();
184
185    return true;
186}
187
188bool Program::detachShader(Shader *shader)
189{
190    if (shader->getType() == GL_VERTEX_SHADER)
191    {
192        if (mVertexShader != shader)
193        {
194            return false;
195        }
196
197        mVertexShader->release();
198        mVertexShader = NULL;
199    }
200    else if (shader->getType() == GL_FRAGMENT_SHADER)
201    {
202        if (mFragmentShader != shader)
203        {
204            return false;
205        }
206
207        mFragmentShader->release();
208        mFragmentShader = NULL;
209    }
210    else UNREACHABLE();
211
212    return true;
213}
214
215int Program::getAttachedShadersCount() const
216{
217    return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
218}
219
220void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
221{
222    if (index < MAX_VERTEX_ATTRIBS)
223    {
224        for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
225        {
226            mAttributeBinding[i].erase(name);
227        }
228
229        mAttributeBinding[index].insert(name);
230    }
231}
232
233void Program::bindAttributeLocation(GLuint index, const char *name)
234{
235    mAttributeBindings.bindAttributeLocation(index, name);
236}
237
238// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
239// compiling them into binaries, determining the attribute mappings, and collecting
240// a list of uniforms
241bool Program::link()
242{
243    unlink(false);
244
245    mInfoLog.reset();
246
247    mProgramBinary.set(new ProgramBinary(mRenderer));
248    mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
249
250    return mLinked;
251}
252
253int AttributeBindings::getAttributeBinding(const std::string &name) const
254{
255    for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
256    {
257        if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
258        {
259            return location;
260        }
261    }
262
263    return -1;
264}
265
266// Returns the program object to an unlinked state, before re-linking, or at destruction
267void Program::unlink(bool destroy)
268{
269    if (destroy)   // Object being destructed
270    {
271        if (mFragmentShader)
272        {
273            mFragmentShader->release();
274            mFragmentShader = NULL;
275        }
276
277        if (mVertexShader)
278        {
279            mVertexShader->release();
280            mVertexShader = NULL;
281        }
282    }
283
284    mProgramBinary.set(NULL);
285    mLinked = false;
286}
287
288bool Program::isLinked()
289{
290    return mLinked;
291}
292
293ProgramBinary* Program::getProgramBinary()
294{
295    return mProgramBinary.get();
296}
297
298bool Program::setProgramBinary(const void *binary, GLsizei length)
299{
300    unlink(false);
301
302    mInfoLog.reset();
303
304    mProgramBinary.set(new ProgramBinary(mRenderer));
305    mLinked = mProgramBinary->load(mInfoLog, binary, length);
306    if (!mLinked)
307    {
308        mProgramBinary.set(NULL);
309    }
310
311    return mLinked;
312}
313
314void Program::release()
315{
316    mRefCount--;
317
318    if (mRefCount == 0 && mDeleteStatus)
319    {
320        mResourceManager->deleteProgram(mHandle);
321    }
322}
323
324void Program::addRef()
325{
326    mRefCount++;
327}
328
329unsigned int Program::getRefCount() const
330{
331    return mRefCount;
332}
333
334GLint Program::getProgramBinaryLength() const
335{
336    ProgramBinary *programBinary = mProgramBinary.get();
337    if (programBinary)
338    {
339        return programBinary->getLength();
340    }
341    else
342    {
343        return 0;
344    }
345}
346
347int Program::getInfoLogLength() const
348{
349    return mInfoLog.getLength();
350}
351
352void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
353{
354    return mInfoLog.getLog(bufSize, length, infoLog);
355}
356
357void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
358{
359    int total = 0;
360
361    if (mVertexShader)
362    {
363        if (total < maxCount)
364        {
365            shaders[total] = mVertexShader->getHandle();
366        }
367
368        total++;
369    }
370
371    if (mFragmentShader)
372    {
373        if (total < maxCount)
374        {
375            shaders[total] = mFragmentShader->getHandle();
376        }
377
378        total++;
379    }
380
381    if (count)
382    {
383        *count = total;
384    }
385}
386
387void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
388{
389    ProgramBinary *programBinary = getProgramBinary();
390    if (programBinary)
391    {
392        programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
393    }
394    else
395    {
396        if (bufsize > 0)
397        {
398            name[0] = '\0';
399        }
400
401        if (length)
402        {
403            *length = 0;
404        }
405
406        *type = GL_NONE;
407        *size = 1;
408    }
409}
410
411GLint Program::getActiveAttributeCount()
412{
413    ProgramBinary *programBinary = getProgramBinary();
414    if (programBinary)
415    {
416        return programBinary->getActiveAttributeCount();
417    }
418    else
419    {
420        return 0;
421    }
422}
423
424GLint Program::getActiveAttributeMaxLength()
425{
426    ProgramBinary *programBinary = getProgramBinary();
427    if (programBinary)
428    {
429        return programBinary->getActiveAttributeMaxLength();
430    }
431    else
432    {
433        return 0;
434    }
435}
436
437void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
438{
439    ProgramBinary *programBinary = getProgramBinary();
440    if (programBinary)
441    {
442        return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
443    }
444    else
445    {
446        if (bufsize > 0)
447        {
448            name[0] = '\0';
449        }
450
451        if (length)
452        {
453            *length = 0;
454        }
455
456        *size = 0;
457        *type = GL_NONE;
458    }
459}
460
461GLint Program::getActiveUniformCount()
462{
463    ProgramBinary *programBinary = getProgramBinary();
464    if (programBinary)
465    {
466        return programBinary->getActiveUniformCount();
467    }
468    else
469    {
470        return 0;
471    }
472}
473
474GLint Program::getActiveUniformMaxLength()
475{
476    ProgramBinary *programBinary = getProgramBinary();
477    if (programBinary)
478    {
479        return programBinary->getActiveUniformMaxLength();
480    }
481    else
482    {
483        return 0;
484    }
485}
486
487void Program::flagForDeletion()
488{
489    mDeleteStatus = true;
490}
491
492bool Program::isFlaggedForDeletion() const
493{
494    return mDeleteStatus;
495}
496
497void Program::validate()
498{
499    mInfoLog.reset();
500
501    ProgramBinary *programBinary = getProgramBinary();
502    if (isLinked() && programBinary)
503    {
504        programBinary->validate(mInfoLog);
505    }
506    else
507    {
508        mInfoLog.append("Program has not been successfully linked.");
509    }
510}
511
512bool Program::isValidated() const
513{
514    ProgramBinary *programBinary = mProgramBinary.get();
515    if (programBinary)
516    {
517        return programBinary->isValidated();
518    }
519    else
520    {
521        return false;
522    }
523}
524
525}
526