Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/PlugIns/CgProgramManager/src/OgreCgProgram.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 17.7 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#include "OgreCgProgram.h"
30#include "OgreGpuProgramManager.h"
31#include "OgreStringConverter.h"
32#include "OgreLogManager.h"
33
34namespace Ogre {
35    //-----------------------------------------------------------------------
36    CgProgram::CmdEntryPoint CgProgram::msCmdEntryPoint;
37    CgProgram::CmdProfiles CgProgram::msCmdProfiles;
38    CgProgram::CmdArgs CgProgram::msCmdArgs;
39    //-----------------------------------------------------------------------
40    void CgProgram::selectProfile(void)
41    {
42        mSelectedProfile.clear();
43        mSelectedCgProfile = CG_PROFILE_UNKNOWN;
44
45        StringVector::iterator i, iend;
46        iend = mProfiles.end();
47        GpuProgramManager& gpuMgr = GpuProgramManager::getSingleton();
48        for (i = mProfiles.begin(); i != iend; ++i)
49        {
50            if (gpuMgr.isSyntaxSupported(*i))
51            {
52                mSelectedProfile = *i;
53                mSelectedCgProfile = cgGetProfile(mSelectedProfile.c_str());
54                // Check for errors
55                checkForCgError("CgProgram::selectProfile", 
56                    "Unable to find CG profile enum for program " + mName + ": ", mCgContext);
57                break;
58            }
59        }
60    }
61    //-----------------------------------------------------------------------
62    void CgProgram::buildArgs(void)
63    {
64        StringVector args;
65        if (!mCompileArgs.empty())
66            args = StringUtil::split(mCompileArgs);
67
68        StringVector::const_iterator i;
69        if (mSelectedCgProfile == CG_PROFILE_VS_1_1)
70        {
71            // Need the 'dcls' argument whenever we use this profile
72            // otherwise compilation of the assembler will fail
73            bool dclsFound = false;
74            for (i = args.begin(); i != args.end(); ++i)
75            {
76                if (*i == "dcls")
77                {
78                    dclsFound = true;
79                    break;
80                }
81            }
82            if (!dclsFound)
83            {
84                args.push_back("-profileopts");
85                                args.push_back("dcls");
86            }
87        }
88        // Now split args into that god-awful char** that Cg insists on
89        freeCgArgs();
90        mCgArguments = new char*[args.size() + 1];
91        int index = 0;
92        for (i = args.begin(); i != args.end(); ++i, ++index)
93        {
94            mCgArguments[index] = new char[i->length() + 1];
95            strcpy(mCgArguments[index], i->c_str());
96        }
97        // Null terminate list
98        mCgArguments[index] = 0;
99
100
101    }
102    //-----------------------------------------------------------------------
103    void CgProgram::freeCgArgs(void)
104    {
105        if (mCgArguments)
106        {
107            size_t index = 0;
108            char* current = mCgArguments[index];
109            while (current)
110            {
111                delete [] current;
112                current = mCgArguments[++index];
113            }
114            delete [] mCgArguments;
115            mCgArguments = 0;
116        }
117    }
118    //-----------------------------------------------------------------------
119    void CgProgram::loadFromSource(void)
120    {
121        // Create Cg Program
122        selectProfile();
123                if (mSelectedCgProfile == CG_PROFILE_UNKNOWN)
124                {
125                        LogManager::getSingleton().logMessage(
126                                "Attempted to load Cg program '" + mName + "', but no suported "
127                                "profile was found. ");
128                        return;
129                }
130        buildArgs();
131        mCgProgram = cgCreateProgram(mCgContext, CG_SOURCE, mSource.c_str(), 
132            mSelectedCgProfile, mEntryPoint.c_str(), const_cast<const char**>(mCgArguments));
133
134        // Test
135        //LogManager::getSingleton().logMessage(cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM));
136
137        // Check for errors
138        checkForCgError("CgProgram::loadFromSource", 
139            "Unable to compile Cg program " + mName + ": ", mCgContext);
140
141    }
142    //-----------------------------------------------------------------------
143    void CgProgram::createLowLevelImpl(void)
144    {
145                // ignore any previous error
146                if (mSelectedCgProfile != CG_PROFILE_UNKNOWN)
147                {
148
149                        // Create a low-level program, give it the same name as us
150                        mAssemblerProgram = 
151                                GpuProgramManager::getSingleton().createProgramFromString(
152                                        mName, 
153                                        mGroup,
154                                        cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM),
155                                        mType, 
156                                        mSelectedProfile);
157                }
158    }
159    //-----------------------------------------------------------------------
160    void CgProgram::unloadHighLevelImpl(void)
161    {
162        // Unload Cg Program
163        // Lowlevel program will get unloaded elsewhere
164        if (mCgProgram)
165        {
166            cgDestroyProgram(mCgProgram);
167            checkForCgError("CgProgram::unloadImpl", 
168                "Error while unloading Cg program " + mName + ": ", 
169                mCgContext);
170            mCgProgram = 0;
171        }
172    }
173    //-----------------------------------------------------------------------
174    void CgProgram::buildConstantDefinitions() const
175    {
176        // Derive parameter names from Cg
177
178                mFloatLogicalToPhysical.bufferSize = 0;
179                mIntLogicalToPhysical.bufferSize = 0;
180                mConstantDefs.floatBufferSize = 0;
181                mConstantDefs.intBufferSize = 0;
182
183                if (!mCgProgram)
184                        return;
185
186                recurseParams(cgGetFirstParameter(mCgProgram, CG_PROGRAM));
187        recurseParams(cgGetFirstParameter(mCgProgram, CG_GLOBAL));
188        }
189        //---------------------------------------------------------------------
190        void CgProgram::recurseParams(CGparameter parameter, size_t contextArraySize) const
191        {
192                while (parameter != 0)
193        {
194            // Look for uniform (non-sampler) parameters only
195            // Don't bother enumerating unused parameters, especially since they will
196            // be optimised out and therefore not in the indexed versions
197            CGtype paramType = cgGetParameterType(parameter);
198
199            if (cgGetParameterVariability(parameter) == CG_UNIFORM &&
200                paramType != CG_SAMPLER1D &&
201                paramType != CG_SAMPLER2D &&
202                paramType != CG_SAMPLER3D &&
203                paramType != CG_SAMPLERCUBE &&
204                paramType != CG_SAMPLERRECT &&
205                cgGetParameterDirection(parameter) != CG_OUT && 
206                cgIsParameterReferenced(parameter))
207            {
208                                int arraySize;
209
210                                switch(paramType)
211                                {
212                                case CG_STRUCT:
213                                        recurseParams(cgGetFirstStructParameter(parameter));
214                                        break;
215                                case CG_ARRAY:
216                                        // Support only 1-dimensional arrays
217                                        arraySize = cgGetArraySize(parameter, 0);
218                                        recurseParams(cgGetArrayParameter(parameter, 0), (size_t)arraySize);
219                                        break;
220                                default:
221                                        // Normal path (leaf)
222                                        String paramName = cgGetParameterName(parameter);
223                                        size_t logicalIndex = cgGetParameterResourceIndex(parameter);
224
225                                        // Get the parameter resource, to calculate the physical index
226                                        CGresource res = cgGetParameterResource(parameter);
227                                        bool isRegisterCombiner = false;
228                                        size_t regCombinerPhysicalIndex = 0;
229                                        switch (res)
230                                        {
231                                        case CG_COMBINER_STAGE_CONST0:
232                                                // register combiner, const 0
233                                                // the index relates to the texture stage; store this as (stage * 2) + 0
234                                                regCombinerPhysicalIndex = logicalIndex * 2;
235                                                isRegisterCombiner = true;
236                                                break;
237                                        case CG_COMBINER_STAGE_CONST1:
238                                                // register combiner, const 1
239                                                // the index relates to the texture stage; store this as (stage * 2) + 1
240                                                regCombinerPhysicalIndex = (logicalIndex * 2) + 1;
241                                                isRegisterCombiner = true;
242                                                break;
243                                        default:
244                                                // normal constant
245                                                break;
246                                        }
247
248                                        // Trim the '[0]' suffix if it exists, we will add our own indexing later
249                                        if (StringUtil::endsWith(paramName, "[0]", false))
250                                        {
251                                                paramName.erase(paramName.size() - 3);
252                                        }
253
254
255                                        GpuConstantDefinition def;
256                                        def.arraySize = contextArraySize;
257                                        mapTypeAndElementSize(paramType, isRegisterCombiner, def);
258
259                                        if (def.constType == GCT_UNKNOWN)
260                                        {
261                                                LogManager::getSingleton().logMessage(
262                                                        "Problem parsing the following Cg Uniform: '"
263                                                        + paramName + "' in file " + mName);
264                                                // next uniform
265                                                continue;
266                                        }
267                                        if (isRegisterCombiner)
268                                        {
269                                                def.physicalIndex = regCombinerPhysicalIndex;
270                                        }
271                                        else
272                                        {
273                                                // base position on existing buffer contents
274                                                if (def.isFloat())
275                                                {
276                                                        def.physicalIndex = mFloatLogicalToPhysical.bufferSize;
277                                                }
278                                                else
279                                                {
280                                                        def.physicalIndex = mIntLogicalToPhysical.bufferSize;
281                                                }
282                                        }
283
284
285                                        mConstantDefs.map.insert(GpuConstantDefinitionMap::value_type(paramName, def));
286
287                                        // Record logical / physical mapping
288                                        if (def.isFloat())
289                                        {
290                                                OGRE_LOCK_MUTEX(mFloatLogicalToPhysical.mutex)
291                                                mFloatLogicalToPhysical.map.insert(
292                                                        GpuLogicalIndexUseMap::value_type(logicalIndex, 
293                                                                GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize)));
294                                                mFloatLogicalToPhysical.bufferSize += def.arraySize * def.elementSize;
295                                                mConstantDefs.floatBufferSize = mFloatLogicalToPhysical.bufferSize;
296                                        }
297                                        else
298                                        {
299                                                OGRE_LOCK_MUTEX(mIntLogicalToPhysical.mutex)
300                                                mIntLogicalToPhysical.map.insert(
301                                                        GpuLogicalIndexUseMap::value_type(logicalIndex, 
302                                                                GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize)));
303                                                mIntLogicalToPhysical.bufferSize += def.arraySize * def.elementSize;
304                                                mConstantDefs.intBufferSize = mIntLogicalToPhysical.bufferSize;
305                                        }
306
307                                        // Deal with array indexing
308                                        mConstantDefs.generateConstantDefinitionArrayEntries(paramName, def);
309
310                                        break;
311               
312                                }
313                                       
314            }
315            // Get next
316            parameter = cgGetNextParameter(parameter);
317        }
318
319       
320    }
321        //-----------------------------------------------------------------------
322        void CgProgram::mapTypeAndElementSize(CGtype cgType, bool isRegisterCombiner, 
323                GpuConstantDefinition& def) const
324        {
325                if (isRegisterCombiner)
326                {
327                        // register combiners are the only single-float entries in our buffer
328                        def.constType = GCT_FLOAT1;
329                        def.elementSize = 1;
330                }
331                else
332                {
333                        switch(cgType)
334                        {
335                        case CG_FLOAT:
336                        case CG_FLOAT1:
337                        case CG_HALF:
338                        case CG_HALF1:
339                                def.constType = GCT_FLOAT1;
340                                def.elementSize = 4; // padded to 4 elements
341                                break;
342                        case CG_FLOAT2:
343                        case CG_HALF2:
344                                def.constType = GCT_FLOAT2;
345                                def.elementSize = 4; // padded to 4 elements
346                                break;
347                        case CG_FLOAT3:
348                        case CG_HALF3:
349                                def.constType = GCT_FLOAT3;
350                                def.elementSize = 4; // padded to 4 elements
351                                break;
352                        case CG_FLOAT4:
353                        case CG_HALF4:
354                                def.constType = GCT_FLOAT4;
355                                def.elementSize = 4; 
356                                break;
357                        case CG_FLOAT2x2:
358                        case CG_HALF2x2:
359                                def.constType = GCT_MATRIX_2X2;
360                                def.elementSize = 8; // Cg pads this to 2 float4s
361                                break;
362                        case CG_FLOAT2x3:
363                        case CG_HALF2x3:
364                                def.constType = GCT_MATRIX_2X3;
365                                def.elementSize = 8; // Cg pads this to 2 float4s
366                                break;
367                        case CG_FLOAT2x4:
368                        case CG_HALF2x4:
369                                def.constType = GCT_MATRIX_2X4;
370                                def.elementSize = 8; 
371                                break;
372                        case CG_FLOAT3x2:
373                        case CG_HALF3x2:
374                                def.constType = GCT_MATRIX_2X3;
375                                def.elementSize = 12; // Cg pads this to 3 float4s
376                                break;
377                        case CG_FLOAT3x3:
378                        case CG_HALF3x3:
379                                def.constType = GCT_MATRIX_3X3;
380                                def.elementSize = 12; // Cg pads this to 3 float4s
381                                break;
382                        case CG_FLOAT3x4:
383                        case CG_HALF3x4:
384                                def.constType = GCT_MATRIX_3X4;
385                                def.elementSize = 12; 
386                                break;
387                        case CG_FLOAT4x2:
388                        case CG_HALF4x2:
389                                def.constType = GCT_MATRIX_4X2;
390                                def.elementSize = 16; // Cg pads this to 4 float4s
391                                break;
392                        case CG_FLOAT4x3:
393                        case CG_HALF4x3:
394                                def.constType = GCT_MATRIX_4X3;
395                                def.elementSize = 16; // Cg pads this to 4 float4s
396                                break;
397                        case CG_FLOAT4x4:
398                        case CG_HALF4x4:
399                                def.constType = GCT_MATRIX_4X4;
400                                def.elementSize = 16; // Cg pads this to 4 float4s
401                                break;
402                        case CG_INT:
403                        case CG_INT1:
404                                def.constType = GCT_INT1;
405                                def.elementSize = 4; // Cg pads this to int4
406                                break;
407                        case CG_INT2:
408                                def.constType = GCT_INT2;
409                                def.elementSize = 4; // Cg pads this to int4
410                                break;
411                        case CG_INT3:
412                                def.constType = GCT_INT3;
413                                def.elementSize = 4; // Cg pads this to int4
414                                break;
415                        case CG_INT4:
416                                def.constType = GCT_INT4;
417                                def.elementSize = 4; 
418                                break;
419                        default:
420                                def.constType = GCT_UNKNOWN;
421                                break;
422                        }
423                }
424        }
425    //-----------------------------------------------------------------------
426    CgProgram::CgProgram(ResourceManager* creator, const String& name, 
427        ResourceHandle handle, const String& group, bool isManual, 
428        ManualResourceLoader* loader, CGcontext context)
429        : HighLevelGpuProgram(creator, name, handle, group, isManual, loader), 
430        mCgContext(context), mCgProgram(0), 
431        mSelectedCgProfile(CG_PROFILE_UNKNOWN), mCgArguments(0)
432    {
433        if (createParamDictionary("CgProgram"))
434        {
435            setupBaseParamDictionary();
436
437            ParamDictionary* dict = getParamDictionary();
438
439            dict->addParameter(ParameterDef("entry_point", 
440                "The entry point for the Cg program.",
441                PT_STRING),&msCmdEntryPoint);
442            dict->addParameter(ParameterDef("profiles", 
443                "Space-separated list of Cg profiles supported by this profile.",
444                PT_STRING),&msCmdProfiles);
445            dict->addParameter(ParameterDef("compile_arguments", 
446                "A string of compilation arguments to pass to the Cg compiler.",
447                PT_STRING),&msCmdArgs);
448        }
449       
450    }
451    //-----------------------------------------------------------------------
452    CgProgram::~CgProgram()
453    {
454        freeCgArgs();
455        // have to call this here reather than in Resource destructor
456        // since calling virtual methods in base destructors causes crash
457        if (isLoaded())
458        {
459            unload();
460        }
461        else
462        {
463            unloadHighLevel();
464        }
465    }
466    //-----------------------------------------------------------------------
467    bool CgProgram::isSupported(void) const
468    {
469        if (mCompileError || !isRequiredCapabilitiesSupported())
470            return false;
471
472                StringVector::const_iterator i, iend;
473        iend = mProfiles.end();
474        // Check to see if any of the profiles are supported
475        for (i = mProfiles.begin(); i != iend; ++i)
476        {
477            if (GpuProgramManager::getSingleton().isSyntaxSupported(*i))
478            {
479                return true;
480            }
481        }
482        return false;
483
484    }
485    //-----------------------------------------------------------------------
486    void CgProgram::setProfiles(const StringVector& profiles)
487    {
488        mProfiles.clear();
489        StringVector::const_iterator i, iend;
490        iend = profiles.end();
491        for (i = profiles.begin(); i != iend; ++i)
492        {
493            mProfiles.push_back(*i);
494        }
495    }
496
497    //-----------------------------------------------------------------------
498    const String& CgProgram::getLanguage(void) const
499    {
500        static const String language = "cg";
501
502        return language;
503    }
504
505
506    //-----------------------------------------------------------------------
507    //-----------------------------------------------------------------------
508    String CgProgram::CmdEntryPoint::doGet(const void *target) const
509    {
510        return static_cast<const CgProgram*>(target)->getEntryPoint();
511    }
512    void CgProgram::CmdEntryPoint::doSet(void *target, const String& val)
513    {
514        static_cast<CgProgram*>(target)->setEntryPoint(val);
515    }
516    //-----------------------------------------------------------------------
517    String CgProgram::CmdProfiles::doGet(const void *target) const
518    {
519        return StringConverter::toString(
520            static_cast<const CgProgram*>(target)->getProfiles() );
521    }
522    void CgProgram::CmdProfiles::doSet(void *target, const String& val)
523    {
524        static_cast<CgProgram*>(target)->setProfiles(StringUtil::split(val));
525    }
526    //-----------------------------------------------------------------------
527    String CgProgram::CmdArgs::doGet(const void *target) const
528    {
529        return static_cast<const CgProgram*>(target)->getCompileArguments();
530    }
531    void CgProgram::CmdArgs::doSet(void *target, const String& val)
532    {
533        static_cast<CgProgram*>(target)->setCompileArguments(val);
534    }
535
536}
Note: See TracBrowser for help on using the repository browser.