Subversion Repository Public Repository

Divide-Framework

This repository has no backups
This repository's network speed is throttled to 100KB/sec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include "Headers/ShaderManager.h"

#include "Core/Headers/ParamHandler.h"
#include "Core/Resources/Headers/ResourceCache.h"
#include "Hardware/Video/Headers/GFXDevice.h"
#include "Hardware/Video/Shaders/Headers/Shader.h"
#include "Geometry/Material/Headers/Material.h"

namespace Divide {

ShaderManager::ShaderManager() :  _init(false),
                                  _imShader(nullptr),
                                  _nullShader(nullptr)
{
}

ShaderManager::~ShaderManager()
{
}

/// Remove the NULL and IM shaders and destroy the API specific shader loading system
void ShaderManager::destroy() {
    RemoveResource(_imShader);
    RemoveResource(_nullShader);
	GFX_DEVICE.deInitShaders();
    _atoms.clear();
}

/// Initialize the shader manager so that it may process program loading requests
bool ShaderManager::init() {    
    // Avoid double init requests
    if (_init) {
        ERROR_FN(Locale::get("WARNING_SHADER_MANAGER_DOUBLE_INIT"));
        return false;
    }
    // Initialize the rendering-API specific shader loading system
    _init = GFX_DEVICE.initShaders();
    // Create an immediate mode rendering shader that simulates the fixed function pipeline
    ResourceDescriptor immediateModeShader("ImmediateModeEmulation");
    immediateModeShader.setThreadedLoading(false);
    _imShader = CreateResource<ShaderProgram>(immediateModeShader);
    assert(_imShader != nullptr);
    // Create a null shader (basically telling the API to not use any shaders when bound)
    _nullShader = CreateResource<ShaderProgram>(ResourceDescriptor("NULL_SHADER"));
    // The null shader should never be nullptr!!!!
    assert(_nullShader != nullptr); //LoL -Ionut

    return _init;
}

/// Whenever a new program is created, it's registered with the manager
void ShaderManager::registerShaderProgram(const stringImpl& name, ShaderProgram* const shaderProgram) {
    ShaderProgramMap::iterator it = _shaderPrograms.find(name);
    // Either update an existing shader
    if (it != _shaderPrograms.end()) {
        MemoryManager::SAFE_UPDATE( it->second, shaderProgram );
    } else {
        // Or register a new one
        hashAlg::emplace(_shaderPrograms, name, shaderProgram);
    }
}

/// Unloading/Deleting a program will unregister it from the manager
void ShaderManager::unregisterShaderProgram(const stringImpl& name) {
    // The shader program must be registered in order to unregister it
    ShaderProgramMap::iterator it = _shaderPrograms.find(name);
    if (it != _shaderPrograms.end()) {
        _shaderPrograms.erase(it);
    } else {
        // Show an error if this isn't the case
        ERROR_FN(Locale::get("ERROR_SHADER_REMOVE_NOT_FOUND"),name.c_str());
    }
}

/// Called once per frame
bool ShaderManager::update(const U64 deltaTime) {
    // Pass the update call to all registered programs
    for ( ShaderProgramMap::value_type& it : _shaderPrograms ) {
        if ( !it.second->update( deltaTime ) ) {
            // If an update call fails, stop updating
            return false;
        }
    }
	return true;
}

/// Calling this will force a recompilation of all shader stages for the program that matches the name specified
bool ShaderManager::recompileShaderProgram(const stringImpl& name) {
    bool state = false;
    // Find the shader program
    for ( ShaderProgramMap::value_type& it : _shaderPrograms ) {
        const stringImpl& shaderName = it.second->getName();
        // Check if the name matches any of the program's name components
        if ( shaderName.find( name ) != stringImpl::npos || shaderName.compare( name ) == 0 ) {
            // We process every partial match. So add it to the recompilation queue
            _recompileQueue.push( it.second );
            // Mark as found
            state = true;
        }
    }
    // If no shaders were found, show an error
    if ( !state ) {
        ERROR_FN( Locale::get( "ERROR_SHADER_RECOMPILE_NOT_FOUND" ), name.c_str() );
    }

    return state;
}

/// Called after a swap buffer request
void ShaderManager::idle(){
    // If we don't have any shaders queued for recompilation, return early
    if ( !_recompileQueue.empty() ) {
        // Else, recompile the top program from the queue
        _recompileQueue.top()->recompile( true, true, true, true, true );
        _recompileQueue.pop();
    }
    return;
}

/// Pass uniform data update call to every registered program
void ShaderManager::refreshShaderData() {
	for (ShaderProgramMap::value_type& it : _shaderPrograms) {
        it.second->refreshShaderData();
    }
}

/// Pass scene data update call to every registered program
void ShaderManager::refreshSceneData() {
	for (ShaderProgramMap::value_type& it : _shaderPrograms) {
        it.second->refreshSceneData();
    }
}

/// Open the file found at 'location' matching 'atomName' and return it's source code
const stringImpl& ShaderManager::shaderFileRead(const stringImpl &atomName, const stringImpl& location) {
    // See if the atom was previously loaded and still in cache
    AtomMap::iterator it = _atoms.find(atomName);
    // If that's the case, return the code from cache
    if (it != _atoms.end()) {
        return it->second;
    }
    // If we forgot to specify an atom location, we have nothing to return
	assert(!location.empty());

    // Open the atom file
    stringImpl file = location+"/"+atomName;
    FILE *fp = nullptr;
    fopen_s(&fp,file.c_str(),"r");
	assert(fp != nullptr);

    // Read the contents
    fseek(fp, 0, SEEK_END);
    I32 count = ftell(fp);
    rewind(fp);
	assert(count > 0);

    char* content = MemoryManager_NEW char[count + 1];
    count = (I32)(fread(content,sizeof(char),count,fp));
    content[count] = '\0';
	fclose(fp);

    // Add the code to the atom cache for future reference
	hashAlg::pair<AtomMap::iterator, bool> result = hashAlg::emplace(_atoms, atomName, stringImpl(content));
	assert(result.second);
    MemoryManager::DELETE_ARRAY( content );
    
    // Return the source code
	return result.first->second;
}

/// Dump the source code 's' of atom file 'atomName' to file
I8 ShaderManager::shaderFileWrite(char *atomName, const char *s) {
    I8 status = 0;

    if (atomName != nullptr) {
        // Create the target file (or open it for writing)
        FILE *fp = nullptr;
        fopen_s(&fp, atomName,"w");
        if (fp != nullptr) {
            // Dump the source code
            if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s)) {
                status = 1;
            }
            // Close the file
            fclose(fp);
        }
    }
    return status;
}

