Having Many Lights Calculated in one Shader

Hi, I have been doing some reading on the subject of tile-based deferred rendering, and I have been thinking about implementing one myself. I’ve come across one problem though, it seems (from my understanding at least) that your supposed to calculate the lighting for each tile in one shader pass (to reduce the amount of times you sample from the G-Buffer). In my old deferred renderer, I just was drawing fullscreen quads that sampled from the G-Buffer, and I tried having one shader calculate lighting from 7 lights (passed in as uniform arrays) and although on my GPU (GTX 480) this worked well, and saved a lot of fill rate, when I tested it one a laptop (with a GT 540M) it didn’t seem to work. I was able to narrow the problem down to the instruction limit of the fragment shader. Having 7 lights made the fs seemed to break the instruction limit, which odiously caused problems. When I limited the shader to 1 light, it worked great. So, to my question how, if you are at all, are you supposed to have the lighting from several lights calculated in the fs without passing the instruction limit?

If you don’t want to read that my question is: How do you calculate lighting for several lights in the fragment shader, without passing the instruction limit?

You don’t.

Part of the point of a deferred renderer is that you don’t do all the lights at once. You accumulate each light (or small number of lights) per lighting pass. So instead of running a 7 light shader, you run a 1-light shader with 7 different lights, adding the contribution from each on each pass. Or you run 2-light shaders 3 times and a 1-light shader once.

You also don’t need to render a full-screen quad if a particular light doesn’t affect everywhere on the screen. Indeed, you could render a sphere that covers the limit of a particular light’s range.

Okay, yeah. I am talking about a tile based deferred renderer. The idea is too separate the screen into small tiles to cull the scene for lighting. Here is a good presentation going over it.

download-software.intel.com/sites/default/files/m/d/4/1/d/8/lauritzen_deferred_shading_siggraph_2010.pdf

The idea is to batch the lights together for each tile and minimize reading from the G-Buffer. The same type of system was used if Frostbite 2. In this presentation and in other things I’ve read about tile-based systems, it seems like the idea is to render with multiple lights per shader pass per tile, if that makes sense… Or am I wrong?

Thanks for starting that topic.

[QUOTE=Alfonse Reinheart;1249445]You don’t.

Part of the point of a deferred renderer is that you don’t do all the lights at once. You accumulate each light (or small number of lights) per lighting pass. So instead of running a 7 light shader, you run a 1-light shader with 7 different lights, adding the contribution from each on each pass. Or you run 2-light shaders 3 times and a 1-light shader once.

You also don’t need to render a full-screen quad if a particular light doesn’t affect everywhere on the screen. Indeed, you could render a sphere that covers the limit of a particular light’s range.[/QUOTE]

Isn’t the point of deferred rendering to not calculate all the lights per fragment since most fragments behind other fragments will be discarded? Using multiple passes to accumulate light is called Multipass Rendering and can be used together with deferred rendering by first getting the “outer shell” of the scene and then running the multiple passes to accumulate light. For what he’s trying to do, I’d say he’s trying to group lights and thus have arrays of lights in one shader pass.

@Spaceman1701: Is your array of lights inside a uniform block? I just did a quick test of 14 lights in one shader pass and it didn’t seem to change anything. Of course my lighting computations might be a lot less complex than yours and my hardware might be better, but I think the problem is you’re using something like:

struct Light {
    ...
};

Light lights[7];

While you could be doing:

struct Light {
    ...
};
uniform Lights {
    Light lights[7];
};

I tried using an array of Light structs in my own program and it complains about the instruction limit, but it doesn’t when I use Uniform Buffer Objects.

One or a small number of shader passes, yes. How many passes depends on how many light sources that you process within each shader iteration. This is determined on things like the max number of lights one shader iteration can process, whether there are different light source types represented in the same tile and how you handle that case, etc.

Also note that you do this not only to reduce the number of times you sample from the G-buffer, but to reduce the number of times you have to read/additive_blend/write to the lighting buffer.

In my old deferred renderer, I just was drawing fullscreen quads that sampled from the G-Buffer, and I tried having one shader calculate lighting from 7 lights (passed in as uniform arrays) and although on my GPU (GTX 480) this worked well, and saved a lot of fill rate, when I tested it one a laptop (with a GT 540M) it didn’t seem to work. I was able to narrow the problem down to the instruction limit of the fragment shader. Having 7 lights made the fs seemed to break the instruction limit … So, to my question how, if you are at all, are you supposed to have the lighting from several lights calculated in the fs without passing the instruction limit?

Typically instruction limits can be avoided merely by telling your shader compiler “not” to unroll loops, and you writing your shader code such that it doesn’t have to. Then the number of lights you can handle per shader pass is only limited by the max amount of uniform data you can pull in via the uniform passing method you choose to use. You just have a loop over all of the light sources to be applied in that pass, and on each pass you index the uniform data for the appropriate light source. In other words, you only have the code/instructions in there for applying one light source though you may be applying 20 or so.

What you’re talking about is a basic (v1) deferred renderer where your light source application loop is over light sources. He’s talking about tile-based deferred, where the loop is over screen tiles. The light sources have already been binned into those tiles.

i actually struggle to find anything specific about how this (v2.0?:)) deferred rendering technique goes along with shadows on local lights.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.