Transform-feedback / glGetAttribLocation

Hi there,

one more question…

First time trying to realize a transfom-feedback (which is also the first time, where i use vertex-attributes), i wonder why this:

GLint tffInput = glGetAttribLocation(prg, "tffInput");

might return -1 as value for tffInput. The value for prg is correct and it is already linked without errors.

The vertex-shader i use is a quiet simple one only to see if it works:

void main()    {
    cppReturn = sqrt(tffInput);
}

Best,
Frank

If the shader doesn’t reference the vertex attribute in ways that affect the output, then the compiler my compile out all references to the attribute (aka dead code elimination). IIRC this will be indicated when querying attribute and uniform locations by returning -1.

Hey!

Sorry, for the long time. Worked on my UI in between…

Puh! I was hardly confused about your comment. You’re surely right. I forgot to post some code. The shader-code is actually


// for transform feedback
in  float tffInput;
out float cppReturn;

void main()    {
    cppReturn = sqrt(tffInput);
}

Maybe you also have to know, that i have a working application, where i want to integrate the tf. So in fact there is happening more then i just wrote. For example, there is a runtime-shader-editor working in the backgruond, while i did thist test. Also my program is not static and most of what is happening ist contolled by some kind of interpreter. What i mean is that the following code is not written in C. It is part of a string, wihich is interpreted at runtime:


        ccColor         .UpdateRGB();

//        ResetGL_TexSettings();

//glColor4f       (1, 1, 1, 1);
//        glColor3fv      (ccColor.Color);
//        specColor       = vcLight.Get01();
        glMaterialf     (GL_FRONT_AND_BACK, GL_SHININESS, vcEdge.Get01());
        glMaterialfv    (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ccColor.Color);
        glMaterialfv    (GL_FRONT_AND_BACK, GL_SPECULAR, [vcLight.Get01(),vcLight.Get01(),vcLight.Get01()]);

        glMatrixMode    (GL_TEXTURE);      glPushMatrix ();
        glMatrixMode    (GL_MODELVIEW);    glPushMatrix ();

        selTexture      .Apply();

        selPosition     .Apply();
        Radius          = vcScale.Get() * (0.1 * pow(4, selLevel.GetInt() + 1) + 1) * 0.25;
        glScalef        (Radius, Radius, Radius);

        selVBO          .Apply();

        glMatrixMode    (GL_TEXTURE);      glPopMatrix  ();
        glMatrixMode    (GL_MODELVIEW);    glPopMatrix  ();

For the tf-test, i reduced the overhead as much as possible without completly restructurating everything, but there is still a lot of things done next to the tf. This is also, why i forgot to post the in-out-part of the shader-function. In fact, it is not possible to collect all the code, which is really executed.
Half the C-code looks like this:


        else if (!strcmp (nam, "sin"))       {  (num1) = (sin(list[0][0]));                            }
        else if (!strcmp (nam, "sign"))      {  (num1) = ((list[0][0] < 0 ? -1 : list[0][0] < 0 ? 1 : 0));     } 
        
        else if (!strcmp (nam, "strcmp"))    {  (num1) = (strcmp((char*)list[0], (char*)list[1]));         } 
[...]
        else if (!strcmp (nam, "gluPerspective")) {   gluPerspective( list[0][0], list[1][0], list[2][0], list[3][0]  );   }

But anway…

The tf is mostly written in C in the current state, even if i use parts of my application, like the shader-editor.

Today i tried again the tf. The result is stll the same (even if i changed a bit on the program in between, which could have had some effect concerning this). I think there is a somple mistake i do. I oriended my tf-test on this: https://open.gl/feedback and i tried to transfer everything in my program in the correct order. What is basically done in one frame-loop is:

[ul]
[li]System-timer calls interprerter
[/li][li]Some CPU-sided calculations are done to generate parameters like color-values
[/li][li]Rendereing begins. Different FBOs are rendered internally.
[/li][li]After each OpenGL is “resetted” to a kind of basic state
[/li][li]One of these rendering-processes is the tf. Therefore…
[/li]
[li]The interpreter compiles and links the tf-shader
[/li][li]The interpreter checks if some uniforms should be given to the program and transfers them (this might be a problem, because in fact there are some uniform like i.e. the frame-counter which integrated in every shader-program automaticly by my program - so they are also in the tf-vertex shader…)
[/li][li]After this, the interpreter calls a fixed C-function (see below) which does the rest of the tf-rendering
[/li][li]When all the internal rendering is done, the output starts and the UI is updated.
[/li][/ul]

The code of the fixed C-function with the tff is currently (unformated and with a lot of test-trash):


