# How can I improve the performance of my custom Global Illumination approach?

I want to experiment with some new stuff about modern rendering techniques and in that way I'm trying to implement a custom GI (somewhere between pathtracing and instant radiosity). My scene is a bit less than 1,000,000 tris and my algorithm requires to render the same scene a lot of times into different tiny textures (let's call them "bounces").

I've began my implementation in a naive way so I rapidly ran into some performance problems:
With my 1TFlops laptop GPU I can render my 1M poly scene I can have 200 "bounces" before dropping bellow 30FPS which is far from enough.

My "naive" algorithm looks like this in pseudo code:

for (unsigned int i = 0; i < res ; ++i) {
UpdateCameraUniform(i);
glBindFramebuffer(GL_FRAMEBUFFER, BounceFbo[i]);
glDrawBuffers(1, renderBuffer[i]);
for (Mesh& m : Scene) {
m.render();
}
}


with

Mesh::render() {
UpdateTransformUniform();
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);
}


The full code is here (the depot is really messy for now...).

I need to find a new strategy to render my scene so I searched what I could do.
I think I have 2 strategies:

1. Trying to reduce the number (or the performance) of my drawcalls. It seems that there is some magic function like glMultiDraw* (I've found it in a post on "OpenGL superbible" here). But I don't really understand what this does:

• Does this render multiple times the same mesh?
• Different mesh but with one shader?
• Different mesh with different shader but just with low CPU overhead?
2. Trying to reduce the render time while rendering multiple times the same mesh in "Bounces" using the same technique as this but I have absolutely no idea how it works or even if it can apply to me...

Obviously I am open to any other suggestions.

Edit: I can reach 200 "bounces" not 35

• @trichoplax yes but my reputation was not high enough to put more than 2 link so I changed it and then forgot to change my sentence sorry =/ I will fix it Nov 20, 2016 at 17:50
• I (finally) fixed it Nov 22, 2016 at 17:47

You should always profile to determine where your slowdown occurs. From your question, it's unclear whether your work is CPU bound or GPU bound.

But I don't really understand what is does: Does this render a multiple time the same mesh ? different mesh but with one shader ? different mesh with different shader but just with low CPU overhead ?

The glMultiDraw* draw commands are for allowing you to render multiple objects in one draw call. In terms of OpenGL 3.0 and later, this means that you could specify a VBO holding a bunch of objects and use glMultiDraw* to render them. You would use this with the same shader. If you want to render the same object multiple times, then using something such as instancing would be a good solution.

This all concerns draw calls though. If you have one million triangles for only a few meshes, you won't see a massive speedup with rendering. You didn't specify your framebuffer size, but if it's small enough, you can cause severe overdraw from many small triangles. If the images are really that small, maybe you should think about adding an LOD system or use lower polygon meshes and tessellate.

trying to reduce the render time while rendering multiple time the same mesh in "Bounces" using the same technique than this

Stereo instanced rendering is specifically a technique for VR. It relies on the assumption that the scene is pretty much identical in each eye, and so it uses instancing to render to two sides of the screen at once. However, if your bounces render similar geometry, then you may be able to render multiple bounces onto a larger framebuffer provided that the bounces are independent. There is potential for speedup from avoiding framebuffer switching (which is a rather expensive process).

In newer OpenGL versions (4.0 and above), there is added support for indirect rendering, which allows you to determine parameters through GPU computing, but it's unclear if that will help you in this case.

• My CPU load reach rarely more than 30% when I'm bellow 20FPS so I am GPU bound. For my glMultiDraw* problem for now I use matrices to move my objects (the UpdateTransformUniform() call) is this possible to link glMultiDrawElements to a buffer of uniform or something like this? For my buffers, my final buffers are 4 1920x1080 (I'm using deffered rendering) and my bounces are 4 64x64 (will be replaced to 1 64x64 soon). For the algorythm: should I loop over my bounces in every mesh using instances rendering or loop glMultiDraw my mesh for every bounces. Nov 20, 2016 at 18:36
• Actually, I think this is what you would want if you're using uniform transformation matrices: glDrawElementsInstancedBaseVertexBaseInstance (OpenGL 4.2). Here's more info about it: gamedev.net/topic/…
– aces
Nov 21, 2016 at 5:31
• I ask a similar question to the once you are asking here: computergraphics.stackexchange.com/questions/4241/…
– aces
Nov 21, 2016 at 5:41
• Either way, it's not going to make a huge difference if your performance limited by the GPU. With a 64x64 grid, you are going to be doing a lot of overdrawing, even for a deferred renderer, so you should start optimizing there. But in terms of your followup question, I would go through that slideshow I linked and see if that can help you in your situation (extending it to a grid rather than two screens).
– aces
Nov 21, 2016 at 5:42
• Okay I'm almost good, last question: it looks like the stereo instanced rendering seems to use 1 render target split in 2 but I have multiple FBO. I cannot find a way to use instances across multiple FBO, is this possible, if yes how ? Nov 25, 2016 at 20:09

A common approach for real-time radiosity in games is to assume static geometry, which can be used to pre-calculate visible surfels (position, albedo, normal) for a point in space (light probe). This approach avoids the need for run-time rasterization of the geometry for different viewpoints. The surfels can be then dynamically re-lit in run-time and used to gather luminance for the probe, which is used to approximate the indirect illumination.