Coverage Report

Created: 2026-01-10 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreGpuProgramManager.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
#include "OgreGpuProgramManager.h"
30
31
#include <memory>
32
#include "OgreHighLevelGpuProgramManager.h"
33
#include "OgreUnifiedHighLevelGpuProgram.h"
34
#include "OgreStreamSerialiser.h"
35
36
namespace Ogre {
37
namespace {
38
    uint32 CACHE_CHUNK_ID = StreamSerialiser::makeIdentifier("OGPC"); // Ogre Gpu Program cache
39
40
    String sNullLang = "null";
41
    class NullProgram : public GpuProgram
42
    {
43
    protected:
44
        /** Internal load implementation, must be implemented by subclasses.
45
        */
46
0
        void loadFromSource(void) override {}
47
0
        void unloadImpl() override {}
48
49
    public:
50
        NullProgram(ResourceManager* creator,
51
            const String& name, ResourceHandle handle, const String& group,
52
            bool isManual, ManualResourceLoader* loader)
53
0
            : GpuProgram(creator, name, handle, group, isManual, loader){}
54
0
        ~NullProgram() {}
55
        /// Overridden from GpuProgram - never supported
56
0
        bool isSupported(void) const override { return false; }
57
        /// Overridden from GpuProgram
58
0
        const String& getLanguage(void) const override { return sNullLang; }
59
0
        size_t calculateSize(void) const override { return 0; }
60
61
        /// Overridden from StringInterface
62
        bool setParameter(const String& name, const String& value)
63
0
        {
64
0
            // always silently ignore all parameters so as not to report errors on
65
0
            // unsupported platforms
66
0
            return true;
67
0
        }
68
69
    };
70
    class NullProgramFactory : public HighLevelGpuProgramFactory
71
    {
72
    public:
73
1
        NullProgramFactory() {}
74
0
        ~NullProgramFactory() {}
75
        /// Get the name of the language this factory creates programs for
76
        const String& getLanguage(void) const override
77
1
        {
78
1
            return sNullLang;
79
1
        }
80
        GpuProgram* create(ResourceManager* creator,
81
            const String& name, ResourceHandle handle,
82
            const String& group, bool isManual, ManualResourceLoader* loader) override
83
0
        {
84
0
            return OGRE_NEW NullProgram(creator, name, handle, group, isManual, loader);
85
0
        }
86
    };
87
}
88
89
    Resource* GpuProgramManager::createImpl(const String& name, ResourceHandle handle, const String& group,
90
                                            bool isManual, ManualResourceLoader* loader,
91
                                            const NameValuePairList* params)
92
0
    {
93
0
        OgreAssert(params, "params cannot be null");
94
95
0
        auto langIt = params->find("language");
96
0
        auto typeIt = params->find("type");
97
98
0
        if(langIt == params->end())
99
0
            langIt = params->find("syntax");
100
101
0
        if (langIt == params->end() || typeIt == params->end())
102
0
        {
103
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
104
0
                        "You must supply 'language' or 'syntax' and 'type' parameters");
105
0
        }
106
107
        // "syntax" and "type" will be applied by ResourceManager::createResource
108
0
        return getFactory(langIt->second)->create(this, name, handle, group, isManual, loader);
109
0
    }
110
111
    //-----------------------------------------------------------------------
112
    template<> GpuProgramManager* Singleton<GpuProgramManager>::msSingleton = 0;
113
    GpuProgramManager* GpuProgramManager::getSingletonPtr(void)
114
0
    {
115
0
        return msSingleton;
116
0
    }
117
    GpuProgramManager& GpuProgramManager::getSingleton(void)
118
0
    {  
119
0
        assert( msSingleton );  return ( *msSingleton );  
120
0
    }
121
    //-----------------------------------------------------------------------
122
    GpuProgramPtr GpuProgramManager::getByName(const String& name, const String& group) const
123
0
    {
124
0
        return static_pointer_cast<GpuProgram>(getResourceByName(name, group));
125
0
    }
126
    //---------------------------------------------------------------------------
127
    GpuProgramManager::GpuProgramManager()
128
1
    {
129
        // Loading order
130
1
        mLoadOrder = 50.0f;
131
        // Resource type
132
1
        mResourceType = "GpuProgram";
133
1
        mSaveMicrocodesToCache = false;
134
1
        mCacheDirty = false;
135
136
1
        mNullFactory = std::make_unique<NullProgramFactory>();
137
1
        addFactory(mNullFactory.get());
138
1
        mUnifiedFactory = std::make_unique<UnifiedHighLevelGpuProgramFactory>();
139
1
        addFactory(mUnifiedFactory.get());
140
141
1
        ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this);