void ParseDrawRenderTFF(clsControl *Control, clsLst &list) {       
  
  while ( glGetError() != GL_NO_ERROR) ;  

//    theorie:
//    ----------------
//    Shader ist bereits aktiviert. Enthält:
//      in  float tffInput; 
//      out float cppReturn
//
//    VAO erzeugen (noch nie gemacht - wofür?)
        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

//    Array von "list" erzeugen
        GLfloat data[list.size];                    
        for (int i=0; i < list.size; i++) data[i] = list[i][0];

//    VBO von array" erzeugen
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
GLenum err;
if ( glGetError() != GL_NO_ERROR) wxMessageBox("err0");;  

//    Übergabeadress für Attribut "inValue" ermitteln
GLint prg;
glGetIntegerv(GL_CURRENT_PROGRAM, &prg);
Print(tostr(prg));
        GLint tffInput = glGetAttribLocation(prg, "tffInput");
err = glGetError();
if ( err != GL_NO_ERROR) Print("err1");;  


        glEnableVertexAttribArray(tffInput);
err = glGetError();
if ( err != GL_NO_ERROR) 
    Print(    tostr(GL_NO_ERROR)+" (no err val)
"    +(
        err == GL_INVALID_ENUM                  ? "GL_INVALID_ENUM" 
      : err == GL_INVALID_VALUE                 ? "GL_INVALID_VALUE" 
      : err == GL_INVALID_OPERATION             ? "GL_INVALID_OPERATION" 
      : err == GL_INVALID_FRAMEBUFFER_OPERATION ? "GL_INVALID_FRAMEBUFFER_OPERATION" 
      : err == GL_OUT_OF_MEMORY                 ? "GL_OUT_OF_MEMORY" 
      : err == GL_STACK_UNDERFLOW               ? "GL_STACK_UNDERFLOW" 
      : err == GL_STACK_OVERFLOW                ? "GL_STACK_OVERFLOW" 
    :"err2 " + tostr(err))+" " + tostr(tffInput));;  

        glVertexAttribPointer(tffInput, 1, GL_FLOAT, GL_FALSE, 0, 0);

if ( glGetError() != GL_NO_ERROR) Print("err3");;  

//    Gleich großen Zielbuffer erzeugen mit
        GLuint tbo;
        glGenBuffers(1, &tbo);
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), NULL, GL_STATIC_READ);

if ( glGetError() != GL_NO_ERROR) Print("err4");;  
        
//    PROZESS:
        glEnable(GL_RASTERIZER_DISCARD);
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);

        glBeginTransformFeedback(GL_POINTS);
            glDrawArrays(GL_POINTS, 0, list.size);
        glEndTransformFeedback();
    
        glFlush();
    
//    Ergebnis auslesen:
        GLfloat feedback[list.size];
        glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), feedback);

        Print(tostr(data[0]) + " - " + tostr(feedback[1]) + " - " + tostr(feedback[2]) + " - " + tostr(data[3]) + " - " + tostr(data[4]));
//    Aufräumen:
        // glDisable           (GL_RASTERIZER_DISCARD);    muss nicht - ist in ResetGL();
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDeleteBuffers(1, &tbo);
        glDeleteBuffers(1, &vbo);
        glDeleteVertexArrays(1, &vao);
    
}     

Would be nice if someone had an idea, where / how to serch the -1 problem.

Thank you!
Frank

This is a bad idea, and may very well be covering up the cause of the problem that’s tripping you up.


// for transform feedback
in  float tffInput;
out float cppReturn;
 
void main()    {
    cppReturn = sqrt(tffInput);
} 

I see that you got your vertex shader here:

[ul]
[li]Transform Feedback (open.gl) [/li][/ul]
This vertex shader shouldn’t compile. You should be checking for shader compile errors and program link errors (LINK and LINK).

What I get when I try to compile your shader here on NVidia GL drivers:


TF vertex shader: Failed to compile.
0(4) : error C5060: out can't be used with non-varying cppReturn

In order to compile this, you’re going to need something like the following prepended to the top of the vertex shader:


#version 130

