1

I have a game with models and when I render them my CPU usage goes high (about 10% per one model). I use glutMainLoop which calls DisplayFunc 60 times per one second. I call drawing functions there where is

  • glPushMatrix
  • glTranslatef, glRotatef, glScalef
  • glMaterialfv so materials for texture, I bind my texture
  • glBegin for triangles
  • then in loop for faces glNormal3f, glTexCoord2f, glVertex3f for triangles
  • glEnd
  • and glPopMatrix

I don't know what I am doing wrong and I don't have any foothold, so that's why I'm asking here.

Ok, so I made simple correction and is it all right now?

    #include <GL/glut.h>
    #include <gl/glext.h>

    void Display();
    void Reshape(int width, int height);

    const int windowWidth = 480;
    const int windowHeight = 270;

    GLuint vertexbuffer;
    static const GLfloat g_vertex_buffer_data[] =
    {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f,  1.0f, 0.0f,
    };

    int main(int argc, char* argv[])
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
        glutInitWindowPosition(100, 100);
        glutInitWindowSize(windowWidth, windowHeight);
        glutCreateWindow("Modern OpenGL");

        glutDisplayFunc(Display);
        glutReshapeFunc(Reshape);
        glutIdleFunc(Display);

        GLfloat reset_ambient[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, reset_ambient);
        glEnable(GL_LIGHTING);
        glShadeModel(GL_SMOOTH);
        glEnable(GL_LIGHT0);

        glGenBuffers(1, &vertexbuffer);

        glutMainLoop();

        return 0;
    }

    void Display()
    {
        glClearColor(1.0, 1.0, 1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();

        gluLookAt(0,0,10,0,0,0,0,1,0);

        GLfloat light0amb[4] = { 1.0, 1.0, 1.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_AMBIENT, light0amb);
        GLfloat light0dif[4] = { 1.0, 1.0, 1.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light0dif);
        GLfloat light0spe[4] = { 1.0, 1.0, 1.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_SPECULAR, light0spe);
        GLfloat light0pos[4] = { 0.0, 0.0, 0.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_POSITION, light0pos);

        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(
            0,
            3,
            GL_FLOAT,
            GL_FALSE,
            0,
            (void*)0
        );
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glDisableVertexAttribArray(0);

        glFlush();
        glutSwapBuffers();
    }

    void Reshape(int width, int height)
    {
        glutReshapeWindow(windowWidth, windowHeight);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glViewport(0, 0, width, height);
        gluPerspective(45.0f, width / (double)height, 0.1f, 1000.0f);
        glMatrixMode(GL_MODELVIEW);
    }
ground0
  • 33
  • 4
  • 3
    You should stop using deprecated `glBegin`/`glEnd` and fixed pipeline API and switch to vertex buffers and shaders. [See this question.](http://stackoverflow.com/questions/14300569/opengl-glbegin-glend) – user7860670 Apr 19 '17 at 19:40
  • I'm sort of an opengl noob, but are you doing face culling properly ? https://learnopengl.com/#!Advanced-OpenGL/Face-culling – ether_joe Apr 20 '17 at 19:29
  • @VTT can you comment what I added? – ground0 Apr 21 '17 at 21:38
  • Yes, you do create the whole VB at once instead of pushing vertex by vertex (though recreating the same buffer every frame does not make much sense), but your code still uses the same deprecated fixed pipeline API. Also it is not clear how do you measure performance. Did you actually get more fps our CPU utilization is wasted on something else? – user7860670 Apr 22 '17 at 06:08

2 Answers2

2

VTT's comment re: glBegin/glEnd is the correct answer. To expand upon it a bit, by using the old, deprecated API you are running into one definite problem and one potential problem.

The definite problem is that OpenGL cannot take advantage of a number of hardware acceleration features in modern GPUs because rather than having all of the triangles (i.e. vertices) and materials (e.g. textures) stored in GPU memory, it will likely need to copy at least some of those from main memory to GPU memory every time you render things. That's a non-trivial expense that you can easily avoid by using vertex buffers along with vertex shaders and fragment shaders.

There are many examples out there if you search for them so while it may take some time to refactor your code, knowing how to do it shouldn't been an issue.

The potential problem is that the fixed function pipeline has been deprecated for a while (and informally discouraged for even longer) such that many drivers likely contain that functionality more for compatibility with older games and applications rather than as active targets for optimization. In other words, developer time is spent on optimizing the modern APIs rather than the APIs of the late 1990s.

It's likely not your fault that you ended up writing your code in the way you did. Unfortunately, the web and freely available copies of older books provide a lot of examples based on the old fixed function pipeline rather than the modern programmable pipeline. Combined with the fact that (initially) the fixed function pipeline is often easier to understand and use, it leads to situations like the one you are in. But it's well worth the time to learn the modern APIs. It opens a wealth of opportunities in terms of the effects you can use to make your graphics shine even on "low-end" systems.

MikeBMcL
  • 414
  • 3
  • 6
0

So now you're doing things the new way, but you're not taking advantage of everything you can. You're uploading your geometry every time you render. Since it's not changing (you're using GL_STATIC_DRAW) don't upload it more than once. Once it's up there in video memory it will stay there until you delete it. Same with the uniforms for your shaders. The only calls you need are clearing the color, binding the various arrays and attributes, drawing the arrays, then unbinding the various arrays and attributes. And probably the flush. The glBufferData() call is probably what's taking so long.

Also, I have to say that 10% CPU usage is nothing. I'm not sure why that concerns you. In fact, the various new renderers (Metal, Vulkan, DX12) are basically useful for reducing the CPU component of your rendering. If it was only 10%, they'd hardly be needed!

user1118321
  • 25,567
  • 4
  • 55
  • 86