ground0
ground0

Reputation: 33

How to properly render models (meshes with textures) in OpenGL game without high CPU usage?

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

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);
    }

Upvotes: 1

Views: 300

Answers (2)

user1118321
user1118321

Reputation: 26345

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!

Upvotes: 0

MikeBMcL
MikeBMcL

Reputation: 424

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.

Upvotes: 2

Related Questions