Any version later than 130 should be fine (e.g. 330, etc.). This shader just isn’t valid in GLSL version 1.1 (#version 110), which is the default if you don’t specify a #version directive.

Thanks for your time at first!

This glGetError-loop was just for this test. In fact, i never used glGetError before. So there were some errors cued, when wrote this. This was just to clear the cue at this point.

This vertex shader shouldn’t compile. You should be checking for shader compile errors and program link errors

My shader-processing was (until these days) the only part of my application, which has has complete error-handling-routine. The shader compiles as it is (maybe a special of my Intel HD4000?). But this remembers me that i filtered out the warnigs there. Maybe i have to make them visible…

Concerning

#version 130

I tried 330 just some minutes ago - still having errors.

In General:
Today i worked out two things: I implemented a better error-handeling (not at least a lot of glGetError-calls all over the program) and i refined all the program-parts that work with shaders. Especiall i implemente a possibility to bypass parts of it, which are not needed. In effect a huge amount of the upper mentioned overhead is eleminated now. Especially: I can now say for sure, what is done and in which order.

The OpenGL-process with the tff-function calls a “reset” fisrt, where mostly some OpenGL-flags are set to a initial value. This function is sometihng like a barrier between different renderings. Here it is (okay: two functions):

void ResetGL_TexSettings() {
    glMatrixMode        (GL_TEXTURE);
    for (int i = 0; i < 10; i++) {      
        glActiveTexture (GL_TEXTURE0 + i);      
        glDisable       (GL_TEXTURE_2D);    glLoadIdentity  ();              
        glTexEnvf       (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,   GL_REPLACE);                                
        glTexParameteri (GL_TEXTURE_2D,  GL_TEXTURE_WRAP_S,     GL_REPEAT);                                 
        glTexParameteri (GL_TEXTURE_2D,  GL_TEXTURE_WRAP_T,     GL_REPEAT);                                 
        glTexParameteri (GL_TEXTURE_2D,  GL_TEXTURE_MAG_FILTER, GL_LINEAR);                                 
        glTexParameteri (GL_TEXTURE_2D,  GL_TEXTURE_MIN_FILTER, GL_LINEAR);                                 
    }   
    glMatrixMode        (GL_MODELVIEW);
    glActiveTexture     (GL_TEXTURE0);
    glEnable            (GL_TEXTURE_2D);                                                                    
    glColor4f           (1, 1, 1, 1);   
    Debug(1,"ResetGL_TexSettings");
}                                                                               
void ResetGL() {                                                                               
    glUseProgram        (0);                curPRG = 0;     curTEX = -1;                                                     
                                                                    
    ResetGL_TexSettings (); 
    
    glDisable           (GL_RASTERIZER_DISCARD);
    glDisable           (GL_DEPTH_TEST);   
    glEnable            (GL_CULL_FACE);   
    glEnable            (GL_MULTISAMPLE);   glSampleCoverage    (0.5, GL_FALSE);
    glDisable           (GL_BLEND);         glBlendFunc         (GL_ONE, GL_ZERO);                                                                  
    glDisable           (GL_COLOR_MATERIAL);                                                                
    glDisable           (GL_LIGHTING);                                                                      
    glDisable           (GL_COLOR_LOGIC_OP);                                                                
    glDisable           (GL_FOG);                                                                           
    glColor4f           (1, 1, 1, 1); 
    
    glFogi              (GL_FOG_MODE, GL_EXP2);

    glLightModeli       (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
    //glLightModeli       (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
                                                                              
    float lightPosition[] = {12.0f, 12.0f, 12.0f, 0.0f};                                                
    glLightfv           (GL_LIGHT0, GL_POSITION, lightPosition);                                           
}

… okay, i should clean them a bit.

After this, the shader is comiled (successfully, as already said), which is done by a huge function. The shader now includes only the few lines menioned before. Nothing more.
In the next step is the fixed tff-function is called. There i did no relevant changes. So it is still almost the same like in the post above. Already some weeks ago i started to implement a global log-file, where i added a lot of outputs today. So i’m now sure, that nothing unwated is happening in beween. That means that i “isolated” tff-thread form most of the other things in my program, but still the error is there.
The next days, i will hopefully find the time to look over this fixed tff-function again, but i currently have no idea, what i can change there. Maybe i’ll write a version for my interpreter. Then i can do tests without compiling the C-program…

PS. glGetInteger reports 128 GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS - so my hardware should do it…

Best,
Frank

While today trying furtherhin, to get it to work, i wondered (again) about this:

        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);  

For me it seems that it has no use? Where is refered to the vao, or does it just have to be stayed bound that it’ll be used? And where for?

Furtherhin i found out, that the -1 error which appers after glEnableVertexAttribArray, comes not from there. Already glGetAttribLocation returns -1. So its obvous that the array can’t be enabled. But still i don’t know why this happens.

If i understood this right, i can alternativliy use glBindAttributeLocation, which i have to call before attaching the v-shader to the program, in order to use a fixed index instead of glGetAttribLocation. I tried this. The result is: No error-messages at all, but the feedback still returns values of 0.

Best,
Frank

Edit:
I’m sorry about staying at this topic, but i really think i have to get it to work. Also it seems, that it’s quiet simple compared with other things, i do. I’ve spent a long time in the development of my UI and an interpreter, which can call most OpenGL-functions, which i did in order to fill it with advanced OpenGL-functions. For the UI-deveopment i used a only few basic OpenGL-functions, after i had understood the concept. Now the “background” mostly works, and i stuck at the first step, using more OpenGL then the things i used for testing my program! :mad:
Especiall this feedback-thing is important for me. Things like this (or even more advanced: compute-shader - where i’m far away from), which use the graphic-engine for calculations are in the end where i created my program for. So it can’t give up here…

[QUOTE=art-ganseforth;1292646]While today trying furtherhin, to get it to work, i wondered (again) about this:

        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);  

For me it seems that it has no use? Where is refered to the vao, or does it just have to be stayed bound that it’ll be used? And where for?[/QUOTE]
It just needs to be bound. In OpenGL 3+ core profile, all state relating to attribute arrays (plus the current element array buffer binding) is stored in the currently-bound VAO. It’s an error to modify this state or issue draw calls if no VAO is bound.