142
1
    }
143
    //---------------------------------------------------------------------------
144
    GpuProgramManager::~GpuProgramManager()
145
1
    {
146
1
        ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType);
147
1
    }
148
    //---------------------------------------------------------------------------
149
    GpuProgramPtr GpuProgramManager::load(const String& name,
150
        const String& groupName, const String& filename, 
151
        GpuProgramType gptype, const String& syntaxCode)
152
0
    {
153
0
        GpuProgramPtr prg;
154
0
        {
155
0
            OGRE_LOCK_AUTO_MUTEX;
156
0
            prg = getByName(name, groupName);
157
0
            if (!prg)
158
0
            {
159
0
                prg = createProgram(name, groupName, filename, gptype, syntaxCode);
160
0
            }
161
162
0
        }
163
0
        prg->load();
164
0
        return prg;
165
0
    }
166
    //---------------------------------------------------------------------------
167
    GpuProgramPtr GpuProgramManager::loadFromString(const String& name, 
168
        const String& groupName, const String& code, 
169
        GpuProgramType gptype, const String& syntaxCode)
170
0
    {
171
0
        GpuProgramPtr prg;
172
0
        {
173
0
                    OGRE_LOCK_AUTO_MUTEX;
174
0
            prg = getByName(name, groupName);
175
0
            if (!prg)
176
0
            {
177
0
                prg = createProgramFromString(name, groupName, code, gptype, syntaxCode);
178
0
            }
179
180
0
        }
181
0
        prg->load();
182
0
        return prg;
183
0
    }
184
    //---------------------------------------------------------------------------
185
    GpuProgramPtr GpuProgramManager::create(const String& name, const String& group, GpuProgramType gptype,
186
                                            const String& syntaxCode, bool isManual,
187
                                            ManualResourceLoader* loader)
188
0
    {
189
0
        auto prg = getFactory(syntaxCode)->create(this, name, getNextHandle(), group, isManual, loader);
190
0
        prg->setType(gptype);
191
0
        prg->setSyntaxCode(syntaxCode);
192
193
0
        ResourcePtr ret(prg);
194
0
        addImpl(ret);
195
        // Tell resource group manager
196
0
        if(ret)
197
0
            ResourceGroupManager::getSingleton()._notifyResourceCreated(ret);
198
0
        return static_pointer_cast<GpuProgram>(ret);
199
0
    }
200
    //---------------------------------------------------------------------------
201
    GpuProgramPtr GpuProgramManager::createProgram(const String& name, const String& groupName,
202
                                                   const String& filename, GpuProgramType gptype,
203
                                                   const String& syntaxCode)
204
0
    {
205
0
        GpuProgramPtr prg = createProgram(name, groupName, syntaxCode, gptype);
206
0
        prg->setSourceFile(filename);
207
0
        return prg;
208
0
    }
209
    //---------------------------------------------------------------------------
210
    GpuProgramPtr GpuProgramManager::createProgramFromString(const String& name, 
211
        const String& groupName, const String& code, GpuProgramType gptype, 
212
        const String& syntaxCode)
213
0
    {
214
0
        GpuProgramPtr prg = createProgram(name, groupName, syntaxCode, gptype);
215
0
        prg->setSource(code);
216
0
        return prg;
217
0
    }
218
    //---------------------------------------------------------------------------
219
    const GpuProgramManager::SyntaxCodes& GpuProgramManager::getSupportedSyntax(void)
220
0
    {
221
        // Use the current render system
222
0
        RenderSystem* rs = Root::getSingleton().getRenderSystem();
223
224
        // Get the supported syntaxed from RenderSystemCapabilities 
225
0
        return rs->getCapabilities()->getSupportedShaderProfiles();
226
0
    }
227
228
    //---------------------------------------------------------------------------
229
    bool GpuProgramManager::isSyntaxSupported(const String& syntaxCode)
230
0
    {
231
        // Use the current render system
232
0
        RenderSystem* rs = Root::getSingleton().getRenderSystem();
233
234
        // Get the supported syntax from RenderSystemCapabilities 
235
0
        return rs && rs->getCapabilities()->isShaderProfileSupported(syntaxCode);
236
0
    }
237
    //---------------------------------------------------------------------
238
    GpuSharedParametersPtr GpuProgramManager::createSharedParameters(const String& name)
239
0
    {
240
0
        if (mSharedParametersMap.find(name) != mSharedParametersMap.end())
241
0
        {
242
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
243
0
                "The shared parameter set '" + name + "' already exists!", 
244
0
                "GpuProgramManager::createSharedParameters");
245
0
        }
