Still having problems with calling glTransformFeedbackVaryings

Hi there,

i already posted this in the beginners-forum, but noone seems to know help. So i have a second try here…

My program dosn’t return from calling ‘glTransformFeedbackVaryings’. Even a simple test-code dosn’t work. My GPU should be able to do this (Intel HD4000 / OpenGL 4.0).

This is my code (not the test-code):


    success                 = GL_FALSE;                                         errHandle           = vShNewHandle;
 
    const GLchar* feedbackVaryings[] = { "cppReturn" };
 
[...]
 
    vShNewHandle            = glCreateShader  (GL_VERTEX_SHADER); 
    tcShNewHandle           = glCreateShader  (GL_TESS_CONTROL_SHADER); 
    teShNewHandle           = glCreateShader  (GL_TESS_EVALUATION_SHADER);
    gShNewHandle            = glCreateShader  (GL_GEOMETRY_SHADER);   
    fShNewHandle            = glCreateShader  (GL_FRAGMENT_SHADER);   
    prgNewHandle            = glCreateProgram (); 
 
    clsRegEx hasCode ("[\
\\r][\	 ]*void\\s*main\\s*\\(");      // Regular expresseion to test if a shader-string contains "void main ("
 
    if (hasCode.Matches(vShLnkC)) {
        success                 = GL_FALSE;                                     errHandle           = vShNewHandle;   
        glShaderSource          (vShNewHandle, 1, &vShLnkC, NULL);              glCompileShader     (vShNewHandle); 
        glGetShaderiv           (vShNewHandle,  GL_COMPILE_STATUS, &success);   if (success != GL_TRUE) goto ex;
        glAttachShader          (prgNewHandle, vShNewHandle); 
 
        if (hasCode.Matches(fShLnkC)) {
 
[... - Tesselation-, geometry- & fragment-shader are compiled here if fragment-shader-string ('fShLnkC') contains a main-function]
 
        else {
            glTransformFeedbackVaryings (prgNewHandle, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);    
        }
    }

Any idea what might be the reason?

Best,
Frank

Try this short, stand-alone GLUT test program:


#include <stdio.h>
#include <math.h>
#include <string.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glu.h>
#include <GL/glut.h>

#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(x[0]))

const int TF_NUM_OUT   = 2;
const int TF_OUT_COUNT = 3;
const int TF_OUT_SIZE  = TF_OUT_COUNT * sizeof(float);

GLuint Tf_pgm                   = 0;      // Transform feedback program
GLuint Tf_obj                   = 0;      // Transform feedback object
GLuint Tf_outbuf[ TF_NUM_OUT ];           // Transform feedback output buffer

const int NUM_ATTR = 1;

GLuint Vbo_handle[ NUM_ATTR ];            // Positions


static const char TF_VERT_SHADER[] = R"MAGIC(
  #version 330
  
  in  vec3 vertex;
  out vec3 pos;
  
  void main(void)
  {
    pos = vertex;
  };

)MAGIC";


static const char TF_GEOM_SHADER[] = R"MAGIC(
  #version 400

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

  // Inputs
  in vec3 pos[1];

  // Outputs
  layout( stream=0 ) out float stream0;
  layout( stream=1 ) out float stream1;
  
  void main(void)
  {
    int route = ( pos[0].z >= 1 ) ? 1 : 0;

    switch ( route )
    { 
      case 0  : stream0 = 1234; EmitStreamVertex(0); break;
      case 1  : 
      default : stream1 = 5678; EmitStreamVertex(1); break;
    }
  };

)MAGIC";


//----------------------------------------------------------------------------

void check( const char *s )
{
  GLenum err ;
  bool   found = false;

  while ( (err = glGetError()) != GL_NO_ERROR )
  {
    found = true;
    fprintf ( stderr, "%s: OpenGL Error: %s
", 
              s ? s : "", gluErrorString ( err ) );
  }
  if ( found )
    exit(1);
}