Prior to 3.0, attribute array state was part of the context. In the compatibility profile there exists a default VAO with a name (handle) of zero which is bound by default, so there’s always a VAO bound.

It means that the attribute doesn’t exist. Check that the shader compiled and linked correctly. If the attribute’s value isn’t used, it may be eliminated. You may need a suitable fragment shader simply to prevent the vertex shader’s outputs from being considered unused.

glBindAttribLocation() does nothing if the attribute name doesn’t exist. It doesn’t generate errors. Also, with later versions of GLSL you can use e.g. [var]layout(location=0)[/var] to set the attribute location in the shader code.

It just needs to be bound. In OpenGL 3+ core profile, all state relating to attribute arrays (plus the current element array buffer binding) is stored in the currently-bound VAO. It’s an error to modify this state or issue draw calls if no VAO is bound.

Prior to 3.0, attribute array state was part of the context. In the compatibility profile there exists a default VAO with a name (handle) of zero which is bound by default, so there’s always a VAO bound.

As far as i understand it, this is intersting to know. So, if i do something without this (as currently), there is a default one used?

Check that the shader compiled and linked correctly.

This is working correct so far. I don’t get any error-messages.
In my application, is only one function, which is used to compile and link shaders. I can edit shaders at runtime. If one of the the sources change, the changed sources are compiled with a new handle. If there are no errors, the handles are swapt and the old program is deleted. Otherwise, the error-messages are displayed and the new program is deleted. This works fine for a long time now at 2d and 3d renderings.
Therefore i’m sure that the program is accepted, as it is.

glBindAttribLocation() does nothing if the attribute name doesn’t exist

I thought so. Anyway i tested it, becaus i also think that glGetAttributeLocation must work.

layout(location=0)

