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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
#include "Headers/LightPool.h"

#include "Core/Headers/ParamHandler.h"
#include "Core/Time/Headers/ProfileTimer.h"
#include "Managers/Headers/SceneManager.h"
#include "Graphs/Headers/SceneGraphNode.h"
#include "Platform/Video/Headers/GFXDevice.h"
#include "Core/Resources/Headers/ResourceCache.h"
#include "Platform/Video/Textures/Headers/Texture.h"
#include "Platform/Video/Shaders/Headers/ShaderProgram.h"
#include "Rendering/Lighting/ShadowMapping/Headers/ShadowMap.h"
#include "Platform/Video/Buffers/RenderTarget/Headers/RenderTarget.h"
#include "Platform/Video/Buffers/ShaderBuffer/Headers/ShaderBuffer.h"

namespace Divide {

std::array<U8, to_const_uint(ShadowType::COUNT)> LightPool::_shadowLocation = { {
    to_const_ubyte(ShaderProgram::TextureUsage::COUNT) + 2u, //Single
    to_const_ubyte(ShaderProgram::TextureUsage::COUNT) + 3u, //Layered
    to_const_ubyte(ShaderProgram::TextureUsage::COUNT) + 1u  //Cubemap
}};

Light* LightPool::_currentShadowCastingLight = nullptr;

bool LightPool::_previewShadowMaps = false;
bool LightPool::_shadowMapsEnabled = true;

LightPool::LightPool(Scene& parentScene)
    : SceneComponent(parentScene),
      _init(false),
      _lightImpostorShader(nullptr),
      _lightIconsTexture(nullptr),
     // shadowPassTimer is used to measure the CPU-duration of shadow map generation step
     _shadowPassTimer(Time::ADD_TIMER("Shadow Pass Timer"))
{
    _activeLightCount.fill(0);
    _lightTypeState.fill(true);
    _shadowCastingLights.fill(nullptr);
    // NORMAL holds general info about the currently active
    // lights: position, colour, etc.
    _lightShaderBuffer[to_const_uint(ShaderBufferType::NORMAL)] = nullptr;
    // SHADOWS holds info about the currently active shadow
    // casting lights:
    // ViewProjection Matrices, View Space Position, etc
    _lightShaderBuffer[to_const_uint(ShaderBufferType::SHADOW)] = nullptr;

    ParamHandler::instance().setParam<bool>(_ID("rendering.debug.displayShadowDebugInfo"), false);

    init();
}

LightPool::~LightPool()
{
    clear();
    MemoryManager::DELETE(_lightShaderBuffer[to_uint(ShaderBufferType::NORMAL)]);
    MemoryManager::DELETE(_lightShaderBuffer[to_uint(ShaderBufferType::SHADOW)]);
}

void LightPool::init() {
    if (_init) {
        return;
    }

    GFX_DEVICE.add2DRenderFunction(
        DELEGATE_BIND(&LightPool::previewShadowMaps, this, nullptr), 1);
    // NORMAL holds general info about the currently active lights: position, colour, etc.
    _lightShaderBuffer[to_const_uint(ShaderBufferType::NORMAL)] = GFX_DEVICE.newSB(1,
                                                                                   true,
                                                                                   false,
                                                                                   BufferUpdateFrequency::OCASSIONAL);
    // SHADOWS holds info about the currently active shadow casting lights:
    // ViewProjection Matrices, View Space Position, etc
    // Should be SSBO (not UBO) to use std430 alignment. Structures should not be padded
    _lightShaderBuffer[to_const_uint(ShaderBufferType::SHADOW)] = GFX_DEVICE.newSB(1,
                                                                                   true,
                                                                                   false,
                                                                                   BufferUpdateFrequency::OCASSIONAL);

    _lightShaderBuffer[to_const_uint(ShaderBufferType::NORMAL)]
        ->create(Config::Lighting::MAX_POSSIBLE_LIGHTS, sizeof(LightProperties));

    _lightShaderBuffer[to_const_uint(ShaderBufferType::SHADOW)]
        ->create(Config::Lighting::MAX_SHADOW_CASTING_LIGHTS, sizeof(Light::ShadowProperties));

    ResourceDescriptor lightImpostorShader("lightImpostorShader");
    lightImpostorShader.setThreadedLoading(false);
    _lightImpostorShader = CreateResource<ShaderProgram>(lightImpostorShader);

    SamplerDescriptor iconSampler;
    iconSampler.toggleMipMaps(false);
    iconSampler.setAnisotropy(0);
    iconSampler.setWrapMode(TextureWrap::REPEAT);
    ResourceDescriptor iconImage("LightIconTexture");
    iconImage.setThreadedLoading(false);
    iconImage.setPropertyDescriptor<SamplerDescriptor>(iconSampler);
    stringImpl iconImageLocation =
        Util::StringFormat("%s/misc_images/lightIcons.png",
            ParamHandler::instance().getParam<stringImpl>(_ID("assetsLocation")).c_str());
    iconImage.setResourceLocation(iconImageLocation);
    iconImage.setEnumValue(to_const_uint(TextureType::TEXTURE_2D));
    _lightIconsTexture = CreateResource<Texture>(iconImage);

    _init = true;
}

bool LightPool::clear() {
    if (!_init) {
        return true;
    }

    SceneGraph& sceneGraph = _parentScene.sceneGraph();
    for (Light::LightList& lightList : _lights) {
        // Lights are removed by the sceneGraph
        // (range_based for-loops will fail due to iterator invalidation
        vectorAlg::vecSize lightCount = lightList.size();
        for (vectorAlg::vecSize i = lightCount; i--> 0;) {
            Light* crtLight = lightList[i];
            sceneGraph.getRoot().removeNode(*crtLight->getSGN());

        }
        lightList.clear();
    }
    _init = false;
    
    return true;
}

bool LightPool::addLight(Light& light) {
    light.addShadowMapInfo(MemoryManager_NEW ShadowMapInfo(&light));

    const LightType type = light.getLightType();
    const U32 lightTypeIdx = to_const_uint(type);

    if (findLight(light.getGUID(), type) != std::end(_lights[lightTypeIdx])) {

        Console::errorfn(Locale::get(_ID("ERROR_LIGHT_POOL_DUPLICATE")),
                         light.getGUID());
        return false;
    }

    vectorAlg::emplace_back(_lights[lightTypeIdx], &light);

    return true;
}

// try to remove any leftover lights
bool LightPool::removeLight(I64 lightGUID, LightType type) {
    Light::LightList::const_iterator it = findLight(lightGUID, type);

    if (it == std::end(_lights[to_uint(type)])) {
        Console::errorfn(Locale::get(_ID("ERROR_LIGHT_POOL_REMOVE_LIGHT")),
                         lightGUID);
        return false;
    }

    _lights[to_uint(type)].erase(it);  // remove it from the map
    return true;
}

void LightPool::idle() {
    _shadowMapsEnabled = ParamHandler::instance().getParam<bool>(_ID("rendering.enableShadows"));
}


/// When pre-rendering is done, the Light Manager will generate the shadow maps
/// Returning false in any of the FrameListener methods will exit the entire
/// application!
bool LightPool::generateShadowMaps(SceneRenderState& sceneRenderState) {
    if (!_shadowMapsEnabled) {
        return true;
    }
    ShadowMap::clearShadowMapBuffers();
    Time::ScopedTimer timer(_shadowPassTimer);
    // generate shadowmaps for each light
    I32 idx = 0;
    for (Light* light : _shadowCastingLights) {
        if(light != nullptr) {
            Attorney::SceneRenderStateLightPool::shadowLightIndex(sceneRenderState, idx++);
            _currentShadowCastingLight = light;
            light->validateOrCreateShadowMaps(sceneRenderState);
            light->generateShadowMaps(sceneRenderState);
        }
    }

    Attorney::SceneRenderStateLightPool::shadowLightIndex(sceneRenderState , -1);
    _currentShadowCastingLight = nullptr;
    return true;
}

void LightPool::togglePreviewShadowMaps() {
    _previewShadowMaps = !_previewShadowMaps;
    // Stop if we have shadows disabled
    if (!_shadowMapsEnabled || GFX_DEVICE.getRenderStage() != RenderStage::DISPLAY) {
        ParamHandler::instance().setParam( _ID("rendering.debug.displayShadowDebugInfo"), false);
    } else {
        ParamHandler::instance().setParam( _ID("rendering.debug.displayShadowDebugInfo"), _previewShadowMaps);
    }
}

void LightPool::previewShadowMaps(Light* light) {
#ifdef _DEBUG
    // Stop if we have shadows disabled
    if (!_shadowMapsEnabled || !_previewShadowMaps || _lights.empty() ||
        GFX_DEVICE.getRenderStage() != RenderStage::DISPLAY) {
        return;
    }

    // If no light is specified show as many shadowmaps as possible
    if (!light) {
        U32 rowIndex = 0;
        for (Light* shadowLight : _shadowCastingLights) {
            if (shadowLight != nullptr &&
                shadowLight->getShadowMapInfo()->getShadowMap() != nullptr)
            {
                shadowLight->getShadowMapInfo()->getShadowMap()->previewShadowMaps(rowIndex++);
            }
        }
        return;
    }

    if (light && light->castsShadows()) {
        assert(light->getShadowMapInfo()->getShadowMap() != nullptr);
        light->getShadowMapInfo()->getShadowMap()->previewShadowMaps(0);
    }
#endif
}

// If we have computed shadowmaps, bind them before rendering any geometry;
void LightPool::bindShadowMaps() {
    // Skip applying shadows if we are rendering to depth map, or we have
    // shadows disabled
    if (!_shadowMapsEnabled) {
        return;
    }

    ShadowMap::bindShadowMaps();
}

bool LightPool::shadowMappingEnabled() {
    return _shadowMapsEnabled;
}

Light* LightPool::getLight(I64 lightGUID, LightType type) {
    Light::LightList::const_iterator it = findLight(lightGUID, type);
    assert(it != std::end(_lights[to_uint(type)]));

    return *it;
}

void LightPool::updateAndUploadLightData(const vec3<F32>& eyePos, const mat4<F32>& viewMatrix) {
    // Sort all lights (Sort in parallel by type)   
    TaskHandle cullTask = CreateTask(DELEGATE_CBK_PARAM<bool>());
    for (Light::LightList& lights : _lights) {
        if (!lights.empty()) {
            cullTask.addChildTask(CreateTask(
                [&eyePos, &lights](const std::atomic_bool& stopRequested) mutable
                {
                    std::sort(std::begin(lights), std::end(lights),
                              [&eyePos](Light* a, Light* b) -> bool
                    {
                        return a->getPosition().distanceSquared(eyePos) <
                               b->getPosition().distanceSquared(eyePos);
                    });
                })._task
            )->startTask(Task::TaskPriority::HIGH);
        }
    }

    cullTask.startTask(Task::TaskPriority::HIGH);
    cullTask.wait();

    vec3<F32> tempColour;
    // Create and upload light data for current pass
    _activeLightCount.fill(0);
    _shadowCastingLights.fill(nullptr);
    U32 totalLightCount = 0;
    U32 lightShadowPropertiesCount = 0;
    for(Light::LightList& lights : _lights) {
        for (Light* light : lights) {
            LightType type = light->getLightType();
            U32 typeUint = to_uint(type);

            if (!light->getEnabled() || !_lightTypeState[typeUint]) {
                continue;
            }

            if (totalLightCount >= Config::Lighting::MAX_POSSIBLE_LIGHTS) {
                break;
            }

            LightProperties& temp = _lightProperties[typeUint][_activeLightCount[typeUint]];
            light->getDiffuseColour(tempColour);
            temp._diffuse.set(tempColour, light->getSpotCosOuterConeAngle());
            // Non directional lights are positioned at specific point in space
            // So we need W = 1 for a valid positional transform
            // Directional lights use position for the light direction. 
            // So we need W = 0 for an infinite distance.
            temp._position.set(viewMatrix.transform(light->getPosition(), type != LightType::DIRECTIONAL),
                               light->getRange());
            // spot direction is not considered a point in space, so W = 0
            temp._direction.set(viewMatrix.transformNonHomogeneous(light->getSpotDirection()),
                                light->getSpotAngle());

            temp._options.x = typeUint;
            temp._options.y = light->castsShadows();
            if (light->getLightType() == LightType::DIRECTIONAL) {
                temp._options.w = static_cast<DirectionalLight*>(light)->csmSplitCount();
            }

            if (light->castsShadows() &&
                lightShadowPropertiesCount < Config::Lighting::MAX_SHADOW_CASTING_LIGHTS) {

                temp._options.z = to_int(lightShadowPropertiesCount);
                _lightShadowProperties[lightShadowPropertiesCount] = light->getShadowProperties();
                _shadowCastingLights[lightShadowPropertiesCount] = light;
                lightShadowPropertiesCount++;
            }

            totalLightCount++;
            _activeLightCount[typeUint]++;
        }

    }

    // Passing 0 elements is fine (early out in the buffer code)
    U32 offset = 0;
    for (U32 type = 0; type < to_const_uint(LightType::COUNT); ++type) {
        U32 range = _activeLightCount[type];
        _lightShaderBuffer[to_const_uint(ShaderBufferType::NORMAL)]->updateData(offset, range, _lightProperties[type].data());
        offset = range;
    }

    uploadLightData(ShaderBufferLocation::LIGHT_NORMAL);
    
    _lightShaderBuffer[to_const_uint(ShaderBufferType::SHADOW)]->updateData(0, lightShadowPropertiesCount, _lightShadowProperties.data());
    _lightShaderBuffer[to_const_uint(ShaderBufferType::SHADOW)]->bind(ShaderBufferLocation::LIGHT_SHADOW);
}

void LightPool::uploadLightData(ShaderBufferLocation location) {
    _lightShaderBuffer[to_const_uint(ShaderBufferType::NORMAL)]->bind(location);
}

void LightPool::drawLightImpostors() const {
    if (!_previewShadowMaps) {
        return;
    }

    assert(_lightImpostorShader);
    const U32 directionalLightCount = _activeLightCount[to_const_uint(LightType::DIRECTIONAL)];
    const U32 pointLightCount = _activeLightCount[to_const_uint(LightType::POINT)];
    const U32 spotLightCount = _activeLightCount[to_const_uint(LightType::SPOT)];
    const U32 totalLightCount = directionalLightCount + pointLightCount + spotLightCount;
    if (totalLightCount > 0) {
        _lightIconsTexture->bind(to_const_ubyte(ShaderProgram::TextureUsage::UNIT0));


        GenericDrawCommand pointsCmd;
        pointsCmd.primitiveType(PrimitiveType::API_POINTS);
        pointsCmd.drawCount(to_ushort(totalLightCount));
        pointsCmd.stateHash(GFX_DEVICE.getDefaultStateBlock(true));
        pointsCmd.shaderProgram(_lightImpostorShader);

        GFX_DEVICE.draw(pointsCmd);
    }
}

};

