Block/struct scoping for varyings

So I was playing a bit more with stream out geometry shaders (link), and gave another go at avoiding the needless copy/paste/modify for declaring all the stream outputs and for populating those outputs when you want to send the exact same list of 5 to 10 output values to 1 of 4 output streams. That is, to avoid:


layout( stream=0 ) out float stream0var1;
layout( stream=1 ) out float stream1var1;
layout( stream=2 ) out float stream2var1;
layout( stream=3 ) out float stream3var1;

layout( stream=0 ) out float stream0var2;
layout( stream=1 ) out float stream1var2;
...
layout( stream=0 ) out float stream0var10;

Using a struct to group the output vars seemed promising. It compiles with no problems.


// Outputs
struct OutStruct
{ 
  float var1;
  float var2;
};

layout( stream=0 ) out OutStruct out0;
layout( stream=1 ) out OutStruct out1;

...
out0 = OutStruct( 1234, -1 );
EmitStreamVertex(0);
...

However, the link fails because it can’t find out0.var1, out0.var2, etc. (registered with glTransformFeedbackVaryings). Apparently while the struct scopes the struct members properly in the shader, the compiler loses this scoping info. You can register “var1” and “var2” with glTransformFeedbackVaryings, but who knows which stream output it’s attaching to. There’s no way AFAICT to designate “which” stream you’re referring to when you use those unscoped vars.

So I tried another approach: structs in blocks.


layout( stream=0 ) out Out0 { OutStruct out0; };
layout( stream=1 ) out Out1 { OutStruct out1; };

Same as above but with changed varying declarations. This compiles and links (with varyings registered being out0.var1, out0.var2, etc.). However, anything the shader tries to output on stream other than 0 (for instance, stream 1:


out1 = OutStruct( 5678, -1 );
EmitStreamVertex(1);

is never registered as a primitive output by GL. That is, never bumps the GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN count for that stream output. But stream 0 works fine – I get all the primitive outputs that should have gone to stream 0, and only those outputs.

Am I doing something obviously wrong here?

Here’s the full shader in case someone wants to run it through the compiler:


#version 400
layout( points ) in ;
layout( points, max_vertices = 1 ) out;

// Inputs
in vec3 pos[1];

// Outputs
struct OutStruct
{ 
  float var1;
  float var2;
};

layout( stream=0 ) out OutStruct out0;
layout( stream=1 ) out OutStruct out1;

//layout( stream=0 ) out Out0 { OutStruct out0; };
//layout( stream=1 ) out Out1 { OutStruct out1; };

void main(void)
{
  int route = ( pos[0].z >= 1 ) ? 1 : 0;

  switch ( route )
  { 
    case 0 : out0 = OutStruct( 1234, -1 ); EmitStreamVertex(0); break;
    case 1 : 
    default : out1 = OutStruct( 5678, -1 ); EmitStreamVertex(1); break;
  }
};

Adding an instance name to the block doesn’t help. I still only get output on stream 0.

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