Skip to content

Commit 7fe6be9

Browse files
author
Alin
committed
added readme to the example
1 parent 0cc5787 commit 7fe6be9

File tree

6 files changed

+187
-12
lines changed

6 files changed

+187
-12
lines changed

example/Readme.md

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# ThreadedRenderingGL Example
2+
Based on NVIDIA's Gameworks GL Threading example, it was adapted to a deferred renderer with multiple volumetric lights to exemplify command buffer usage.
3+
4+
It shows more advanced usage of how to use commands recording, pod hints, creating a material binder, prioritize custom commands, dispatch and have multiple command buffers for a deferred renderer.
5+
6+
![pic-main](example/screenshot.png)
7+
8+
## Usage
9+
Requires Visual Studio 2017.
10+
You can click on the top left arrow to open the example settings menu.
11+
12+
## Breakdown
13+
The example is composed of several worker theads that all issue GL commands, there are n-1 animation threads that issue vbo update commands for the fish animation and also draw commands. And also an additional thread for issuing defferred commands
14+
15+
There are several buffer modes for async updates(recommended to also check the original NVIDIA example which has more modes):
16+
```cpp
17+
enum
18+
{
19+
TECHNIQUE_GLES_SUBRANGE = 0,
20+
TECHNIQUE_GLES_SUBRANGE_PERSISTENT,
21+
TECHNIQUE_GLES_ORPHANED,
22+
TECHNIQUE_GLES_POOLED,
23+
TECHNIQUE_GLES_POOLED_PERSISTENT,
24+
TECHNIQUE_COUNT
25+
};
26+
```
27+
28+
### Material Binder
29+
In order to reduce state changes commands are sorted according to their material id.
30+
Thus you'll need to create a material binder that will handle the binding of materials, see Buffers.h.
31+
A material will be defined as:
32+
```cpp
33+
struct Material
34+
{
35+
std::string name;
36+
GLuint location = 0;
37+
GLuint ubo = 0;
38+
NvGLSLProgram* shader = nullptr;
39+
};
40+
```
41+
42+
And the bind operator must be implemented to the Material Binder:
43+
```cpp
44+
///@note Returns true if there are more passes to bind.
45+
CB_FORCE_INLINE bool operator()(cb::MaterialId material) const
46+
{
47+
if (material.id == 0) // first material is a dummy, nothing to bind
48+
return false;
49+
50+
const Material& mat = materials[material.id];
51+
assert(mat.shader);
52+
if (mat.shader != activeShader)
53+
{
54+
//bind only if different shaders
55+
mat.shader->enable();
56+
activeShader = mat.shader;
57+
}
58+
if (material.id != activeMaterial)
59+
{
60+
// bind material ubo
61+
glBindBufferBase(GL_UNIFORM_BUFFER, mat.location, mat.ubo);
62+
activeMaterial = material.id;
63+
}
64+
65+
return false;
66+
}
67+
```
68+
69+
In the above case the material pass is ignored, which gets incremented in the command buffer submit, however if a material has more passes you will need to return true until all material passes are complete.
70+
71+
### Command buffers
72+
There are 3 command buffers, see Buffers.h:
73+
```cpp
74+
typedef cb::CommandBuffer<cb::DrawKey, cb::DefaultKeyDecoder, Nv::MaterialBinder> GeometryCommandBuffer;
75+
typedef cb::CommandBuffer<uint32_t,cb::DummyKeyDecoder<uint32_t>> DeferredCommandBuffer;
76+
typedef cb::CommandBuffer<uint16_t,cb::DummyKeyDecoder<uint16_t>> PostProcessCommandBuffer;
77+
```
78+
79+
The GeometryCommandBuffer will be used to fill the GBuffer, thus the geometry pass.
80+
While the deferred pass(see ThreadedRenderingGL::DrawPointLightCommand) will be handled by the DeferredCommandBuffer with additive blending enabled when the pass begins.
81+
Finally post processing, like volumetric lights(see ThreadedRenderingGL::PostProcessVolumetricLight), will be handled by the PostProcessCommandBuffer.
82+
83+
Before submitting commands they first be sorted, also a custom sorting functor can be passed:
84+
```cpp
85+
m_geometryCommands.sort(radixsort<GeometryCommandBuffer::command_t>);
86+
m_deferredCommands.sort();
87+
m_postProcessCommands.sort();
88+
```
89+
NOTE. Radix sort is recommend for geometry commands as it will usually be faster for sorting integers.
90+
91+
A custom logger can be set via:
92+
```cpp
93+
m_geometryCommands.setLogFunction(&commandLogFunction);
94+
m_deferredCommands.setLogFunction(&commandLogFunction);
95+
m_postProcessCommands.setLogFunction(&commandLogFunction);
96+
```
97+
98+
### Comands
99+
Commands can be private, inside a class like ThreadedRenderingGL::InitializeCommand(see ThreadedRenderingGL.h for more) or can be public like cmds::WaitFenceCommand(see Commands.h).
100+
Drawing commands can be found at NvInstancedModelExtGL.h: RenderNonInstanced, RenderInstanced, RenderInstancedUpdate and UpdateVertexBinder.
101+
102+
For setting up kDispatchFunction member you can do it from a static function or from a command member via cb::makeExecuteFunction:
103+
```cpp
104+
// via a static method
105+
const cb::RenderContext::function_t WaitFenceCommand::kDispatchFunction = &waitFenceCommand;
106+
107+
// or via member and helper
108+
const cb::RenderContext::function_t NvInstancedModelExtGL::RenderNonInstanced::kDispatchFunction = &cb::makeExecuteFunction<NvInstancedModelExtGL::RenderNonInstanced>;
109+
110+
```
111+
112+
Commands that have non-POD members will required a hint as the linear allocator won't call the ctr:
113+
```cpp
114+
struct DrawPointLightCommand
115+
{
116+
static const cb::RenderContext::function_t kDispatchFunction;
117+
// hint that we dont care about ctr/dtr
118+
typedef void pod_hint_tag;
119+
120+
LightingUBO lightingUBO_Data; // non-pod member
121+
...
122+
```
123+
124+
### Command keys
125+
For the command keys the default cb::DrawKey is used.
126+
Custom commands are issued before executing the draw commands, like upading the VBOs for the schools:
127+
```cpp
128+
// in ThreadedRenderingGL.cpp:454
129+
cb::DrawKey key = cb::DrawKey::makeCustom(cb::ViewLayerType::eHighest, 10);
130+
auto& cmd = *m_geometryCommands.addCommand<cmds::VboPoolUpdateCommand>(key);
131+
// in School.cpp:665
132+
cb::DrawKey key = cb::DrawKey::makeCustom(cb::ViewLayerType::eHighest, 10);
133+
auto& cmd = *geometryCommands.addCommand<cmds::VboUpdate>(key);
134+
```
135+
136+
Each school will have it's own material:
137+
```cpp
138+
int materialId = schoolIndex + 1; // first material is reserved
139+
pSchool->SetMaterial(cb::TranslucencyType::eOpaque, materialId);
140+
auto& mat = m_geometryCommands.materialBinder().materials[materialId];
141+
mat.name = "Fish school:";
142+
mat.name += std::to_string(schoolIndex);
143+
mat.shader = m_shader_Fish;
144+
mat.ubo = ubo.first;
145+
mat.location = ubo.second;
146+
```
147+
148+
To take advantage of early-z culling opaque draw calls will be sorted in front to back order:
149+
```cpp
150+
// draw front to back order for early-z culling
151+
nv::vec4f position = projView * nv::vec4f(m_lastCentroid.x, 1.f);
152+
float invDepth = (1.f - position.z / position.w);
153+
invDepth *= 10000.f;
154+
m_pInstancedModel->DrawKey().setDepth(invDepth);
155+
```
156+
157+
### Command recording
158+
Since we copy in the command all the data required from issuing commands we can reuse the previous submited commands and not clear the command buffers:
159+
```cpp
160+
const bool clearCommands = !m_animPaused; // using recorded commands when paused
161+
// nothing to pass as GL doesn't have any contexts
162+
m_geometryCommands.submit(nullptr, clearCommands);
163+
m_deferredCommands.submit(nullptr, clearCommands);
164+
m_postProcessCommands.submit(nullptr, clearCommands);
165+
```
166+
167+
Also because the VBOs dont change while the animations are paused when recording we exclude the vbo update commands:
168+
```cpp
169+
if (m_forceUpdateMode != ForceUpdateMode::eForceDispatch)
170+
{
171+
m_schools[i]->Animate(getClampedFrameTime(), &m_schoolStateMgr, m_avoidance);
172+
// Dispatch vbo update commands
173+
m_schools[i]->Update(m_geometryCommands);
174+
}
175+
```
176+
177+
But you can also use other command buffers only for VBO updates that would simplify the recording logic.
178+
179+
## License
180+
181+
The code is available under a custom license as it based on [NVIDIA's Gameworks Samples](https://github.com/NVIDIAGameWorks/GraphicsSamples), see license.txt.
182+
Code that is not part of the Gameworks example is avaiable under the MIT license.

example/ThreadedRenderingGL/Buffers.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Nv
2222
///@note Returns true if there are more passes to bind.
2323
CB_FORCE_INLINE bool operator()(cb::MaterialId material) const
2424
{
25-
if (material.id == 0) // first material is a dummy
25+
if (material.id == 0) // first material is a dummy, nothing to bind
2626
return false;
2727

2828
const Material& mat = materials[material.id];

example/ThreadedRenderingGL/School.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ uint32_t School::Render(const nv::matrix4f& projView, uint32_t batchSize, Geomet
699699
return drawCallCount;
700700
}
701701

702-
// draw closest opaque first for early-z culling
702+
// draw front to back order for early-z culling
703703
nv::vec4f position = projView * nv::vec4f(m_lastCentroid.x, 1.f);
704704
float invDepth = (1.f - position.z / position.w);
705705
invDepth *= 10000.f;
@@ -716,6 +716,7 @@ void School::SetMaterial(cb::TranslucencyType translucency, uint32_t materialId)
716716
m_pInstancedModel->DrawKey().setViewLayer(cb::ViewLayerType::e3D, translucency);
717717
m_pInstancedModel->DrawKey().setMaterial(materialId);
718718
}
719+
719720
void School::FindNewGoal()
720721
{
721722
m_schoolGoal = ScaledRandomVector(m_flockParams.m_spawnZoneMax

example/ThreadedRenderingGL/ThreadedRenderingGL.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -1167,9 +1167,7 @@ static NvTweakEnum<uint32_t> RENDER_TECHNIQUES[] =
11671167
{ "(GLES) Persistent VBO SubRanges", ThreadedRenderingGL::TECHNIQUE_GLES_SUBRANGE_PERSISTENT },
11681168
{ "(GLES) Orphaned VBOs", ThreadedRenderingGL::TECHNIQUE_GLES_ORPHANED },
11691169
{ "(GLES) VBO Pool", ThreadedRenderingGL::TECHNIQUE_GLES_POOLED },
1170-
{ "(GLES) Persistent VBO Pool", ThreadedRenderingGL::TECHNIQUE_GLES_POOLED_PERSISTENT },
1171-
{ "(AZDO) VBO Pool", ThreadedRenderingGL::TECHNIQUE_GLAZDO_POOLED },
1172-
{ "(AZDO) Persistent VBO Pool", ThreadedRenderingGL::TECHNIQUE_GLAZDO_POOLED_PERSISTENT }
1170+
{ "(GLES) Persistent VBO Pool", ThreadedRenderingGL::TECHNIQUE_GLES_POOLED_PERSISTENT }
11731171
};
11741172

11751173

@@ -1212,7 +1210,7 @@ void ThreadedRenderingGL::initUI(void)
12121210
mTweakBar->addValue("Number of Worker Threads", m_uiThreadCount, 1, MAX_THREAD_COUNT, 1, UIACTION_ANIMTHREADCOUNT);
12131211
mTweakBar->addValue("Batch Size (Fish per Draw Call)", m_uiBatchSize, 1, MAX_INSTANCE_COUNT, 1, UIACTION_BATCHSIZE,
12141212
&m_pBatchSlider, &m_pBatchVar);
1215-
mTweakBar->addMenu("Mode", m_uiRenderingTechnique, &(RENDER_TECHNIQUES[0]), TECHNIQUE_GLAZDO_POOLED, UIACTION_RENDERINGTECHNIQUE);
1213+
mTweakBar->addMenu("Mode", m_uiRenderingTechnique, &(RENDER_TECHNIQUES[0]), TECHNIQUE_COUNT, UIACTION_RENDERINGTECHNIQUE);
12161214
mTweakBar->addMenu("BRDF", (uint32_t&)m_brdf, &(BRDF_OPTIONS[0]), BRDF_COUNT, UIACTION_UIBRDF);
12171215
var = mTweakBar->addValue("Use Volumetric Lights", m_useVolumetricLights);
12181216
addTweakKeyBind(var, NvKey::K_V);
@@ -1695,10 +1693,6 @@ NvUIEventResponse ThreadedRenderingGL::handleReaction(const NvUIReaction &react)
16951693
case TECHNIQUE_GLES_POOLED_PERSISTENT:
16961694
policy = Nv::VBO_POOLED_PERSISTENT;
16971695
break;
1698-
case TECHNIQUE_GLAZDO_POOLED:
1699-
case TECHNIQUE_GLAZDO_POOLED_PERSISTENT:
1700-
policy = m_ESVBOPolicy;
1701-
break;
17021696
}
17031697

17041698
const cb::DrawKey key(0); // execute at the end of the frame as vbo may still be in bound

example/ThreadedRenderingGL/ThreadedRenderingGL.h

-2
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,6 @@ class ThreadedRenderingGL : public NvSampleAppGL
105105
TECHNIQUE_GLES_ORPHANED,
106106
TECHNIQUE_GLES_POOLED,
107107
TECHNIQUE_GLES_POOLED_PERSISTENT,
108-
TECHNIQUE_GLAZDO_POOLED,
109-
TECHNIQUE_GLAZDO_POOLED_PERSISTENT,
110108
TECHNIQUE_COUNT
111109
};
112110

example/screenshot.PNG

6.9 MB
Loading

0 commit comments

Comments
 (0)