Search code examples
c++openglsegmentation-faultglfwparticle-system

Segmentation fault error while attempting to create a particle system with OpenGL


I'm trying to create a simple particle system but I'm facing the segmentation fault error. My problem seems to be related to the number of vertex attributes I'm passing. One vertex has 3 floats, corresponding to x, y and z coordinates, so if I want to create 1 million particles, I'll have an array of 3 million floats containing the positions coordinates for each particle. The problem is that if I go above a certain number of particles, like around 400000, I get a segmentation fault.

Here's part of the code:

#define NP  1000000

int main(void)
{
    // Init GLFW
    MyGLFW myglfw(4, 5, W, H, "Particles");
    // Create shader program
    Shader shader("shaders/shader.vs", "shaders/shader.fs");

    // Define particle's vertex attrib
    float particleData[NP * 3];
    for(uint i = 0; i < NP * 3; i++)
    {
        // Creates a new particle with random position in the given range
        Particle p(-1.0f, 1.0f);
        particleData[i++] = p.pos[0];
        particleData[i++] = p.pos[1];
        particleData[i]   = p.pos[2];
    }

    // Create Vertex Buffer Object (VBO) to store vertices into GPU memory
    uint VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(particleData), particleData, GL_STATIC_DRAW);

    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // Render loop
    while(!glfwWindowShouldClose(myglfw.getWindow()))
    {
        // Check input
        myglfw.processInput();

        // Rendering commands
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Activate shader
        shader.use();

        // Draw triangle through VAO
        glBindVertexArray(VAO);
        glDrawArrays(GL_POINTS, 0, NP * 3);
        glBindVertexArray(0);

        // GLFW: swap buffers and poll IO events (e.g. keys pressed, released, mouse moved, etc.)
        glfwSwapBuffers(myglfw.getWindow());
        glfwPollEvents();
    }

    // GLFW: terminate, clearing all previously allocated GLFW resources
    myglfw.terminate();
    return 0;
}

I manage to write around 400000-500000 particles and above that I get a segmentation fault. GDB says that the segmentation signal comes right at the first line of the main, which I don't understand. I also tried to set the number of particles by setting a long int nr = 1000000 directly in the main function, but I get the same error, and in this way GDB gives me an error at float particleData[nr];.

I'm writing and running my code on a Linux system using VS Code, my GPU is a GTX 1070 FE.


Solution

  • As per the comment, the use of...

    float particleData[NP * 3];
    

    is, potentially, causing a stack overflow. Rather than allocate such a large array on the stack you should consider using std::vector instead. The following is your code with (hopefully) the minimal necessary modifications (look for @G.M. )...

    #define NP  1000000
    
    int main(void)
    {
        // Init GLFW
        MyGLFW myglfw(4, 5, W, H, "Particles");
        // Create shader program
        Shader shader("shaders/shader.vs", "shaders/shader.fs");
    
        // Define particle's vertex attrib
        std::vector<float> particleData(NP * 3); /* @G.M. */
        for(uint i = 0; i < NP * 3; i++)
        {
            // Creates a new particle with random position in the given range
            Particle p(-1.0f, 1.0f);
            particleData[i++] = p.pos[0];
            particleData[i++] = p.pos[1];
            particleData[i]   = p.pos[2];
        }
    
        // Create Vertex Buffer Object (VBO) to store vertices into GPU memory
        uint VBO, VAO;
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        
        glBindVertexArray(VAO);
    
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(particleData[0]) * particleData.size(), particleData.data(), GL_STATIC_DRAW); /* @G.M. */
    
        // Position
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);
    
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
        // Render loop
        while(!glfwWindowShouldClose(myglfw.getWindow()))
        {
            // Check input
            myglfw.processInput();
    
            // Rendering commands
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            // Activate shader
            shader.use();
    
            // Draw triangle through VAO
            glBindVertexArray(VAO);
            glDrawArrays(GL_POINTS, 0, NP * 3);
            glBindVertexArray(0);
    
            // GLFW: swap buffers and poll IO events (e.g. keys pressed, released, mouse moved, etc.)
            glfwSwapBuffers(myglfw.getWindow());
            glfwPollEvents();
        }
    
        // GLFW: terminate, clearing all previously allocated GLFW resources
        myglfw.terminate();
        return 0;