This i tested also, when i tried glBindAttribLocation, but it did not help. The program compiles and links (both: with and without “#version 330”-tag). As far as i know, even this is a bit srange. With glGetErrors i get more or less messages, but the shader-compiler (wich normally reacts on every wrong character with messages), seems to be happy with my test-program…

One more thing: A a while ago i already tried a first time to aproach transform feeddback. That time i had a problen with glTransformFeedbackVaryings, which always crashed my program. By chance and while doing other things, i found out, that there is a “glewExperimental”-flag, to be set to TRUE before calling glewInit, to solve the problem and i still don’t know why.
Maybe it’s something like this??

You may need a suitable fragment shader simply to prevent the vertex shader’s outputs from being considered unused.

That seems to help a bit. My logfile reports,

Index of tffInput: 0

alfter calling glGetAttribLocation and glEnableVertexAttribArray as also glVertexAttribPointer do not lead to error-messages anymore.

Unfortunatly, now it stucks at “glBeginTransformFeedback(GL_POINTS);”. After this glGetErrors reports GL_INVALID_OPERATION. I’m not sure, if the existence of a fragment-shader, leads to this?

However: i did not really looked at the code after glEnableVertexAttribArray. I’ll check it later.

For the case that someone also want to have a look at it: Here is my c-code…

Shader-compilation (the complete function except of the error-output. So it is prepared to compile all kind of shaders - even if i currently don’t use most of it). Here is the glTransformFeedbackVaryings-call (the upper-one is used, since i have a fragment-shader).
A short explanation:

  • First, the sources are checked for changes (=> bool ch) and cut together of fragments (“uniformStr”). If there are none, the function returns.
  • After this some temporary handles are requested.
  • The regex is used to detect “void main () {…}”-expressions in the sources. If there is none, the shader is skipped.
  • glTransformFeedbackVaryings is called, it the vertex-shader contains “cppReturn”. Here i also tested BindLocation.
  • If the compilation is okay, the temporary handels are swapped with the active ones. Otherwise the active ones stay in use.

void clsControl::PrepareShader(wxString uniformStr) {          if (!recompile) return; _ONCE_PER_FRAME();

    bool ch = false;

    if (SYS != shSrcStr[_sysShd ]) {    SYS = shSrcStr[_sysShd ];   ch = true;  } 
    if (GLB != shSrcStr[_glbShd ]) {    GLB = shSrcStr[_glbShd ];   ch = true;  } 


    if (CTR != uniformStr        ) {    CTR = uniformStr;           ch = true;  }
    if (VS  != shSrcStr[_vShd   ]) {    VS  = shSrcStr[_vShd   ];   ch = true;  if (vShLnkC ) { delete vShLnkC;     vShLnkC  = NULL; }  vShLnkC  = _NEW_CHAR(SYS + CTR + GLB + VS);   }
    if (TCS != shSrcStr[_tcShd  ]) {    TCS = shSrcStr[_tcShd  ];   ch = true;  if (tcShLnkC) { delete tcShLnkC;    tcShLnkC = NULL; }  tcShLnkC = _NEW_CHAR(            TCS     );   }
    if (TES != shSrcStr[_teShd  ]) {    TES = shSrcStr[_teShd  ];   ch = true;  if (teShLnkC) { delete teShLnkC;    teShLnkC = NULL; }  teShLnkC = _NEW_CHAR(            TES     );   }
    if (GS  != shSrcStr[_gShd   ]) {    GS  = shSrcStr[_gShd   ];   ch = true;  if (gShLnkC ) { delete gShLnkC;     gShLnkC  = NULL; }  gShLnkC  = _NEW_CHAR(SYS + CTR       + GS);   }
    if (FS  != shSrcStr[_fShd   ]) {    FS  = shSrcStr[_fShd   ];   ch = true;  if (fShLnkC ) { delete fShLnkC;     fShLnkC  = NULL; }  fShLnkC  = _NEW_CHAR(SYS + CTR + GLB + FS);   }
    if (CS  != shSrcStr[_prstShd]) {    CS  = shSrcStr[_prstShd];   ch = true;  if (cShLnkC ) { delete cShLnkC;     cShLnkC  = NULL; }  cShLnkC  = _NEW_CHAR(      CTR +       CS);   }
    
    if (!ch)     return;                                                Debug(3, "Compilig shader progeam");

    CheckGL("Error left in cue");  
    
    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);   
    cShNewHandle            = glCreateShader  (GL_COMPUTE_SHADER);   
    prgNewHandle            = glCreateProgram (); 

    static wxRegEx hasCode ("[\
\\r][\	 ]*void\\s*main\\s*\\(\\s*\\)\\s*\\{.*\\}"/*"[\
\\r][\	 ]*void\\s*main\\s*\\("/*"[\
\\r][\	 ]*\\w.*"*/, wxRE_ADVANCED);
   
    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)) {
            if (hasCode.Matches(tcShLnkC) && hasCode.Matches(teShLnkC)) {
            //if (shdShader->tcShSrc != "" && shdShader->teShSrc != "") {
                success             = GL_FALSE;                                     errHandle          = tcShNewHandle;   
                glShaderSource      (tcShNewHandle, 1, &tcShLnkC, NULL);            glCompileShader     (tcShNewHandle);
                glGetShaderiv       (tcShNewHandle, GL_COMPILE_STATUS, &success);   if (success != GL_TRUE) goto ex;
                glAttachShader      (prgNewHandle, tcShNewHandle);                  //glLinkProgram       (prgNewHandle);  
        
                success             = GL_FALSE;                                     errHandle          = teShNewHandle;   
                glShaderSource      (teShNewHandle, 1, &teShLnkC, NULL);            glCompileShader     (teShNewHandle);
                glGetShaderiv       (teShNewHandle, GL_COMPILE_STATUS, &success);   if (success != GL_TRUE) goto ex;
                glAttachShader      (prgNewHandle, teShNewHandle);                  //glLinkProgram       (prgNewHandle);  
            }  
                  
            if (hasCode.Matches(gShLnkC)) {            //_wxMessageBox(shdShader->gShSrc);
            //if (shdShader->gShSrc != "") {
                success             = GL_FALSE;                                     errHandle          = gShNewHandle;   
                glShaderSource      (gShNewHandle, 1, &gShLnkC, NULL);              glCompileShader     (gShNewHandle);
                glGetShaderiv       (gShNewHandle, GL_COMPILE_STATUS, &success);    if (success != GL_TRUE) goto ex;
                glAttachShader      (prgNewHandle, gShNewHandle);                   //glLinkProgram       (prgNewHandle);  
            }        
    
            success             = GL_FALSE;                                     errHandle          = fShNewHandle;   
            glShaderSource      (fShNewHandle, 1, &fShLnkC, NULL);              glCompileShader     (fShNewHandle);
            glGetShaderiv       (fShNewHandle,  GL_COMPILE_STATUS, &success);   if (success != GL_TRUE) goto ex;
            glAttachShader      (prgNewHandle, fShNewHandle);
            
            if (shSrcStr[_vShd   ].Find("tffInput") != wxNOT_FOUND) {
            const GLchar* feedbackVaryings[] = { "cppReturn" };
            glEnable(GL_RASTERIZER_DISCARD);  
//            if (!feedbackVaryings) wxMessageBox("feedbackVaryings = 0");
            glTransformFeedbackVaryings (prgNewHandle, 0, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);      //wxMessageBox("ENDLICH!!!");
        glBindAttribLocation(prgNewHandle, 0, "tffInput");                               CheckGL("glBindAttribLocation");  
            }
        }
        else {                                                            //_wxMessageBox(tostr(prgNewHandle));
            const GLchar* feedbackVaryings[] = { "cppReturn" };
            glEnable(GL_RASTERIZER_DISCARD);  
//            if (!feedbackVaryings) wxMessageBox("feedbackVaryings = 0");
            glTransformFeedbackVaryings (prgNewHandle, 0, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);      //wxMessageBox("ENDLICH!!!");
        glBindAttribLocation(prgNewHandle, 0, "tffInput");                               CheckGL("glBindAttribLocation");  
        }
    }

    if (hasCode.Matches(cShLnkC)) {            //_wxMessageBox(shdShader->gShSrc);
    //if (shdShader->gShSrc != "") {
        success                 = GL_FALSE;                                     errHandle          = cShNewHandle;   
        glShaderSource          (cShNewHandle, 1, &cShLnkC, NULL);              glCompileShader     (cShNewHandle);
        glGetShaderiv           (cShNewHandle, GL_COMPILE_STATUS, &success);    if (success != GL_TRUE) goto ex;
        glAttachShader          (prgNewHandle, cShNewHandle);                   //glLinkProgram       (prgNewHandle);  
    }        

    success                     = GL_FALSE;                                     errHandle          = prgNewHandle;   
        
    glLinkProgram               (prgNewHandle);                                 glUseProgram        (prgNewHandle);                                 
    glGetProgramiv              (prgNewHandle, GL_LINK_STATUS,   &success);     if (success != GL_TRUE) goto ex;
    
    GLuint tmpHandle;
    tmpHandle               = vShHandle;        vShHandle  = vShNewHandle;  vShNewHandle  = tmpHandle;
    tmpHandle               = tcShHandle;       tcShHandle = tcShNewHandle; tcShNewHandle = tmpHandle;
    tmpHandle               = teShHandle;       teShHandle = teShNewHandle; teShNewHandle = tmpHandle;
    tmpHandle               = gShHandle;        gShHandle  = gShNewHandle;  gShNewHandle  = tmpHandle;
    tmpHandle               = fShHandle;        fShHandle  = fShNewHandle;  fShNewHandle  = tmpHandle;
    tmpHandle               = cShHandle;        cShHandle  = cShNewHandle;  cShNewHandle  = tmpHandle;
    tmpHandle               = prgHandle;        prgHandle  = prgNewHandle;  prgNewHandle  = tmpHandle;

    prgCanLink              = true;             recompile  = false; 

