Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/GLSL/src/OgreGLSLLinkProgramManager.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 18.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30#include "OgreGLSLLinkProgramManager.h"
31#include "OgreGLSLGpuProgram.h"
32#include "OgreGLSLProgram.h"
33#include "OgreStringConverter.h"
34#include "OgreLogManager.h"
35
36namespace Ogre {
37
38        //-----------------------------------------------------------------------
39        template<> GLSLLinkProgramManager* Singleton<GLSLLinkProgramManager>::ms_Singleton = 0;
40
41        //-----------------------------------------------------------------------
42    GLSLLinkProgramManager* GLSLLinkProgramManager::getSingletonPtr(void)
43    {
44        return ms_Singleton;
45    }
46
47        //-----------------------------------------------------------------------
48    GLSLLinkProgramManager& GLSLLinkProgramManager::getSingleton(void)
49    { 
50        assert( ms_Singleton );  return ( *ms_Singleton ); 
51    }
52
53        //-----------------------------------------------------------------------
54        GLSLLinkProgramManager::GLSLLinkProgramManager(void) : mActiveVertexGpuProgram(NULL),
55                mActiveFragmentGpuProgram(NULL), mActiveLinkProgram(NULL)
56        {
57                // Fill in the relationship between type names and enums
58                mTypeEnumMap.insert(StringToEnumMap::value_type("float", GL_FLOAT));
59                mTypeEnumMap.insert(StringToEnumMap::value_type("vec2", GL_FLOAT_VEC2));
60                mTypeEnumMap.insert(StringToEnumMap::value_type("vec3", GL_FLOAT_VEC3));
61                mTypeEnumMap.insert(StringToEnumMap::value_type("vec4", GL_FLOAT_VEC4));
62                mTypeEnumMap.insert(StringToEnumMap::value_type("sampler1D", GL_SAMPLER_1D));
63                mTypeEnumMap.insert(StringToEnumMap::value_type("sampler2D", GL_SAMPLER_2D));
64                mTypeEnumMap.insert(StringToEnumMap::value_type("sampler3D", GL_SAMPLER_3D));
65                mTypeEnumMap.insert(StringToEnumMap::value_type("samplerCube", GL_SAMPLER_CUBE));
66                mTypeEnumMap.insert(StringToEnumMap::value_type("sampler1DShadow", GL_SAMPLER_1D_SHADOW));
67                mTypeEnumMap.insert(StringToEnumMap::value_type("sampler2DShadow", GL_SAMPLER_2D_SHADOW));
68                mTypeEnumMap.insert(StringToEnumMap::value_type("int", GL_INT));
69                mTypeEnumMap.insert(StringToEnumMap::value_type("ivec2", GL_INT_VEC2));
70                mTypeEnumMap.insert(StringToEnumMap::value_type("ivec3", GL_INT_VEC3));
71                mTypeEnumMap.insert(StringToEnumMap::value_type("ivec4", GL_INT_VEC4));
72                mTypeEnumMap.insert(StringToEnumMap::value_type("mat2", GL_FLOAT_MAT2));
73                mTypeEnumMap.insert(StringToEnumMap::value_type("mat3", GL_FLOAT_MAT3));
74                mTypeEnumMap.insert(StringToEnumMap::value_type("mat4", GL_FLOAT_MAT4));
75                // GL 2.1
76                mTypeEnumMap.insert(StringToEnumMap::value_type("mat2x2", GL_FLOAT_MAT2));
77                mTypeEnumMap.insert(StringToEnumMap::value_type("mat3x3", GL_FLOAT_MAT3));
78                mTypeEnumMap.insert(StringToEnumMap::value_type("mat4x4", GL_FLOAT_MAT4));
79                mTypeEnumMap.insert(StringToEnumMap::value_type("mat2x3", GL_FLOAT_MAT2x3));
80                mTypeEnumMap.insert(StringToEnumMap::value_type("mat3x2", GL_FLOAT_MAT3x2));
81                mTypeEnumMap.insert(StringToEnumMap::value_type("mat3x4", GL_FLOAT_MAT3x4));
82                mTypeEnumMap.insert(StringToEnumMap::value_type("mat4x3", GL_FLOAT_MAT4x3));
83                mTypeEnumMap.insert(StringToEnumMap::value_type("mat2x4", GL_FLOAT_MAT2x4));
84                mTypeEnumMap.insert(StringToEnumMap::value_type("mat4x2", GL_FLOAT_MAT4x2));
85
86        }
87
88        //-----------------------------------------------------------------------
89        GLSLLinkProgramManager::~GLSLLinkProgramManager(void)
90        {
91                // iterate through map container and delete link programs
92                for (LinkProgramIterator currentProgram = LinkPrograms.begin();
93                        currentProgram != LinkPrograms.end(); ++currentProgram)
94                {
95                        delete currentProgram->second;
96                }
97
98        }
99
100        //-----------------------------------------------------------------------
101        GLSLLinkProgram* GLSLLinkProgramManager::getActiveLinkProgram(void)
102        {
103                // if there is an active link program then return it
104                if (mActiveLinkProgram)
105                        return mActiveLinkProgram;
106
107                // no active link program so find one or make a new one
108                // is there an active key?
109                GLuint activeKey = 0;
110
111                if (mActiveVertexGpuProgram)
112                {
113                        activeKey = mActiveVertexGpuProgram->getProgramID() << 16;
114                }
115
116                if (mActiveFragmentGpuProgram)
117                {
118                        activeKey += mActiveFragmentGpuProgram->getProgramID();
119                }
120
121                // only return a link program object if a vertex or fragment program exist
122                if (activeKey > 0)
123                {
124                        // find the key in the hash map
125                        LinkProgramIterator programFound = LinkPrograms.find(activeKey);
126                        // program object not found for key so need to create it
127                        if (programFound == LinkPrograms.end())
128                        {
129                                mActiveLinkProgram = new GLSLLinkProgram(mActiveVertexGpuProgram, mActiveFragmentGpuProgram);
130                                LinkPrograms[activeKey] = mActiveLinkProgram;
131                        }
132                        else
133                        {
134                                // found a link program in map container so make it active
135                                mActiveLinkProgram = programFound->second;
136                        }
137
138                }
139                // make the program object active
140                if (mActiveLinkProgram) mActiveLinkProgram->activate();
141
142                return mActiveLinkProgram;
143
144        }
145
146        //-----------------------------------------------------------------------
147        void GLSLLinkProgramManager::setActiveFragmentShader(GLSLGpuProgram* fragmentGpuProgram)
148        {
149                if (fragmentGpuProgram != mActiveFragmentGpuProgram)
150                {
151                        mActiveFragmentGpuProgram = fragmentGpuProgram;
152                        // ActiveLinkProgram is no longer valid
153                        mActiveLinkProgram = NULL;
154                        // change back to fixed pipeline
155                        glUseProgramObjectARB(0);
156                }
157        }
158
159        //-----------------------------------------------------------------------
160        void GLSLLinkProgramManager::setActiveVertexShader(GLSLGpuProgram* vertexGpuProgram)
161        {
162                if (vertexGpuProgram != mActiveVertexGpuProgram)
163                {
164                        mActiveVertexGpuProgram = vertexGpuProgram;
165                        // ActiveLinkProgram is no longer valid
166                        mActiveLinkProgram = NULL;
167                        // change back to fixed pipeline
168                        glUseProgramObjectARB(0);
169                }
170        }
171        //---------------------------------------------------------------------
172        void GLSLLinkProgramManager::completeDefInfo(GLenum gltype, 
173                GpuConstantDefinition& defToUpdate)
174        {
175                // decode uniform size and type
176                // Note GLSL never packs rows into float4's(from an API perspective anyway)
177                // therefore all values are tight in the buffer
178                switch (gltype)
179                {
180                case GL_FLOAT:
181                        defToUpdate.constType = GCT_FLOAT1;
182                        defToUpdate.elementSize = 1;
183                        break;
184                case GL_FLOAT_VEC2:
185                        defToUpdate.constType = GCT_FLOAT2;
186                        defToUpdate.elementSize = 2;
187                        break;
188
189                case GL_FLOAT_VEC3:
190                        defToUpdate.constType = GCT_FLOAT3;
191                        defToUpdate.elementSize = 3;
192                        break;
193
194                case GL_FLOAT_VEC4:
195                        defToUpdate.constType = GCT_FLOAT4;
196                        defToUpdate.elementSize = 4;
197                        break;
198                case GL_SAMPLER_1D:
199                        // need to record samplers for GLSL
200                        defToUpdate.constType = GCT_SAMPLER1D;
201                        defToUpdate.elementSize = 1;
202                        break;
203                case GL_SAMPLER_2D:
204                case GL_SAMPLER_2D_RECT_ARB:
205                        defToUpdate.constType = GCT_SAMPLER2D;
206                        defToUpdate.elementSize = 1;
207                        break;
208                case GL_SAMPLER_3D:
209                        defToUpdate.constType = GCT_SAMPLER3D;
210                        defToUpdate.elementSize = 1;
211                        break;
212                case GL_SAMPLER_CUBE:
213                        defToUpdate.constType = GCT_SAMPLERCUBE;
214                        defToUpdate.elementSize = 1;
215                        break;
216                case GL_SAMPLER_1D_SHADOW:
217                        defToUpdate.constType = GCT_SAMPLER1DSHADOW;
218                        defToUpdate.elementSize = 1;
219                        break;
220                case GL_SAMPLER_2D_SHADOW:
221                case GL_SAMPLER_2D_RECT_SHADOW_ARB:
222                        defToUpdate.constType = GCT_SAMPLER2DSHADOW;
223                        defToUpdate.elementSize = 1;
224                        break;
225                case GL_INT:
226                        defToUpdate.constType = GCT_INT1;
227                        defToUpdate.elementSize = 1;
228                        break;
229                case GL_INT_VEC2:
230                        defToUpdate.constType = GCT_INT2;
231                        defToUpdate.elementSize = 2;
232                        break;
233                case GL_INT_VEC3:
234                        defToUpdate.constType = GCT_INT3;
235                        defToUpdate.elementSize = 3;
236                        break;
237                case GL_INT_VEC4:
238                        defToUpdate.constType = GCT_INT4;
239                        defToUpdate.elementSize = 4;
240                        break;
241                case GL_FLOAT_MAT2:
242                        defToUpdate.constType = GCT_MATRIX_2X2;
243                        defToUpdate.elementSize = 4;
244                        break;
245                case GL_FLOAT_MAT3:
246                        defToUpdate.constType = GCT_MATRIX_3X3;
247                        defToUpdate.elementSize = 9;
248                        break;
249                case GL_FLOAT_MAT4:
250                        defToUpdate.constType = GCT_MATRIX_4X4;
251                        defToUpdate.elementSize = 16;
252                        break;
253                case GL_FLOAT_MAT2x3:
254                        defToUpdate.constType = GCT_MATRIX_2X3;
255                        defToUpdate.elementSize = 6;
256                        break;
257                case GL_FLOAT_MAT3x2:
258                        defToUpdate.constType = GCT_MATRIX_3X2;
259                        defToUpdate.elementSize = 6;
260                        break;
261                case GL_FLOAT_MAT2x4:
262                        defToUpdate.constType = GCT_MATRIX_2X4;
263                        defToUpdate.elementSize = 8;
264                        break;
265                case GL_FLOAT_MAT4x2:
266                        defToUpdate.constType = GCT_MATRIX_4X2;
267                        defToUpdate.elementSize = 8;
268                        break;
269                case GL_FLOAT_MAT3x4:
270                        defToUpdate.constType = GCT_MATRIX_3X4;
271                        defToUpdate.elementSize = 12;
272                        break;
273                case GL_FLOAT_MAT4x3:
274                        defToUpdate.constType = GCT_MATRIX_4X3;
275                        defToUpdate.elementSize = 12;
276                        break;
277                default:
278                        defToUpdate.constType = GCT_UNKNOWN;
279                        break;
280
281                }
282
283        }
284        //---------------------------------------------------------------------
285        bool GLSLLinkProgramManager::completeParamSource(
286                const String& paramName,
287                const GpuConstantDefinitionMap* vertexConstantDefs, 
288                const GpuConstantDefinitionMap* fragmentConstantDefs, 
289                GLUniformReference& refToUpdate)
290        {
291                if (vertexConstantDefs)
292                {
293                        GpuConstantDefinitionMap::const_iterator parami = 
294                                vertexConstantDefs->find(paramName);
295                        if (parami != vertexConstantDefs->end())
296                        {
297                                refToUpdate.mSourceProgType = GPT_VERTEX_PROGRAM;
298                                refToUpdate.mConstantDef = &(parami->second);
299                                return true;
300                        }
301
302                }
303                if (fragmentConstantDefs)
304                {
305                        GpuConstantDefinitionMap::const_iterator parami = 
306                                fragmentConstantDefs->find(paramName);
307                        if (parami != fragmentConstantDefs->end())
308                        {
309                                refToUpdate.mSourceProgType = GPT_FRAGMENT_PROGRAM;
310                                refToUpdate.mConstantDef = &(parami->second);
311                                return true;
312                        }
313                }
314                return false;
315
316
317        }
318        //---------------------------------------------------------------------
319        void GLSLLinkProgramManager::extractUniforms(GLhandleARB programObject, 
320                const GpuConstantDefinitionMap* vertexConstantDefs, 
321                const GpuConstantDefinitionMap* fragmentConstantDefs, 
322                GLUniformReferenceList& list)
323        {
324                // scan through the active uniforms and add them to the reference list
325                GLint uniformCount;
326
327                #define BUFFERSIZE 200
328                char   uniformName[BUFFERSIZE];
329                //GLint location;
330                GLUniformReference newGLUniformReference;
331
332                // get the number of active uniforms
333                glGetObjectParameterivARB(programObject, GL_OBJECT_ACTIVE_UNIFORMS_ARB,
334                        &uniformCount);
335
336                // Loop over each of the active uniforms, and add them to the reference container
337                // only do this for user defined uniforms, ignore built in gl state uniforms
338                for (int index = 0; index < uniformCount; index++)
339                {
340                        GLint arraySize;
341                        GLenum glType;
342                        glGetActiveUniformARB(programObject, index, BUFFERSIZE, NULL, 
343                                &arraySize, &glType, uniformName);
344                        // don't add built in uniforms
345                        newGLUniformReference.mLocation = glGetUniformLocationARB(programObject, uniformName);
346                        if (newGLUniformReference.mLocation >= 0)
347                        {
348                                // user defined uniform found, add it to the reference list
349                                String paramName = String( uniformName );
350                               
351                // currant ATI drivers (Catalyst 7.2 and earlier) and older NVidia drivers will include all array elements as uniforms but we only want the root array name and location
352                // Also note that ATI Catalyst 6.8 to 7.2 there is a bug with glUniform that does not allow you to update a uniform array past the first uniform array element
353                // ie you can't start updating an array starting at element 1, must always be element 0.
354               
355                // if the uniform name has a "[" in it then its an array element uniform.
356                String::size_type arrayStart = paramName.find("[");
357                if (arrayStart != String::npos)
358                {
359                    // if not the first array element then skip it and continue to the next uniform
360                    if (paramName.compare(arrayStart, paramName.size() - 1, "[0]") != 0) continue;
361                    paramName = paramName.substr(0, arrayStart);
362                }
363               
364                                // find out which params object this comes from
365                                bool foundSource = completeParamSource(paramName, 
366                                        vertexConstantDefs, 
367                                        fragmentConstantDefs, newGLUniformReference);
368
369                                // only add this parameter if we found the source
370                                if (foundSource)
371                                {
372                                        assert(arraySize == newGLUniformReference.mConstantDef->arraySize
373                                                && "GL doesn't agree with our array size!");
374                                        list.push_back(newGLUniformReference);
375                                }
376
377                                // Don't bother adding individual array params, they will be
378                                // picked up in the 'parent' parameter can copied all at once
379                                // anyway, individual indexes are only needed for lookup from
380                                // user params
381                        } // end if
382                } // end for
383
384        }
385        //---------------------------------------------------------------------
386        void GLSLLinkProgramManager::extractConstantDefs(const String& src, 
387                GpuNamedConstants& defs, const String& filename)
388        {
389                // Could have done this as a compiler but we don't want to have to
390                // create a BNF for the whole GLSL syntax, so use a simpler method
391                String::size_type currPos = 0;
392                String line;
393                currPos = src.find("uniform", currPos);
394                while (currPos != String::npos)
395                {
396                        GpuConstantDefinition def;
397                        String paramName;
398
399                        // Check that this is not in a comment block
400                        bool inComment = false;
401                       
402                        // block-comments
403                        size_t commentStart = src.rfind("/*", currPos);
404                        if (commentStart != String::npos)
405                        {
406                                size_t commentEnd = src.rfind("*/", currPos);
407                                if (commentEnd == String::npos || commentEnd < commentStart)
408                                {
409                                        // no ending comment, or ending comment was from a previous batch
410                                        inComment = true;
411                                }
412                        }
413                        // line-comments
414                        if (!inComment)
415                        {
416                                commentStart = src.rfind("//", currPos);
417                                if (commentStart != String::npos)
418                                {
419                                        size_t lineEnd = src.rfind("\n", currPos);
420
421                                        // On same line as comment? Either no newline or nearest is before comment start
422                                        if (lineEnd == String::npos || lineEnd < commentStart)
423                                        {
424                                                inComment = true;
425                                        }
426                                }
427                        }
428
429                        // Now check for using the word 'uniform' in a larger string & ignore
430                        bool inLargerString = false;
431                        if (!inComment)
432                        {       
433                                if (currPos != 0)
434                                {
435                                        char prev = src.at(currPos - 1);
436                                        if (prev != ' ' && prev != '\t' && prev != '\r' && prev != '\n'
437                                                && prev != ';')
438                                                inLargerString = true;
439                                }
440                                if (!inLargerString && currPos + 7 < src.size())
441                                {
442                                        char next = src.at(currPos + 7);
443                                        if (next != ' ' && next != '\t' && next != '\r' && next != '\n')
444                                                inLargerString = true;
445                                }
446
447                        }
448
449                        // skip 'uniform'
450                        currPos += 7;
451
452                        if (!inComment && !inLargerString)
453                        {
454                                // find terminating semicolon
455                                String::size_type endPos = src.find(";", currPos);
456                                if (endPos == String::npos)
457                                {
458                                        // problem, missing semicolon, abort
459                                        break;
460                                }
461                                line = src.substr(currPos, endPos - currPos);
462
463                                // Split into tokens
464                                StringVector parts = StringUtil::split(line, ", \t\r\n");
465
466                                for (StringVector::iterator i = parts.begin(); i != parts.end(); ++i)
467                                {
468                                        // Is this a type?
469                                        StringToEnumMap::iterator typei = mTypeEnumMap.find(*i);
470                                        if (typei != mTypeEnumMap.end())
471                                        {
472                                                completeDefInfo(typei->second, def);
473                                        }
474                                        else
475                                        {
476                                                // if this is not a type, and not empty, it should be a name
477                                                StringUtil::trim(*i);
478                                                if (i->empty()) continue;
479
480                                                String::size_type arrayStart = i->find("[", 0);
481                                                if (arrayStart != String::npos)
482                                                {
483                                                        // potential name (if butted up to array)
484                                                        String name = i->substr(0, arrayStart);
485                                                        StringUtil::trim(name);
486                                                        if (!name.empty())
487                                                                paramName = name;
488
489                                                        String::size_type arrayEnd = i->find("]", arrayStart);
490                                                        String arrayDimTerm = i->substr(arrayStart + 1, arrayEnd - arrayStart - 1);
491                                                        StringUtil::trim(arrayDimTerm);
492                                                        // the array term might be a simple number or it might be
493                                                        // an expression (e.g. 24*3) or refer to a constant expression
494                                                        // we'd have to evaluate the expression which could get nasty
495                                                        // TODO
496                                                        def.arraySize = StringConverter::parseInt(arrayDimTerm);
497
498                                                }
499                                                else
500                                                {
501                                                        paramName = *i;
502                                                        def.arraySize = 1;
503                                                }
504
505                                                // Name should be after the type, so complete def and add
506                                                // We do this now so that comma-separated params will do
507                                                // this part once for each name mentioned
508                                                if (def.constType == GCT_UNKNOWN)
509                                                {
510                                                        LogManager::getSingleton().logMessage(
511                                                                "Problem parsing the following GLSL Uniform: '"
512                                                                + line + "' in file " + filename);
513                                                        // next uniform
514                                                        break;
515                                                }
516
517                                                // Complete def and add
518                                                // increment physical buffer location
519                                                if (def.isFloat())
520                                                {
521                                                        def.physicalIndex = defs.floatBufferSize;
522                                                        defs.floatBufferSize += def.arraySize * def.elementSize;
523                                                }
524                                                else
525                                                {
526                                                        def.physicalIndex = defs.intBufferSize;
527                                                        defs.intBufferSize += def.arraySize * def.elementSize;
528                                                }
529                                                defs.map.insert(GpuConstantDefinitionMap::value_type(paramName, def));
530
531                                                // Generate array accessors
532                                                defs.generateConstantDefinitionArrayEntries(paramName, def);
533
534
535                                        }
536
537                                }
538
539                        } // not commented or a larger symbol
540
541                        // Find next one
542                        currPos = src.find("uniform", currPos);
543
544                }
545               
546        }
547
548}
Note: See TracBrowser for help on using the repository browser.