//----------------------------------------------------------------------------

void dumpShaderLog( bool is_shader, GLuint obj )
{
  int maxlen = 0;
  if ( is_shader ) glGetShaderiv ( obj, GL_INFO_LOG_LENGTH, &maxlen );
  else             glGetProgramiv( obj, GL_INFO_LOG_LENGTH, &maxlen );
    
  if ( maxlen > 0 )
  {
    char *log = new char [ maxlen ] ;
    int   len ;

    if ( is_shader )  glGetShaderInfoLog ( obj, maxlen, &len, log );
    else              glGetProgramInfoLog( obj, maxlen, &len, log );

    if( len > 0 && log[0] != '\0' )
      fprintf( stderr, "%s
", log ) ;

    delete [] log ;
  }
}

//----------------------------------------------------------------------------

#define getGL( e, str_width )  \
  do                           \
  {                            \
    GLint v;                   \
    glGetIntegerv( e, &v );    \
    printf( "%-*s = %d
", str_width, #e, v ); \
  }                                           \
  while ( 0 )

//----------------------------------------------------------------------------

void queryGL()
{
  int w = 48;

  printf( "
" );
  getGL( GL_MAX_GEOMETRY_OUTPUT_VERTICES                 , w );
  getGL( GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS         , w );
  getGL( GL_MAX_VERTEX_STREAMS                           , w );
  getGL( GL_MAX_TRANSFORM_FEEDBACK_BUFFERS               , w );
  getGL( GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, w );
  printf( "
" );
}

//----------------------------------------------------------------------------

void initTFProgram( GLuint &tf_pgm )
{
  // Read shader text
  const char *vert_src = TF_VERT_SHADER;
  const char *geom_src = TF_GEOM_SHADER;

  // Compile shaders
  GLint  compiled;
  GLuint vs = glCreateShader( GL_VERTEX_SHADER );
  GLuint gs = glCreateShader( GL_GEOMETRY_SHADER );

  glShaderSource ( vs, 1, &vert_src, 0 );
  glShaderSource ( gs, 1, &geom_src, 0 );

  glCompileShader( vs );
  glGetShaderiv  ( vs, GL_COMPILE_STATUS, &compiled );

  if ( !compiled )
  {
    fprintf( stderr, "TF vertex shader: Failed to compile.
" );
    dumpShaderLog( true, vs );
    exit(1);
  }

  glCompileShader( gs );
  glGetShaderiv  ( gs, GL_COMPILE_STATUS, &compiled );

  if ( !compiled )
  {
    fprintf( stderr, "TF geometry shader: Failed to compile.
" );
    dumpShaderLog( true, gs );
    exit(1);
  }


  GLuint pgm = glCreateProgram();

  glBindAttribLocation( pgm, 0, "vertex" );

  //--------------------------------------------------------------------------
  // Designate TRANSFORM FEEDBACK input varyings, ordering, and storage mode
  //--------------------------------------------------------------------------
  const GLchar *strs[] = { "stream0", "gl_NextBuffer", "stream1" }; 
  glTransformFeedbackVaryings( pgm, ARRAY_SIZE(strs), strs, 
                               GL_INTERLEAVED_ATTRIBS ); 

  
  // Link program
  glAttachShader ( pgm, vs );
  glAttachShader ( pgm, gs );
  glLinkProgram  ( pgm ) ;

  GLint linked;
  glGetProgramiv ( pgm, GL_LINK_STATUS, & linked ) ;
  if ( !linked )
  {
    fprintf( stderr, "TF program: Failed to link.
" );
    dumpShaderLog( false, pgm );
    exit(1);
  }

  tf_pgm = pgm;

  check( "initTFProgram" );
}

//----------------------------------------------------------------------------

void initTFObject( GLuint &tf, GLuint outbuf[ TF_NUM_OUT ] )
{
  //--------------------------------------------------------------------------
  // Create TRANSFORM FEEDBACK object
  //--------------------------------------------------------------------------

  glGenTransformFeedbacks   ( 1, &tf );
  glBindTransformFeedback   ( GL_TRANSFORM_FEEDBACK, tf );

  // Transform feedback:
  //   INPUTS : are program varying(s) (VS or GS output(s))
  //   OUTPUTS: are buffer(s)

  // INPUT: (varying)
  //   NOTE: Input varyings, ordering, and storage mode specified above
  //   before we linked the program.  Those are "program state".

  // OUTPUT: (buffer)
  for ( int i = 0; i < TF_NUM_OUT; i++ )
  {
    glGenBuffers              ( 1, &outbuf[i] );
    glNamedBufferDataEXT      ( outbuf[i], TF_OUT_SIZE, 0, GL_DYNAMIC_DRAW );
    glBindBufferBase          ( GL_TRANSFORM_FEEDBACK_BUFFER, i, outbuf[i] );
  }

  // NOTE: If had wanted to output to a subrange of a buffer, could have
  //   used glBindBufferRange.

  glBindTransformFeedback   ( GL_TRANSFORM_FEEDBACK, 0 );

  check( "initTFObject" );
}

//----------------------------------------------------------------------------

void initBatch()
{
  static const GLfloat pos  [ TF_OUT_COUNT*3 ] = { 0,0,0,
                                                   0,0,1,
                                                   0,0,2 };
                                   
  // Create and fill VBOs
  glGenBuffers( NUM_ATTR, Vbo_handle );

  GLenum gl_target = GL_ARRAY_BUFFER;

  // Positions...
  glBindBuffer( gl_target, Vbo_handle[0] );
  glBufferData( gl_target, sizeof(pos)  , pos  , GL_STATIC_DRAW );
}

//----------------------------------------------------------------------------

void init()
{
  queryGL();

  // Create transform feedback program and object
  initTFProgram( Tf_pgm );
  initTFObject ( Tf_obj, Tf_outbuf );
  initBatch    ();  

  check( "init" );
}

//----------------------------------------------------------------------------

void classifyPoints()
{
  //--------------------------------------------------------------------------
  // Write to TRANSFORM FEEDBACK buffer with vertex shader executions
  //--------------------------------------------------------------------------

  glEnable    ( GL_RASTERIZER_DISCARD );
  glUseProgram( Tf_pgm );

  glBindTransformFeedback ( GL_TRANSFORM_FEEDBACK, Tf_obj );
  glBeginTransformFeedback( GL_POINTS );

  // Render batch (classic VBOs)
  glBindBuffer             ( GL_ARRAY_BUFFER, Vbo_handle[0] );
  glVertexAttribPointer    ( 0, 3, GL_FLOAT, false, 0, 0 );
  glEnableVertexAttribArray( 0 );

  glDrawArrays       ( GL_POINTS, 0, 3 );
  
  glEndTransformFeedback();

  glUseProgram( 0 );
  glDisable   ( GL_RASTERIZER_DISCARD );

  check( "classifyPoints" );
}

//----------------------------------------------------------------------------

float *mapBuffer( int i )
{
  return (GLfloat *) glMapNamedBufferRangeEXT( Tf_outbuf[i], 0, TF_OUT_SIZE, 
                                               GL_MAP_READ_BIT );
}

//----------------------------------------------------------------------------

void unmapBuffer( int i )
{
  glUnmapNamedBufferEXT( Tf_outbuf[i] );
}


//----------------------------------------------------------------------------

void display()
{
  glClearColor(0.4, 0.4, 0.8, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Clear TF output
  memset( mapBuffer(0), '\0', TF_OUT_SIZE ); unmapBuffer(0);
  memset( mapBuffer(1), '\0', TF_OUT_SIZE ); unmapBuffer(1);

  // Generate queries to determine how many entries written
  GLuint outquery[ TF_NUM_OUT ];
  glGenQueries( TF_NUM_OUT, outquery );
  for ( int i = 0; i < TF_NUM_OUT; i++ )
    glBeginQueryIndexed( GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i, 
                         outquery[i] );

  // Transform feedback (bin points into 2 different lists)
  classifyPoints();

  // Query/print how many entries written
  GLint counts[ TF_NUM_OUT ];
  for ( int i = 0; i < TF_NUM_OUT; i++ )
  {
    glEndQueryIndexed ( GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, i );
    glGetQueryObjectiv( outquery[i], GL_QUERY_RESULT, &counts[i] );
    printf( "Num primitives written for output %d = %d
", i, counts[i] );
  }
  glDeleteQueries( TF_NUM_OUT, outquery );

  // Dump TF output
  for ( int i = 0; i < TF_NUM_OUT; i++ )
  {
    printf( "Transform feedback output %d =", i );
    GLfloat *p = mapBuffer(i);
    for ( int j = 0; j < counts[ i ]; j++ )
    {
      printf( " %g", p[j] );
    }
    unmapBuffer(i);
    printf( "
" );
  }

  glutSwapBuffers();
  glutPostRedisplay();

  check( "display" );

  exit(0);
}

//----------------------------------------------------------------------------

void reshape(int w, int h) 
{
  glViewport(0, 0, w, h);
}
 
//----------------------------------------------------------------------------

void keyfunc( unsigned char key, int x, int y )
{
  switch(key)
  {
    case 27 : exit(0); break;  // ESCape
  }
}

//----------------------------------------------------------------------------

int main(int argc, char **argv)
{
  glutInit( &argc, argv );
  glutInitWindowSize( 640, 480 );
  glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
  glutCreateWindow( "Transform Feedback" );

  glutReshapeFunc ( reshape );
  glutDisplayFunc ( display );
  glutKeyboardFunc( keyfunc );

  init();

  glutMainLoop();
  return 0;
}

Compile with:


g++ -std=c++11 -o tf_test tf_test.cxx -lglut -lGLU -lGL

It should generate this output:


GL_MAX_GEOMETRY_OUTPUT_VERTICES                  = 1024
GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS          = 1024
GL_MAX_VERTEX_STREAMS                            = 4
GL_MAX_TRANSFORM_FEEDBACK_BUFFERS                = 4
GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 128

Num primitives written for output 0 = 1
Num primitives written for output 1 = 2
Transform feedback output 0 = 1234
Transform feedback output 1 = 5678 5678

Works fine on NVidia. That said, that does “not” necessarily means there’s no errors in it. But if it doesn’t work for you on Intel, it could be that you’re fighting a driver bug.

Thanks for replying. I’ll test it and write a report. I hope to find time tomorrow…

Okay…
After some days of other work i just saw, that someone answered. Now i red, what you wrote. I’m not sure if i’m able to do this. Its quiet funny: i think, i’m a quiet good progrmmer as a non-professional (currently i think about maybe learning assembler to speed up my self-written interpreter), but i still have problems with any compiler-setup. How i work? Currently i use some kind of “package” which i downloaded at once. It contains a minGW-compiler, the wxWidgets library (which i use as UI) and the gl-library and the old-fashiond devC-IDE. Some weeks ago, i (once again) tried to compile my application using another IDE (code::blocks), without success.
So, for me it might be a problem to compile a

stand-alone GLUT test program.
I’m also not sure if glut is included in my package. Anyway i’ll take the time to find out if your code might help me, but it might take a while…

By the way: i also thougt, it might be a driver-bug. So i downloaded the current one from Intel (mine was older). But nothing changed. This means, that i testet two versions of the driver with the same result. While HD4000 is a standard-GTX and transform-feedbacks are used by lots of applications, a driver-bug seems nearly impossible. To exclude this i also succesfully tried a web-page using WebGL-transormfeedback.
Therefore i’m wondering, what the problem might be: two drivers tested, WebGL works and my program still crashes if i call “glTransformFeedbackVaryings”.

Best,
Frank