Commits for Divide-Framework/trunk/Source Code/Rendering/Lighting/LightPool.cpp

Diff revisions: vs.
Revision Author Commited Message
727 Diff Diff IonutCava picture IonutCava Tue 14 Jun, 2016 16:01:38 +0000

[IonutCava]
- Remove node and cmd buffers from GFXDevice and add them as a new BufferData struct to RenderPass class.
— Each render pass holds its own buffers
- Improvements / fixes to the CSM code
- Added a global toggle to enable/disable custom memory allocators

725 Diff Diff IonutCava picture IonutCava Fri 10 Jun, 2016 12:44:46 +0000

[IonutCava]
- Removed GFX drawPoints and drawTriangle calls and replaced them with a single draw command that takes a GenericDrawCommand parameter.
- Updated CSM code. Shadows now render in the correct position again. Still has issues.

722 Diff Diff IonutCava picture IonutCava Thu 09 Jun, 2016 16:15:33 +0000

[IonutCava]
- Restructure RenderTarget system:
— Separate attachments, use an attachment pool, use draw descriptors, require explicit information for RT calls, etc

721 Diff Diff IonutCava picture IonutCava Wed 08 Jun, 2016 15:47:49 +0000

[IonutCava]
- Spelling: change all references from our code of “color” to the PROPER British version of “colour” because it sounds 100x better