246
0
        GpuSharedParametersPtr ret(OGRE_NEW GpuSharedParameters(name));
247
0
        mSharedParametersMap[name] = ret;
248
0
        return ret;
249
0
    }
250
    //---------------------------------------------------------------------
251
    GpuSharedParametersPtr GpuProgramManager::getSharedParameters(const String& name) const
252
0
    {
253
0
        SharedParametersMap::const_iterator i = mSharedParametersMap.find(name);
254
0
        if (i == mSharedParametersMap.end())
255
0
        {
256
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
257
0
                        "referenced shared_params '" + name + "' not found");
258
0
        }
259
0
        return i->second;
260
0
    }
261
    //---------------------------------------------------------------------
262
    const GpuProgramManager::SharedParametersMap& 
263
    GpuProgramManager::getAvailableSharedParameters() const
264
0
    {
265
0
        return mSharedParametersMap;
266
0
    }
267
    //---------------------------------------------------------------------
268
    bool GpuProgramManager::getSaveMicrocodesToCache() const
269
0
    {
270
0
        return mSaveMicrocodesToCache;
271
0
    }
272
    //---------------------------------------------------------------------
273
    bool GpuProgramManager::canGetCompiledShaderBuffer()
274
0
    {
275
        // Use the current render system
276
0
        RenderSystem* rs = Root::getSingleton().getRenderSystem();
277
278
        // Check if the supported  
279
0
        return rs->getCapabilities()->hasCapability(RSC_CAN_GET_COMPILED_SHADER_BUFFER);
280
0
    }
281
    //---------------------------------------------------------------------
282
    void GpuProgramManager::setSaveMicrocodesToCache( const bool val )
283
0
    {
284
        // Check that saving shader microcode is supported
285
0
        if(!canGetCompiledShaderBuffer())
286
0
            mSaveMicrocodesToCache = false;
287
0
        else
288
0
            mSaveMicrocodesToCache = val;
289
0
    }
290
    //---------------------------------------------------------------------
291
    bool GpuProgramManager::isCacheDirty( void ) const
292
0
    {
293
0
        return mCacheDirty;     
294
0
    }
295
    //---------------------------------------------------------------------
296
    String GpuProgramManager::addRenderSystemToName( const String & name )
297
0
    {
298
        // Use the current render system
299
0
        RenderSystem* rs = Root::getSingleton().getRenderSystem();
300
301
0
        return rs->getName() + "_" + name;
302
0
    }
303
    //---------------------------------------------------------------------
304
    bool GpuProgramManager::isMicrocodeAvailableInCache( uint32 id ) const
305
0
    {
306
0
        return mMicrocodeCache.find(id) != mMicrocodeCache.end();
307
0
    }
308
    //---------------------------------------------------------------------
309
    const GpuProgramManager::Microcode & GpuProgramManager::getMicrocodeFromCache( uint32 id ) const
310
0
    {
311
0
        return mMicrocodeCache.find(id)->second;
312
0
    }
313
    //---------------------------------------------------------------------
314
    void GpuProgramManager::addMicrocodeToCache( uint32 id, const GpuProgramManager::Microcode & microcode )
315
0
    {   
316
0
        auto foundIter = mMicrocodeCache.find(id);
317
0
        if ( foundIter == mMicrocodeCache.end() )
318
0
        {
319
0
            mMicrocodeCache.insert(make_pair(id, microcode));
320
            // if cache is modified, mark it as dirty.
321
0
            mCacheDirty = true;
322
0
        }
323
0
        else
324
0
        {
325
0
            foundIter->second = microcode;
326
327
0
        }       
328
0
    }
329
    //---------------------------------------------------------------------
330
    void GpuProgramManager::removeMicrocodeFromCache( uint32 id )
331
0
    {
332
0
        auto foundIter = mMicrocodeCache.find(id);
333
334
0
        if (foundIter != mMicrocodeCache.end())
335
0
        {
336
0
            mMicrocodeCache.erase( foundIter );
337
0
            mCacheDirty = true;
338
0
        }
339
0
    }
340
    //---------------------------------------------------------------------
341
    void GpuProgramManager::saveMicrocodeCache( const DataStreamPtr& stream ) const
342
0
    {
343
0
        if (!mCacheDirty)
344
0
            return; 
345
346
0
        if (!stream->isWriteable())
347
0
        {
348
0
            OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
349
0
                "Unable to write to stream " + stream->getName(),
350
0
                "GpuProgramManager::saveMicrocodeCache");
351
0
        }
352
        
