wxGLContext seems to get lost Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
art-ganseforth
Earned some good credits
Earned some good credits
Posts: 147
Joined: Mon Sep 01, 2014 10:14 am

wxGLContext seems to get lost

Post by art-ganseforth »

Hello,

i've the following problem (a quet special one): In my program (win10, wx 2.9.3) exist several wxGLCanvas-controls using the same wxGLContext. The context is created with the first wxGLCanvas. If this wxGLCanvas-control is hidden, my program crashes since some weeks.

This effect is new but i can't fix the point where it appered. I have an idea, that it has to do with that i use a static (so it's kept in memory and not just generated for one frame) vertex-arrays now - which is some OpenGL-speific thing. My idea is now, that it coud be the case, the somehow some advanced parts of the OpenGL-Context gets lost, if the wxGLContext-control, that created it, is hidden.

For some reasons the program crashes if this control is hidden while drawing my vertex-array (which in this case has nothing to do with really 'drawing', like painting on a graphic-context - it's here a process using the GPU for some internal array-manipulations).

A long time ago i found out, that the initial wxGLCanvas has to be visible, during creation, to retrieve a working OpenGL-context. That means: If i - as i normally do - keep my main-window hidden while starting the program and showing it, if everyting is prepared, i do not retrieve a working context. I have to show the window while creating the wxGLCanvas-control for a shor moment. Afterwards it can be hidden again - which now leads to crashes in some cases, since some weeks.

Now it is like this: For a long time i used only textuers as static OpenGL-Objects. Since some days there are also static vertex-arrays. As far as i remember, the crashes appered around this the first time. My idea is now, that - somehow - my vertex-arrays get lost while textures are kept, if i hide the initial control. While also the creation-process only works if it's visible, it seems as if some advanced OpenGL-things do not work, if wxGLCanvas is not visible, but basic things (textures) still do.

Is there anone who knows more about this?


Best,
Frank
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: wxGLContext seems to get lost

Post by Manolo »

AFAIK, on Windows it doesn't matter if the window is shown or hidden to create an OpenGL context. There's an old issue with wxGTK about not allowing to swap buffers if the window is not shown. Without seeing your code we cannot tell why it behaves so bad for you.

You say you use several wxGLCanvas with the same gl-context. In this case, before any gl-command you must set the context as current to the canvas you want to draw to. Any time you want another canvas, set the context as current to it. The same applies if you use different threads.

BTW, if you are moving to shaders and modern OpenGL (version >= 3.2) then move also to wx >= 3.0, ortherwise no modern OGL context can be created by wx.
art-ganseforth
Earned some good credits
Earned some good credits
Posts: 147
Joined: Mon Sep 01, 2014 10:14 am

Re: wxGLContext seems to get lost

Post by art-ganseforth »

Code: Select all

AFAIK, on Windows it doesn't matter if the window is shown or hidden to create an OpenGL context. There's an old issue with wxGTK about not allowing to swap buffers if the window is not shown. Without seeing your code we cannot tell why it behaves so bad for you.
My program is quiet complex (5000+ lines of C++ and the same amount of code that is interpreted by my own interpreter) and i work on it for a long time now. The gl-context is created like this (nothing relevant changed here for a long time):

Code: Select all

void clsApp::InitGL(wxGLCanvas *Canvas) {         
    Print           ("Initializing OpenGL...");
//    wxGLContextAttrs cxtAttrs;
//cxtAttrs.CompatibilityProfile()/*.CoreProfile()*/.OGLVersion(3, 3).Robust().ResetIsolation().EndList();

    //Kontext         = new wxGLContext(Canvas, NULL, &cxtAttrs);// 
    Kontext         = Canvas->GetContext();
    if (!Kontext) {             wxMessageBox("FATAL ERROR:\nCan't inintialize GL-Context.\n\nExit...");     exit(0);    }  

    mainWin         ->Show();
    Canvas          ->SetCurrent();                                                                     
    mainWin         ->Hide();       
    glewExperimental= TRUE;        // needed for glew version under 1.3  -  before glewInit()                 
    GLenum err      = glewInit();                                                                
    if (GLEW_OK    != err) {    wxMessageBox("FATAL ERROR:\n"+wxString(glewGetErrorString(err)));           exit(0);    } 
    
    if (NULL_Buffer== NULL)     NULL_Buffer     = new clsBuffer   (   2,    2, "OFF"   );                                                 

    glShadeModel    (GL_SMOOTH);                 // Enables Smooth Color Shading

    glHint          (GL_POINT_SMOOTH_HINT, GL_NICEST);
    glHint          (GL_LINE_SMOOTH_HINT, GL_NICEST);
    glHint          (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
    glHint          (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   
    glHint          (GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST);
    glHint          (GL_GENERATE_MIPMAP_HINT, GL_NICEST);   
    glHint          (GL_FOG_HINT, GL_NICEST);   
//    glEnable        (GL_BLEND);
    glEnable        (GL_TEXTURE_2D); 
    glEnable        (GL_POINT_SMOOTH);           
    glEnable        (GL_LINE_SMOOTH);
    glEnable        (GL_POLYGON_SMOOTH);
    glDisable       (GL_CULL_FACE);   
//    glCullFace(GL_BACK);  

    glClearDepth    (1.0);                       // Depth Buffer Setup
    glClearColor    (0.0f, 0.0f, 0.0f, 1.0); 


    GLint           glINT;
    GLint           NumExtensions;                  glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtensions);

    InfoString      . reserve(100000);
    GLversion       . reserve(10000);
    
    GLversion       = wxString() 
            + "\n    GPU-Vendor:    \t" + glGetString(GL_VENDOR)                                                             
            + "\n    GPU-Renderer:  \t" + glGetString(GL_RENDERER)                  
            + "\n    GL-Version:    \t" + glGetString(GL_VERSION)                                                             
            + "\n    SL-Version:    \t" + glGetString(GL_SHADING_LANGUAGE_VERSION)                                                             
            + "\n    GL-Extensions: \t" + tostr((int)NumExtensions);

[...]   
You say you use several wxGLCanvas with the same gl-context. In this case, before any gl-command you must set the context as current to the canvas you want to draw to. Any time you want another canvas, set the context as current to it. The same applies if you use different threads.
Sure. The following function is called to render to wxGLCanvas (see first line):

Code: Select all

clsBuffer *clsBuffer::buf_RenderPreview (wxGLCanvas *dst) { int w, h;   
//ResetGL();    
    dst->SetCurrent             ();
    dst->GetClientSize          (&w, &h);
    glViewport                  (0, 0, (GLint)w, (GLint)h);

    glDisable                   (GL_BLEND);                 glDisable       (GL_LIGHTING);              
    glDisable                   (GL_COLOR_MATERIAL);        glDisable       (GL_CULL_FACE);
    
    glTexEnvf                   (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,  GL_REPLACE);

    int MipMapMode            = buf_W < w / 2 || buf_H < h / 2 ? GL_NEAREST : GL_LINEAR;
    
    buf_Render2D                (MipMapMode);

    dst->SwapBuffers            ();

    return this;    
}
But the problem des not appear with textures and rendering. That all works fine for a long time now. What i mainly changed, is that i use wertex-array now, which are not temporary (for tranform-feedback). Especially: I've a detailed log-file. So i was able to find the exact line, where the program crashes. I is when i call glDrawArray.
There is an object with this code (complete):

Code: Select all

////////////////// clsVAO ///////////////////////////////////////////////////////////////////

clsVAO::~clsVAO         () {    glDeleteBuffers(1, &VBO);     glBindBuffer    (GL_ARRAY_BUFFER, 0);  }

clsVAO:: clsVAO         (int numV, int format) {

    CalcSize            (numV, format);    
    
    glGenBuffers        (1, &VBO);
    glBindBuffer        (GL_ARRAY_BUFFER, VBO);
    glEnableClientState (GL_VERTEX_ARRAY);
    glBufferData        (GL_ARRAY_BUFFER, NumV * Stride, NULL, GL_STATIC_DRAW);
}

void clsVAO::CalcSize (int numV, int format) {
    NumV = numV;  Format = format; 
    Stride  = Format == GL_V2F              ? 2 * sizeof(GLfloat)
            : Format == GL_V3F              ? 3 * sizeof(GLfloat)
//          : Format == GL_C4UB_V2F         ? 4 * sizeof(GLubyte) + 2 * sizeof(GLfloat)
//          : Format == GL_C4UB_V3F         ? 4 * sizeof(GLubyte) + 3 * sizeof(GLfloat)
            : Format == GL_C3F_V3F          ? 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_N3F_V3F          ? 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_C4F_N3F_V3F      ? 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_T2F_V3F          ? 2 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            
            : Format == GL_T4F_V4F          ? 4 * sizeof(GLfloat) + 4 * sizeof(GLfloat)
            
//          : Format == GL_T2F_C4UB_V3F     ? 2 * sizeof(GLfloat) + 4 * sizeof(GLubyte) + 3 * sizeof(GLfloat)
            : Format == GL_T2F_C3F_V3F      ? 2 * sizeof(GLfloat) + 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_T2F_N3F_V3F      ? 2 * sizeof(GLfloat) + 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_T2F_C4F_N3F_V3F  ? 2 * sizeof(GLfloat) + 4 * sizeof(GLfloat) + 3 * sizeof(GLfloat) + 3 * sizeof(GLfloat)
            : Format == GL_T4F_C4F_N3F_V4F  ? 4 * sizeof(GLfloat) + 4 * sizeof(GLfloat) + 3 * sizeof(GLfloat) + 4 * sizeof(GLfloat)
            
            :                                 4 * sizeof(GLfloat) + 4 * sizeof(GLfloat) // _clsPlane
            ;

  
    int count = NumV * Stride;      
}
        
number* clsVAO::Open    (int numV, int format) {

    glBindBuffer        (GL_ARRAY_BUFFER, VBO);
    glEnableClientState (GL_VERTEX_ARRAY);

    if ((numV > 0 && numV != NumV) || (format > 0 && format != Format))  {
        
        CalcSize        (numV, Format);
        glBufferData    (GL_ARRAY_BUFFER, NumV * Stride, NULL, GL_DYNAMIC_DRAW);
    }
    
    return              (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
//    return Data;
}


void clsVAO::Close      () {
                          
    glUnmapBuffer       (GL_ARRAY_BUFFER);        
                          
    glInterleavedArrays (Format, Stride, NULL);                     
//    glBindBuffer        (GL_ARRAY_BUFFER, 0);
}

void clsVAO::DrawAll    (GLint DrawType) {
    glBindBuffer        (GL_ARRAY_BUFFER, VBO);              //Print(tostr(VBO));

    glInterleavedArrays (Format, Stride, NULL);              //Print("2");
    glDrawArrays        (DrawType, 0 /*start*/, NumV);       //Print("3");

    glBindBuffer        (GL_ARRAY_BUFFER, 0);                //Print("4");
}   
 
GLint clsVAO::DrawArrays(GLint DrawType, GLint first, GLint count) {
    glBindBuffer        (GL_ARRAY_BUFFER, VBO);

    glDrawArrays        (DrawType, first, count);

    glBindBuffer        (GL_ARRAY_BUFFER, 0);

    return              first + count;
}    
The out-commented-print-calls in "void clsVAO::DrawAll (GLint DrawType)" were used to figuer out the exact line of the crash. Print("2"); was the last, but it works as long as i don't toggle the visibility of the initial wxGLCanvas.
I used vertex-arrays and "glDrawArrays" also in before, but thy (the arrays) were created, filled with data, drawn and deleted within one function. Only textures were kept in memory for longer time. But there i had no problems. Now i use vertex-arrays filled by shaders (using tff). For this, i need two steps, because two different states of of the OpenGL-state-machiene are needed, to create the array, and to draw it. Therefore i have to keep it in memory. For this i have the "clsVAO" class.
I checked all of it's parameters. They don't get lost. So for me it seems that the vertex-array itself is not adressable anymore when i try to draw it.
Combined with the fact, that i had a simelar problem years ago while context-creating when the same wxGLCanvas (yes, it was/is the same) was not visible, i now considered something basically with the context as reason for the crashes, that doesn't have effect on textures and that only appears if the control (it's that from where i retrieve the context) is hidden.
BTW, if you are moving to shaders and modern OpenGL (version >= 3.2) then move also to wx >= 3.0, ortherwise no modern OGL context can be created by wx.
Here I'm once more estonished!
As already said, i work on my project for a while now. Im Autodidact and some things are - hmmmm - let's say, i shold learn more about, but i've to learn a lot and i start where i stuck...
So, currently i have a compiler-setup, that works and every time, when i try to change someting, i'm really afraid, that i loose everthing. Updating to wxWidegts 3 is one of this things...

But it's like this: If m application would take everything for real, which officially doen't work (like this: "ortherwise no modern OGL context can be created by wx"), it won't do anything. Some days ago someone told me in OpenGL-forum, that i can't render to a texture that i use as source at the same moment, which i in fact do for 2 or 3 years now. Also i use shaders now for a long time with wxWidgets 2.9.X. So it seems, that my system does't really cares about some limitations :)

Anyway: With a little help i would dare it again these days - if someone assists me ;)

Best,
Frank
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: wxGLContext seems to get lost

Post by Manolo »

If the glDrawArrays call crashes your app I'm pretty sure it's not a wxWidgets problem, but something in the way you issue calls to GL. For exampe, do you unmap the buffer before glDrawArrays? Remember that an OGL error may be issued by a previous command, don't trust every gl-call is executed right after you use it, the driver stacks the commands and execute them later.

I see wx3.1 features, like wxGLContextAttrs. I suppose you show them just for clarity of your code, not because you really try to use them. wx2.9 was only capable of create an OGL 2.1 context. It's true that some (a few and old) drivers will give a OGL>3 compatibility context.

Your clsVAO name is confusing. It has nothing to do with Vertex Array Object (VAO), which you may use. Absolutely required in OGL > 3.1
Also, a buffer can't be filled in a OGL-shader (except some special buffers, SSBO). And the idea behind a buffer or a texture is "pass it to the GPU only once, draw many times". No need to "keep in memory" (except for small changes). Again, it seems to me some naming-confusion.

If you are already using buffers and shaders then moving to modern OpenGL will be easy. Just adds VAO's and use some matrix-mathematics, like glm.

Compiling wx is straightforward if you follow the instructions at docs/msw/install.txt
art-ganseforth
Earned some good credits
Earned some good credits
Posts: 147
Joined: Mon Sep 01, 2014 10:14 am

Re: wxGLContext seems to get lost

Post by art-ganseforth »

Manolo wrote:If the glDrawArrays call crashes your app I'm pretty sure it's not a wxWidgets problem, but something in the way you issue calls to GL. For exampe, ...
I would normally also think so, but obviously the glDrawArrays-call (which has nothing to do, with this wxGLCanvas), fails in the moment, when i hide this canvas. I was thinking about various possible reasons, but nothing is plausible.
Okay, my program is quiet complex and if i log a single frame with highest log-level, i get ~10 pages of text. But i see no difference.
It also would be redicolous. What i mean is: there is a toggle-button, which toggels the view. So, if vou press it (after a lot of overhead) there is called once ...->Hide() and once ...->Show() vica versa. So there is no call that has to do with OpenGL - really nothing.
I see wx3.1 features, like wxGLContextAttrs.
Yes - or hmmm - not really. It's just some days ago, that i found out that this does not work with my wx-version (i think it was, when it first time was searching for the reason of this crashes). It was in all the time that i use wx the second or third thie, that i thought, a newer version could be better. On the other hand: Until now, i did not need this wxGLContextAttrs thing and it would make everything more complicated. In this case i have trusted the wx-settings so far...
So, what you see is the rest of the test ;)
Your clsVAO name is confusing. It has nothing to do with Vertex Array Object (VAO), which you may use. Absolutely required in OGL > 3.1
Right! I am a bit confused in this point. Have a look at this discussion, that i yesterday https://www.opengl.org/discussion_board ... ost1292683. I know a bit mor in between...

Generally it's like this, that - after understanding the principals - i worked with basic OpenGL-things until some weeks ago, to create my UI (which is specially created for OpenGL). Now my UI is mostly working and i started to use more advanced OpenGL-things, which i still have to learn in several points.
So, yes, i'm still a bit confused ;)
SSBO... naming confusion
Right again. SSBO i did not use until now, and with VBO/VAO i'm confused. On the other hand: I - this is one of my "basics" - don't need much. My whole program is based on "simple" or better basic things. (There are points wherer i thought about using assambler, but i prefere to use the GPU and shaders). Conserning wxWidgets: it's - hmmm - comfortable. I use it in several points as workaround. I.e. string-manipulations are quiet simple to code.
Also a lot of window-handeling things are easier - especially at the beginning of a project. But the farer i get with my program, the more i'd like to take in my own hand (like i.e. the sizers, which i removed in between).
If you are already using buffers and shaders then moving to modern OpenGL will be easy. Just adds VAO's and use some matrix-mathematics, like glm.
Here i seem to miss some information. Okay: with matrix-mathematics i'm absolutly not as common as i should be. If i really need it (and i see this point not far away) i'll refresh my school-knowlage ;)