718 Diff Diff IonutCava picture IonutCava Thu 02 Jun, 2016 16:02:48 +0000

[IonutCava]
- Code cleanup:
— Rename Framebuffer to RenderTarget. Only OpenGL uses the Framebuffer nomenclature.
— Remove base Shader class as only OpenGL will have separate shaders (and eventually move to pipeline objects) as Direct3D uses FX files and may end up with different structure
— Remove drawBox3D, drawSphere3D and drawLines from GFXDevice class and add them as member functions to the IMPrimitive class (renamed to fromXYZ)
— Pull some elements from SceneManager and move them to standalone classes (W.I.P.)

717 Diff Diff IonutCava picture IonutCava Wed 01 Jun, 2016 16:09:11 +0000

[IonutCava]
- Added initial code for 2 test scenes: ShadowScene and ReflectionScene that will be used to fix and update the shadowing and the reflection systems respectively
- More scene switch bug fixes
— XML scene data is now optional. Scenes can be created entirely form code if needed

713 Diff Diff IonutCava picture IonutCava Wed 25 May, 2016 15:43:38 +0000

[IonutCava]
- Removed all unique_ptr’s from the code with classic new/delete pairs. They were seriously not needed.
- Added the concept of SceneComponent to scene specific classes: aiManager, lightPool, sceneGraph, physicsInterface etc
— This allowed the removal of the global GET_ACTIVE_SCENEGRAPH call;