353
0
        StreamSerialiser serialiser(stream);
354
0
        serialiser.writeChunkBegin(CACHE_CHUNK_ID, 3);
355
356
        // write the size of the array
357
0
        uint32 sizeOfArray = static_cast<uint32>(mMicrocodeCache.size());
358
0
        serialiser.write(&sizeOfArray);
359
        
360
        // loop the array and save it
361
0
        for ( const auto& entry : mMicrocodeCache )
362
0
        {
363
            // saves the id of the shader
364
0
            serialiser.write(&entry.first);
365
366
            // saves the microcode
367
0
            const Microcode & microcodeOfShader = entry.second;
368
0
            uint32 microcodeLength = static_cast<uint32>(microcodeOfShader->size());
369
0
            serialiser.write(&microcodeLength);
370
0
            serialiser.writeData(microcodeOfShader->getPtr(), 1, microcodeLength);
371
0
        }
372
373
0
        serialiser.writeChunkEnd(CACHE_CHUNK_ID);
374
0
    }
375
    //---------------------------------------------------------------------
376
    void GpuProgramManager::loadMicrocodeCache( const DataStreamPtr& stream )
377
0
    {
378
0
        mMicrocodeCache.clear();
379
380
0
        StreamSerialiser serialiser(stream);
381
0
        const StreamSerialiser::Chunk* chunk;
382
383
0
        try
384
0
        {
385
0
            chunk = serialiser.readChunkBegin();
386
0
        }
387
0
        catch (const InvalidStateException& e)
388
0
        {
389
0
            LogManager::getSingleton().logWarning("Could not load Microcode Cache: " +
390
0
                                                  e.getDescription());
391
0
            return;
392
0
        }
393
394
0
        if(chunk->id != CACHE_CHUNK_ID || chunk->version != 3)
395
0
        {
396
0
            LogManager::getSingleton().logWarning("Invalid Microcode Cache");
397
0
            serialiser.readChunkEnd(CACHE_CHUNK_ID);
398
0
            return;
399
0
        }
400
        // write the size of the array
401
0
        uint32 sizeOfArray = 0;
402
0
        serialiser.read(&sizeOfArray);
403
        
404
        // loop the array and load it
405
0
        for ( uint32 i = 0 ; i < sizeOfArray ; i++ )
406
0
        {
407
            // loads the id of the shader
408
0
            uint32 id;
409
0
            serialiser.read(&id);
410
411
            // loads the microcode
412
0
            uint32 microcodeLength = 0;
413
0
            serialiser.read(&microcodeLength);
414
415
0
            Microcode microcodeOfShader(OGRE_NEW MemoryDataStream(microcodeLength));
416
0
            microcodeOfShader->seek(0);
417
0
            serialiser.readData(microcodeOfShader->getPtr(), 1, microcodeLength);
418
419
0
            mMicrocodeCache.insert(make_pair(id, microcodeOfShader));
420
0
        }
421
0
        serialiser.readChunkEnd(CACHE_CHUNK_ID);
422
423
        // if cache is not modified, mark it as clean.
424
0
        mCacheDirty = false;
425
        
426
0
    }
427
    //---------------------------------------------------------------------
428
    //---------------------------------------------------------------------------
429
    void GpuProgramManager::addFactory(GpuProgramFactory* factory)
430
2
    {
431
        // deliberately allow later plugins to override earlier ones
432
2
        mFactories[factory->getLanguage()] = factory;
433
2
    }
434
    //---------------------------------------------------------------------------
435
    void GpuProgramManager::removeFactory(GpuProgramFactory* factory)
436
0
    {
437
        // Remove only if equal to registered one, since it might overridden
438
        // by other plugins
439
0
        FactoryMap::iterator it = mFactories.find(factory->getLanguage());
440
0
        if (it != mFactories.end() && it->second == factory)
441
0
        {
442
0
            mFactories.erase(it);
443
0
        }
444
0
    }
445
    //---------------------------------------------------------------------------
446
    GpuProgramFactory* GpuProgramManager::getFactory(const String& language)
447
0
    {
448
0
        FactoryMap::iterator i = mFactories.find(language);
449
450
0
        if (i == mFactories.end())
451
0
        {
452
            // use the null factory to create programs that will never be supported
453
0
            i = mFactories.find(sNullLang);
454
0
        }
455
0
        return i->second;
456
0
    }
457
    //---------------------------------------------------------------------
458
    bool GpuProgramManager::isLanguageSupported(const String& lang) const
459
0
    {
460
0
        return mFactories.find(lang) != mFactories.end();
461
0
    }
462
}