In fact it's like this: My program is a most interactive and modular thing, where shader-language and the the code that is interpreted by my own interpreter are nearly inegrated. I try to reduce everything as much as i can (so i.e. using as less and as simple OpenGL-Objects as possible). In the case of my application, i can use everything, that my inerpreter provides. Principiall this is a lot, because i integrated/abstrahated a huge part of OpenGL in this form (you cant read it because auf the macro - just that you knot where i talk about):

Code: Select all

#define GL_FUNC(_n)        if(!strcmp(nam, "gl"#_n))     GL_RETURN gl##_n
#define GL_RETURN      /**/
[...]
        else GL_FUNC( Begin                     ) ( list[0][0]  );
        else GL_FUNC( TexCoord2f                ) ( list[0][0], list[1][0]  );     
        else GL_FUNC( Vertex3f                  ) ( list[0][0], list[1][0], list[2][0]  );
        else GL_FUNC( Color4f                   ) ( list[0][0], list[1][0], list[2][0], list[3][0]  ); 
        else GL_FUNC( Normal3f                  ) ( list[0][0], list[1][0], list[2][0]  ); 
Compiling wx is straightforward if you follow the instructions at docs/msw/install.txt
Puh...
My english....
I'm much (lightyears) better in expressing / writing, then in reading / understanding.

