best way to store a massive amount of data available to a shader pogrom

What is the best way of sending a lot of data to a shader?

In my deferred rendering pipeline, i’d like to send the deets of 1,000 point lights, 1,000 spotlights and 1,000 directional lights to a fragment shader

I don’t want to have to split it up, big feature to have one shader do this

I read somewhere that shaders are limited to ~1 thousand uniforms and on some platforms even less so they obviously dont cut it

I need to store for each point light: (7)
*pos(3)
*range
*color(3)

each spotlight: (9)

  • pos(3)
  • range
    *color(3)
  • angle
  • attenuation

and each directional light: (6)

  • dir(3)
  • color(3)

so I need some way of storing 6,000 + 9,000 + 7,000 = 22,000 floating point numbers (I got flunked out of multiplication class in 3rd grade)

Suggestions? I’ll take anything. I really don’t want to have to do this shader over and over. Feels like wasted potential.

Uniform Buffer Objects: https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object

I hope you’re not proposing to loop over all of those thousands of lights in your shader though…

GL_MAX_SHADER_STORAGE_BLOCK_SIZE is required to be at least 227 (=128 MiB) in 4.6. GL_MAX_TEXTURE_BUFFER_SIZE is required to be at least 65536 (that’s in texels, each of which can hold 4 floats). So those are sufficient. GL_MAX_UNIFORM_BLOCK_SIZE is only required to be at least 16384 (bytes, so 4096 floats).

But for a deferred shader, you might render individual light volumes, in which case you could use per-instance attributes.

[QUOTE=mhagain;1291160]Uniform Buffer Objects: https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object

I hope you’re not proposing to loop over all of those thousands of lights in your shader though…[/QUOTE]

That’s exactly what I intend to do, but only to the limit of what a uniform int is set to
E.g.
NumPointLights
NumSpotLights
NumDirLights

I’m trying to support a reasonably infinite number of lights.

[QUOTE=Geklmin;1291168]That’s exactly what I intend to do, but only to the limit of what a uniform int is set to
E.g.
NumPointLights
NumSpotLights
NumDirLights

I’m trying to support a reasonably infinite number of lights.[/QUOTE]

That’s going to run like shit.

Not only that, but you’re going to find it difficult to integrate shadows should the time come when you want to do shadows (and you will).

Games like Doom 3 which do the kind of lighting you’re interested in don’t do it this way. Instead they multi-pass, with each light being a separate pass using additive blending. This ran well on 2004-era hardware, so you shouldn’t make pre-emptive assumptions about performance.

I’m not going to do shadows in the same pass

All shadowed lights get their own pass

and yes I know that it would run like shit with a thousand lights

i’m going to use a uniform variable to do static branching on the number of lights (e.g. loop over all the lights)

Although if you can think of a better way, tell me

wait… did I read that correctly? Multiple passes is really faster?

That doesn’t make sense to me, but since you say that, and since it is easier for me to do, I guess i’ll try it

I just… You know… it seems like just extra uniform binds and draw calls of my screenquad…

also seems like extra texture samples of my initial opaque pass (since every single call will have to draw another screenquad and therefore sample the textures in the G-buffer pass multiple times)

if multiple passes is really faster, there must be some sort of huge optimization going on in the background that i’m just totally oblivious to