ex: OutStatus               (); 

    glUseProgram            (0);        
    glDeleteProgram         (prgNewHandle);
    glDeleteShader          (vShNewHandle); 
    glDeleteShader          (tcShNewHandle); 
    glDeleteShader          (teShNewHandle); 
    glDeleteShader          (gShNewHandle); 
    glDeleteShader          (fShNewHandle); 
    glDeleteShader          (cShNewHandle);   

    CheckGL();  
}

Binding the program - “PrepareShader” is the upper function. Here i cut out everything, which is not relevant - normally here uniforms are implemented, but in this case, tere are none:

void clsControl::ApplyShader(clsLst &list) {                                      
    CheckGL("Error left in cue");  
    
    PrepareShader   ("");    

    if (prgCanLink) {                                                   Debug(3, "Activate shader program " + tostr(prgHandle));   
       
        curPRG          = prgHandle;                                    glUseProgram ( prgHandle );   
        
     }

    CheckGL();  
}

The tff-function (this one and the previous function are called by my interpreter without anything in between):


void ParseDrawRenderTFF(clsControl *Control, clsLst &list) {     


        glDisable(GL_TEXTURE_2D);                                               CheckGL("Error left in cue");  
//    theorie:
//    ----------------
//    Shader ist bereits aktiviert. Enthält:
//      in  float tffInput; 
//      out float cppReturn
//
//    VAO erzeugen (noch nie gemacht - wofür?)
        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);                                                 CheckGL("VAO-Creation");  

//    Array von "list" erzeugen
        GLfloat data[list.size];                    
        for (int i=0; i < list.size; i++) data[i] = list[i][0];

//    Aktiven Shader-Programm-Index ermitteln
        GLint prg;
        glGetIntegerv(GL_CURRENT_PROGRAM, &prg);
        Print(tostr(prg) + " - " + tostr(curPRG));

//    VBO von array" erzeugen
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);      CheckGL("VBO-Creation");  

//    Übergabeadress für Attribut "inValue" ermitteln

//        glBindAttribLocation(prg, 0, "tffInput");                               CheckGL("glBindAttribLocation");  

        GLint tffInput = glGetAttribLocation(prg, "tffInput");                  CheckGL("glGetAttribLocation");  
//
        Print ("Index of tffInput: " + tostr(tffInput));

        glEnableVertexAttribArray(tffInput);                                    CheckGL("glEnableVertexAttribArray"); 


        glVertexAttribPointer(tffInput, 1, GL_FLOAT, GL_FALSE, 0, 0);           CheckGL("glVertexAttribPointer"); 

//    Gleich großen Zielbuffer erzeugen mit
        GLuint tbo;
        glGenBuffers(1, &tbo);
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), NULL, GL_STATIC_READ);      CheckGL("TBO-Creation");  
        
//    PROZESS:
        glEnable(GL_RASTERIZER_DISCARD);                                        CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);                 CheckGL("glBindBufferBase"); 

        glBeginTransformFeedback(GL_POINTS);                                    CheckGL("glBeginTransformFeedback"); 
            glDrawArrays(GL_POINTS, 0, list.size);                              CheckGL("glDrawArrays"); 
        glEndTransformFeedback();                                               CheckGL("glEndTransformFeedback"); 
    
        glFlush();                                                              CheckGL("glFlush"); 
    