712 Diff Diff IonutCava picture IonutCava Tue 24 May, 2016 16:18:37 +0000

[IonutCava]
- Added the concept of “buffer” to be used by GenericVertexData and ShaderBuffer without caring if it’s persistent or not.
— Persistent buffers handle their own locking instead of relying on the parent class
- HiZ occlusion culling fixes and optimizations

709 Diff Diff IonutCava picture IonutCava Thu 19 May, 2016 16:21:46 +0000

[IonutCava]
- Massive rewrite of the resource system:
— ResourceCache now uses a map of weak pointers and passes shared pointers to the call point of CreateResource
— RemoveResource is no longer needed, but resource based smart pointers use a custom deleter that calls unload()
— Keep a shared_ptr of the resource in the entity that needs it and pass shared_ptr references from getter methods
-— All of this removed the need for calls to RemoveResource, REGISTER_TRACKED_DEPENDENCY and UNREGISTER_TRACKED_DEPENDENCY reducing the number of mutex locks and atomic exchanges
- Singleton cleanup:
— Removed ShaderManager singleton and merged it’s data and responsibilities in static methods in both ShaderProgram and Shader classes.
Explanation: Due to the complex interdependency chains in the system, copying, updating, tracking the cache in a thread safe way became a lot more slower than a straight forward smart pointer based implementation. (e.g. scene graph nodes have 3d objects and material instances, 3d objects have materials, materials have textures and shaders, etc)

708 IonutCava picture IonutCava Tue 17 May, 2016 14:06:13 +0000

[IonutCava]
- Fixed reference counter getting out of sync between multiple scene graphs and the ResourceCache
- Added per SGN update flags for SceneNodes
- Fixed some memory leaks (caught by the ResourceCache)