Search code examples
c++static

Performance concerns of using static variables inside display function in OpenGL?


I'm learning OpenGL 4 and am reading an ebook Computer Graphics Programming in OpenGL with C++ Second Edition. They explain that it is very important in our display function, where drawing operations are handled, that we avoid instantiating objects or declaring variables to maximize performance and minimize overhead. Which is why up until that point they'd been globally declaring variables used in the display function as a means to avoid any memory allocation locally.

I've been instead opting to use static variables in the display function like so:

void display(GLFWwindow* window, double currentTime) {

    static float cameraX = 0.0f, cameraY = 0.0f, cameraZ = 20.0f; // <-- statically assigned 

    glm::mat4 mMat, vMat, pMat, mvMat;

    int width, height;

    std::stack<glm::mat4> mvStack;

    glfwGetFramebufferSize(window, &width, &height);

    float aspect = static_cast<float>(width) / static_cast<float>(height);

    glClear(GL_DEPTH_BUFFER_BIT);

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(renderingProgram);

    GLuint mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
    GLuint pLoc = glGetUniformLocation(renderingProgram, "p_matrix");

    pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);

    vMat = glm::translate( glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ) );
    mvStack.push(vMat);

    glUniformMatrix4fv(pLoc, 1, GL_FALSE, glm::value_ptr(pMat));

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(1.0f, 0.0f, 0.0f));

    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top()));

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDrawArrays(GL_TRIANGLES, 0, 18);

    mvStack.pop();

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::translate(glm::mat4(1.0f),
        glm::vec3(
            sin(static_cast<float>(currentTime)) * 4.0f,
            0.0f,
            cos(static_cast<float>(currentTime)) * 4.0f
        ));

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(0.0f, 1.0f, 0.0f));

    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top()));
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_TRIANGLES, 0, 36);
    mvStack.pop();

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::translate(glm::mat4(1.0f),
        glm::vec3(
            0.0f,
            sin(static_cast<float>(currentTime) * 0.5) * 2.0f,
            cos(static_cast<float>(currentTime) * 0.5) * 2.0f
        ));

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), static_cast<float>(currentTime), glm::vec3(-1.0f, 0.0f, 0.0f));

    mvStack.push(mvStack.top());
    mvStack.top() *= glm::scale(glm::mat4(1.0f), glm::vec3(0.25f));

    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvStack.top()));
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_TRIANGLES, 0, 36);

    mvStack.pop(); mvStack.pop(); mvStack.pop(); mvStack.pop();
}

static variables are initialized once in a function and maintain their original value throughout the scope of that function and go out of scope with that function. In my mind since it's only allocated once, assigned to once and maintains the same value and address in memory then there shouldn't be much of a performance concern except during the very first call of the function when the variable is actually instantiated.

Any performance concerns to keep in mind? Would global variables be a better alternative in terms of performance?


Solution

  • I believe your question can be simplied down to this one Is there a penalty for using static variables in C++11, and it seems that the answer is "yes, but mildly"

    The second answer posits an explanation to this:

    Yes, there will be a cost to check whether the object has been initialised. This would typically test an atomic Boolean variable, rather than lock a mutex. @Mike Seymour

    I believe it is better to examine the linked question and the top answer, they are golden