/// Remove a shader entity. The shader is deleted only if it isn't referenced by a program
void ShaderManager::removeShader(Shader* s) {
    // Keep a copy of it's name
    stringImpl name(s->getName());
    // Try to find it
    ShaderMap::iterator it = _shaderNameMap.find(name);
    if (it != _shaderNameMap.end()) {
        // Subtract one reference from it. 
        if (s->SubRef()) {
            // If the new reference count is 0, delete the shader
            MemoryManager::DELETE( it->second );
            _shaderNameMap.erase(name);
        }
    }
}

/// Return a new shader reference
Shader* ShaderManager::getShader(const stringImpl& name, const bool recompile) {
    // Try to find the shader
    ShaderMap::iterator it = _shaderNameMap.find(name);
    if (it != _shaderNameMap.end()) {
        if (!recompile) {
            // We don't need a ref count increase if we just recompile the shader
            it->second->AddRef();
            D_PRINT_FN(Locale::get("SHADER_MANAGER_GET_SHADER_INC"),name.c_str(), it->second->GetRef());
        }
        return it->second;
    }

    return nullptr;
}

/// Load a shader by name, source code and stage
Shader* ShaderManager::loadShader(const stringImpl& name, const stringImpl& source, const ShaderType& type,const bool recompile) {
    // See if we have the shader already loaded
    Shader* shader = getShader(name, recompile);
    if (!recompile) {
        // If we do, and don't need a recompile, just return it
        if (shader != nullptr) {
            return shader;
        }
        // If we can't find it, we create a new one
        shader = GFX_DEVICE.newShader(name, type);
    }
    // At this stage, we have a valid Shader object, so load the source code
    if (!shader->load(source)) {
        // If loading the source code failed, delete it
        MemoryManager::DELETE( shader );
    } else {
        // If we loaded the source code successfully, either update it (if we recompiled) or register it
        if(recompile) {
            _shaderNameMap[name] = shader;
        } else {
            hashAlg::emplace(_shaderNameMap, name, shader);
        }
    }

    return shader;
}

/// Bind the NULL shader which should have the same effect as using no shaders at all
bool ShaderManager::unbind() {
    _nullShader->bind();
    return true;
}

};