Also: i spend lots of time in programming, but it's just a hobby. For my project it would be good to have a professional partner. But i don't have ind i'm also a little bit proud about what i realized in between.

Until now i always had other things to do, which were more important...


[ Posted as written without correction ]

Best,
Frank



PS. Currently i debug things that mostly had worked once. These days i replaced a huge part (20%) of my program by new functions. Therfore ther are some new bugs to be repaired...

PPS. Just was on the way to read docs/msw/install.txt (again), when i realized: The problem is more general. If i do this, i still don't know how to do al the other complier- and linker-settings. It would be i.e. good (as a first step) if i could use another IDE then the old devCPP, but - hmmm - until now i failed compile my program with Code:bloxx. Also: Some weeks ago i tried to install wx3, because my current installation crasched several time (after windows update). No success. Im happy that i got to run the current setup again.
It's really funny: I work with c since ~25 years (sic!) and i never configurered or compiled a library ;)
How i do this? Before internet i hed help of friends. Today i use prepared downloadable setups. The one i use currentloy has been not updated for at least 5 probably more then 10 years.
So - hmmm - compiling librarys is something to learn, but i'd need a second setup and lots of time for this...
art-ganseforth
Earned some good credits
Earned some good credits
Posts: 147
Joined: Mon Sep 01, 2014 10:14 am