//    Ergebnis auslesen:
        GLfloat feedback[list.size];
        glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), feedback);

        Print(tostr(data[0]) + " - " + tostr(feedback[1]) + " - " + tostr(feedback[2]) + " - " + tostr(data[3]) + " - " + tostr(data[4]));
//    Aufräumen:
        // glDisable           (GL_RASTERIZER_DISCARD);    muss nicht - ist in ResetGL();
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDeleteBuffers(1, &tbo);
        glDeleteBuffers(1, &vbo);
        glDeleteVertexArrays(1, &vao);
    
}     

This is the shader-code, i use…

Vertex-shader (currently without “layout…”):


#version 330

//////////////////////////////////////////////////////////  
// Vertex-shader                                            
//////////////////////////////////////////////////////////  


in  float tffInput; 
out float cppReturn; 

void main() {

    cppReturn = sqrt ( tffInput );
}


Fragment-shader:


in float cppReturn;
out vec4 color;

void main() {

    color = vec4(cppReturn);
}

Thanks for your help!!

Best,
Frank

Going to put everything that is needed in the tff-function now and not to call my standard-shader-compiling-function. Might take a while…

Here it is as solid function - still returning GL_INVALID_OPERATION after glBeginTransformFeedback :mad:

Note that the “clsControl *Control” is only needed to access the error-output, which still uses the standerd-function of my program. Therefore also the handels from there (“Control->prgNewHandle” etc.) are used.


void ParseDrawRenderTFF(clsControl *Control, clsLst &list) {
    
    Print("ENTER TFF-FUNCTION");                                                            CheckGL("Errors left in cue");

    char *vShLinkC___ =                      "
"
        "#version 330                         
"
        "                                     
"
        "in  float tffInput;                  
"
        "out float cppReturn;                 
"
        "                                     
"
        "void main() {                        
"
        "                                     
"
        "    cppReturn = sqrt ( tffInput );   
"
        "}                                    
";   
  
    char *fShLinkC___ =                      "
"
        "in float cppReturn;                  
"
        "out vec4 color;                      
"
        "                                     
"
        "void main() {                        
"
        "                                     
"
        "    color = vec4(cppReturn);         
"
        "}                                    
";    
         
    const GLchar* feedbackVaryings[] = { "cppReturn" };    
//    Control->vShLinkC = vShLinkC___;Control->fShLinkC = fShLinkC___;
        
    
    Control->vShNewHandle  = glCreateShader  (GL_VERTEX_SHADER); 
    Control->fShNewHandle  = glCreateShader  (GL_FRAGMENT_SHADER);   
    Control->prgNewHandle  = glCreateProgram ();                                            CheckGL("glCreateProgram");

    Control->success       = GL_FALSE;                                                     
    Control->errHandle     = Control->vShNewHandle;   
    glShaderSource          (Control->vShNewHandle, 1, &vShLinkC___, NULL);                 CheckGL("glShaderSource     (Control->vShNewHandle, 1, &vShLinkC___, NULL);");
    glCompileShader         (Control->vShNewHandle);                                        CheckGL("glCompileShader    (Control->vShNewHandle);");
    glGetShaderiv           (Control->vShNewHandle, GL_COMPILE_STATUS, &Control->success);  if     (Control->success != GL_TRUE) goto ex;
    glAttachShader          (Control->prgNewHandle, Control->vShNewHandle);                 CheckGL("glAttachShader     (prgNewHandle, vShNewHandle);");
    
    Control->success       = GL_FALSE;                                                     
    Control->errHandle     = Control->fShNewHandle;   
    glShaderSource          (Control->fShNewHandle, 1, &fShLinkC___, NULL);                 CheckGL("glShaderSource     (Control->fShNewHandle, 1, &fShLinkC___, NULL);");
    glCompileShader         (Control->fShNewHandle);                                        CheckGL("glCompileShader    (Control->fShNewHandle);");
    glGetShaderiv           (Control->fShNewHandle, GL_COMPILE_STATUS, &Control->success);  if     (Control->success != GL_TRUE) goto ex;
    glAttachShader          (Control->prgNewHandle, Control->fShNewHandle);                 CheckGL("glAttachShader     (prgNewHandle, fShNewHandle);");


    glTransformFeedbackVaryings (Control->prgNewHandle, 0, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);  CheckGL("glTransformFeedbackVaryings");  

//    glBindAttribLocation        (prgNewHandle, 0, "tffInput");                               CheckGL("glBindAttribLocation");  

    Control->success       = GL_FALSE;                                                     
    Control->errHandle     = Control->prgNewHandle;   
    glLinkProgram           (Control->prgNewHandle);                                        CheckGL("glLinkProgram"); 
    glUseProgram            (Control->prgNewHandle);                                        CheckGL("glUseProgram"); 
    glGetProgramiv          (Control->prgNewHandle, GL_LINK_STATUS,   &Control->success);   if     (Control->success != GL_TRUE) goto ex;
    

     

    if                      (Control->success != GL_FALSE)   {

        Control->OutStatus               (); 

///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////


        glDisable(GL_TEXTURE_2D);                                               CheckGL("Error left in cue");  
//    theorie:
//    ----------------
//    Shader ist bereits aktiviert. Enthält:
//      in  float tffInput; 
//      out float cppReturn
//
//    VAO erzeugen (noch nie gemacht - wofür?)
        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);                                                 CheckGL("VAO-Creation");  

//    Array von "list" erzeugen
        GLfloat data[list.size];                    
        for (int i=0; i < list.size; i++) data[i] = list[i][0];

//    Aktiven Shader-Programm-Index ermitteln
        GLint prg;
        glGetIntegerv(GL_CURRENT_PROGRAM, &prg);
        Print(tostr(prg) + " - " + tostr(curPRG));

//    VBO von array" erzeugen
        GLuint vbo;
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);      CheckGL("VBO-Creation");  