Commits for Divide-Framework/trunk/Source Code/Hardware/Video/Shaders/ShaderManager.cpp

Diff revisions: vs.
Revision Author Commited Message
331 Diff Diff IonutCava picture IonutCava Sat 06 Dec, 2014 20:53:45 +0000

[Ionut]
- Limited line length to 132 characters to improve readability and diff-comparisons
- Refactored memory allocation/deallocation functions
- Fixed a few compatibility issues with HashMap.h
- Fixed a bug in GPU Skinning shaders (cast a float to int)

326 Diff Diff IonutCava picture IonutCava Tue 30 Sep, 2014 21:11:32 +0000

[Ionut]
- Fixed more memory leaks
- Simplified Task interface and timing System
- Improved compatibility between Boost, STL and EASTL with random combinations of vectors, strings and maps
- Simplified Light class by removing the “slot” member
- Random optimizations

325 Diff Diff IonutCava picture IonutCava Wed 17 Sep, 2014 20:06:13 +0000

[Ionut]
- Reworked transform system:
— Parent transform chain system moved from Transform class to the PhysicsComponent
— PhysicsComponent now returns all transform values needed both global and local (still needs heavy optimization and caching)

- Reworked SceneGraph node management:
— Proper ref counting of SceneNodes and proper removing of resource (ResourceCache is now empty on destruction, as it should be)
— Removed parent transform tracking as that’s the PhysicsComponent’s responsibility
— Only nodes loaded via the ResourceCache are allowed to be added to the SceneGraph (added proper loaders for Impostors, Sky, etc)

- Optimized some of the math classes (mat4, mat3)

322 Diff Diff IonutCava picture IonutCava Sat 06 Sep, 2014 20:33:47 +0000

[Ionut]
- Refactored most of Boost related code to be C++11 based
— Boost is only used for ThreadPool, Mutex handling, XML parsing and networking (ASIO)
— Function binds, threads, regex, NonCopyable base, Hashing algorithms and more are now using C++11 libraries
- Replaced all FOR_EACH calls with standard, range, “for” calls

321 Diff Diff IonutCava picture IonutCava Wed 03 Sep, 2014 22:05:15 +0000

[Ionut]
- Added support (and enabled by default) for the EASTL library (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html / https://github.com/paulhodge/EASTL)
— Strings, vectors and hash_maps can be combined from EASTL, STL and Boost (not all combinations work. e.g. EASTL strings with STL/Boost containers due to the lack of a proper hash function)

319 Diff Diff IonutCava picture IonutCava Sat 30 Aug, 2014 21:37:57 +0000

[Ionut]
- Performance tweaks based on profiling data

318 Diff Diff IonutCava picture IonutCava Sat 30 Aug, 2014 17:35:53 +0000

[Ionut]
- Wrapped the entire code in a “Divide” namespace
- VertexBuffers now call “shrink_to_fit” on all internal data storage
- Improved some vector performance by preferring “emplace_back” instead of “push_back” + proepr usage of reserve / resize
- Wrapped OIS specific types and classes in Divide::Input namespace
- Added the messageBox.layout file (forgot it in the previous few commits)

301 Diff Diff IonutCava picture IonutCava Tue 05 Aug, 2014 20:55:30 +0000

[Ionut]
- Code cleanups and comments (ShaderManager, ShaderProgram, Texture)
- Fixed some singleton destruction order between ResourceCache and ShaderManager to properly unload remaining shader programs

296 Diff Diff k1ngp1n picture k1ngp1n Sun 03 Aug, 2014 14:54:21 +0000

[Ionut]
- nVidia compatibility fixes (GUI, shadows, post-processing)
- Texture bind slots are now part of ShaderProgram class
- Renamed ForwardRenderer class to ForwardPlusRenderer and moved ligh grid creation to it
- More code cleanups and comments

295 k1ngp1n picture k1ngp1n Fri 01 Aug, 2014 20:10:44 +0000

[Ionut]
- If a shader fails to bind, skip draw call. A shader will fail to bind if it wasn’t linked properly, as well
- Moved ShaderManager to the Hardware project due to its tight coupling
- More code cleanup and comments:
— OpenGL wrapper code : GLWrapper.h, GLWrapper.cpp, GLStates.cpp, glShaderProgram.cpp
- Cleaned up Shader.cpp
- Binary shader dump also saves binary format in .fmt file for each binary shader
- Renamed immediate mode primitive files