Geometry shader output streams (for binning instances)

Need some help from GLSL syntax gurus. I’m looking for a generic way to output to multiple streams without having to hard-code explicit logic for each stream in the geometry shader.

For example, I know you can do this:


  #version 400

  layout( points )                   in ;
  layout( points, max_vertices = 1 ) out;

  // Outputs
  layout( stream=0 ) out float data0;
  layout( stream=1 ) out float data1;
  layout( stream=2 ) out float data2;
  layout( stream=3 ) out float data3;
  ...

  void main(void)
  {
    int output = determineOutput();

    switch ( output )
    { 
      case 0  : data0 = my_data; EmitStreamVertex(0); break;
      case 1  : data1 = my_data; EmitStreamVertex(1); break;
      case 2  : data2 = my_data; EmitStreamVertex(2); break;
      case 3  : data3 = my_data; EmitStreamVertex(3); break;
      ...
    }
  };

But this copy/paste/modify code is undesirable, and I might have 10, 20, or 30+ different output streams with 4 or 5 outputs per stream.

Any tips? Trying to avoid re-sifting the list N times.

What I really want is something like this:


#version 400

layout( points ) in ;
layout( points, max_vertices = 1 ) out;

// Outputs
layout( streams ) out float data;

void main(void)
{
  int output = determineOutput();

  data = my_data;
  EmitStreamVertex( output );
};

where I don’t have to hard-code the number of streams in the shader. But EmitStreamVertex explicitly says it only takes a constant integral argument, and I don’t see a way to define an output that applies to any requested stream.

Thanks.

Just noticed that GL_MAX_VERTEX_STREAMS is 4 even on this relatively recent GL 4.x hardware (which is what GL 4.3 requires). That’s inconvenient.

Could multipass, but probably time for a different approach. Thoughts?

I don’t think there is a way to avoid the crux of your problem: wanting to arbitrarily choose where to output which data, without having a switch statement.

Every method for outputting data, whether it’s streams, regular shader outputs, or even writing to image variables, ultimately requires either an integral constant expression or a dynamically uniform expression.

Through the use of image variables, you can avoid the limited stream count issue. You’ll of course need your own atomic variable to figure out how to insert it into the next slot in the image variable. But while image variable arrays are allowed, the array index has to be a dynamically uniform expression. And even then, you can only have a limited number of image variables. It’s required to be at least 8 (but only in the fragment/compute shader).

So ultimately, you’re going to need to use a switch statement.

I don’t think there is a way to avoid the crux of your problem: wanting to arbitrarily choose where to output which data, without having a switch statement.

Hmm. Ok, thanks.

Reading up a bit on what’s out there for GPU binning, one common method (popularized 4 years back by ATI) which gets you past this limitation seems to be computing the bin index in the vertex shader (gl_Position) and then using normal point rasterization to toss the data in that bin. Has its own shortcomings though. Have a few other options to explore as well.

Through the use of image variables, you can avoid the limited stream count issue. You’ll of course need your own atomic variable to figure out how to insert it into the next slot in the image variable. But while image variable arrays are allowed, the array index has to be a dynamically uniform expression. And even then, you can only have a limited number of image variables. It’s required to be at least 8 (but only in the fragment/compute shader).

Thanks for the tip.

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