Re: wxGLContext seems to get lost

Post by art-ganseforth »

Today I'm quit lucky. Also this is solved.

Here it is:
In order, to be able to use results of renderings within a rendering-process (don't know how to express it better) i've the possibility to link modules to diffrernt "timer-thread". That means: there is on timer-function only, but inside are different loops ("threads"), calling all the processes to be done. Modules may be linked to the first, the second or the third etc. loop. That means, that per frame the modules linked to the firts loop are evaluated before the evaluation of the modules start, that are linked to the second, etc.

The point is, that all outputs have to be linked to the last "thread". For some reasons, one of the outputs was linked to the wrong thread. So, within the internal rendering-thread, OpenGL settings were done, that should not have been done there. What it was exactly, i don't really know, but probably it was exact what you propsed: that the buffer was unmapped.

So....

Within two or three weeks, i hope to have a stabel beta-version. Think i'll post a link here and in the OpenGL-forum where i found a lot of help...
art-ganseforth
Earned some good credits
Earned some good credits
Posts: 147
Joined: Mon Sep 01, 2014 10:14 am

Re: wxGLContext seems to get lost

Post by art-ganseforth »

Addendum:
I was right with my idea, that a valid OpenGL-context needs a visible wxGLCanvas. See here: https://wiki.wxwidgets.org/WxGLCanvas#S ... as_Context
Post Reply