PacktPublishing / OpenGL-4-Shading-Language-Cookbook-Third-Edition

OpenGL 4 Shading Language Cookbook - Third Edition, published by Packt
MIT License
312 stars 72 forks source link

Segmentation fault at close #6

Closed ghost closed 4 years ago

ghost commented 5 years ago

Hi, the examples all work on Ubuntu 18.04 but they don't exit cleanly starting from Chapter 2. Only Chapter 1's example exits properly without any issues. When the X is clicked with the mouse or when I hit ESC, the app always segmentation faults at close. Here's the output for Chapter 2's example:

$ ./chapter02 basic-attrib

GL Vendor : NVIDIA Corporation GL Renderer : GeForce GTX 1070 Ti/PCIe/SSE2 GL Version : 4.6.0 NVIDIA 418.56 GL Version : 4.6 GLSL Version : 4.60 NVIDIA MSAA samples : 0 MSAA buffers : 0

Active attributes: 1 VertexColor (vec3) 0 VertexPosition (vec3) OpenGL:OtherNOTIFY: Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations. OpenGL:OtherNOTIFY: Buffer detailed info: Buffer object 2 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as the source for buffer object operations. OpenGL:PerformanceMED: Program/shader state performance warning: Vertex shader in program 1 is being recompiled based on GL state. App:MarkerNOTIFY: End debug Segmentation fault

thatrobotguy commented 5 years ago

Well, it should be noted that when you press Ctrl+C on the terminal it does not self-destruct: it just closes the program like we would hope. It looks like the memory is not being freed properly. There is an infinite loop going on in the scenerunner object:

void mainLoop(GLFWwindow * window, Scene & scene) {
        while( ! glfwWindowShouldClose(window) && !glfwGetKey(window, GLFW_KEY_ESCAPE) ) {
            GLUtils::checkForOpenGLError(__FILE__,__LINE__);

            scene.update(float(glfwGetTime()));
            scene.render();
            glfwSwapBuffers(window);

            glfwPollEvents();
            int state = glfwGetKey(window, GLFW_KEY_SPACE);
            if (state == GLFW_PRESS)
                scene.animate(!scene.animating());
        }

That while loop is getting terminated before any variables can be deleted. Usually you create a function that gets registered as a button function. The button type then gets checked in a state machine (at least, that is what my CG class using glut and glew on windows did). It looks like the code is only checking for the space-bar as a 1-line if(), whereas the escape key and close window buttons simply exit the while loop without freeing the scene object from memory (it is defined in the outermost file main.cpp). Maybe there should be some call to delete somewhere in the call to run() to free memory manually. I am no expert, but that is my guess as what needs to be done. Seg faults usually happen when code tries to access something that is not there or it doesn't have permissions to see. What do you guys think?

daw42 commented 5 years ago

Thanks for your input @thatrobotguy, and thanks for the report @jesse-meza .

The Scene object will be destroyed when the unique_ptr in main goes out of scope, at the end of main. However, the destruction of the Scene object will potentially take place after the GL context is destroyed. I've seen segfaults like this before, and they are usually due to calling OpenGL functions after the GL context is destroyed. There are a few destructors that call OpenGL functions (e.g. glDeleteShader in ~GLSLShaderProgram). My guess is that one of the destructors is executing after the OpenGL context is destroyed. I don't have access to an Ubuntu machine to test with, so I'm hoping you can help me. The best thing to do would be to run it in a debugger and see if you can isolate the call that is causing the segfault.

ghost commented 5 years ago

@daw42 Yes, I agree. The OpenGL context should be the last object to be destroyed to allow any destructor having OpenGL calls to execute. I'll see if I can find a function which is executing after the destruction of the GL context in the debugger. I'll update my findings.

ghost commented 5 years ago

I put breakpoints in sceneRunner.h at glfwTerminate() and in the shader destructor call to glDeleteShader() in glslProgram.cpp. Sure enough, glfwTerminate() gets called immediately after quitting so glDeleteShader()never gets called with a live GL context, which would certainly cause a segfault. I couldn't even find the destruction calls for the VBOs and VAOs to try those.

Looking at it now, the fact that Chapter 1 didn't previously segfault was just pure dumb luck... So it looks like the problem is the Scene class needs to be re-implemented to clean-up after itself before the GL context gets destroyed.

daw42 commented 4 years ago

I just pushed some changes that should resolve this. The Scene object is now getting destroyed before glfwTerminate is called.

Thanks again to @jesse-meza and @thatrobotguy for your help!