//    Übergabeadress für Attribut "inValue" ermitteln

//        glBindAttribLocation(prg, 0, "tffInput");                               CheckGL("glBindAttribLocation");  

        GLint tffInput = glGetAttribLocation(prg, "tffInput");                  CheckGL("glGetAttribLocation");  
//
        Print ("Index of tffInput: " + tostr(tffInput));

        glEnableVertexAttribArray(tffInput);                                    CheckGL("glEnableVertexAttribArray"); 


        glVertexAttribPointer(tffInput, 1, GL_FLOAT, GL_FALSE, 0, 0);           CheckGL("glVertexAttribPointer"); 

//    Gleich großen Zielbuffer erzeugen mit
        GLuint tbo;
        glGenBuffers(1, &tbo);
        glBindBuffer(GL_ARRAY_BUFFER, tbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(data), NULL, GL_STATIC_READ);      CheckGL("TBO-Creation");  
        
//    PROZESS:
        glEnable(GL_RASTERIZER_DISCARD);                                        CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);                 CheckGL("glBindBufferBase"); 

        glBeginTransformFeedback(GL_POINTS);                                    CheckGL("glBeginTransformFeedback"); 
            glDrawArrays(GL_POINTS, 0, list.size);                              CheckGL("glDrawArrays"); 
        glEndTransformFeedback();                                               CheckGL("glEndTransformFeedback"); 
    
        glFlush();                                                              CheckGL("glFlush"); 
    
//    Ergebnis auslesen:
        GLfloat feedback[list.size];
        glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), feedback);

        Print(tostr(data[0]) + " - " + tostr(feedback[1]) + " - " + tostr(feedback[2]) + " - " + tostr(data[3]) + " - " + tostr(data[4]));
//    Aufräumen:
        // glDisable           (GL_RASTERIZER_DISCARD);    muss nicht - ist in ResetGL();
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDeleteBuffers(1, &tbo);
        glDeleteBuffers(1, &vbo);
        glDeleteVertexArrays(1, &vao);
    }

ex: if(Control->success != GL_TRUE)Control->OutStatus               (); 

    glUseProgram            (0);        
    glDeleteProgram         (Control->prgNewHandle);
    glDeleteShader          (Control->vShNewHandle); 
    glDeleteShader          (Control->fShNewHandle); 
}     

At his point, there is nothing really left anymore, which i could simplify. Also the shader-program is not kept, but just created for a single call. Only the function ResetGL is still used as i posted it before. I also red the documentation here https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBeginTransformFeedback.xhtml. But i don’t find any reason concerning the GL_INVALID_OPERATION -error, that seems possible to me…

According to the glBeginTransformFeedback() reference page:

GL_INVALID_OPERATION is generated if glBeginTransformFeedback is executed while transform feedback is active.

GL_INVALID_OPERATION is generated by glBeginTransformFeedback if any binding point used in transform feedback mode does not have a buffer object bound.

GL_INVALID_OPERATION is generated by glBeginTransformFeedback if no binding points would be used, either because no program object is active or because the active program object has specified no varying variables to record.

The call to glTransformFeedbackVaryings() in the code you’ve shown has a count of zero, which would correspond to the last of the three reasons above:

Wow!!! This it was!

You won’t believe how much i thank you for this!!!

This tff-thing is most important for me. I have this interpreter, which can control my UI, calculate GLfloats, handle strings and can call gl-functions. But it’s not usable for bigger amounts of data-calculations. I always thougth to give this to GPU, but comute-shaders are far away for my skills. For the moment this is a good solution. Now i can combine my interpreter-functions with things done on GPU.

So, i’ll start to figure out the possibilities now…

Best,
Frank

Addendum:

That’s fantastic! I have intgrated a (first) type of tff-functions now and porgrammed a shader, that calculates a complete VAO for drawing geometrical objects, like a torus, a sphere, moving waverings etc. with (uniform) parameters, set by controls of my UI. All of this was done by CPU in before. The resolution of my objects is ~10x finer then before without losing frames.

Best,
Frank