Sepideh Abadpour
Sepideh Abadpour

Reputation: 2598

CPU usage is high when using opengl control class?

Consider I have used the OpenGL Control class as follows: (No need to read the code, I have just made slight changes to be able to use the code in more than one opengl window)

OpenGLControl.cpp

#include "stdafx.h"
#include "OpenGLControl.h"

COpenGLControl::COpenGLControl(void)
{
m_fPosX = 0.0f;     // X position of model in camera view
m_fPosY = 0.0f;     // Y position of model in camera view
m_fZoom = 10.0f;    // Zoom on model in camera view
m_fRotX = 0.0f;     // Rotation on model in camera view
m_fRotY = 0.0f;     // Rotation on model in camera view
m_bIsMaximized = false;
}

COpenGLControl::~COpenGLControl(void)
{
}

BEGIN_MESSAGE_MAP(COpenGLControl, CWnd)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_TIMER()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

void COpenGLControl::OnPaint()
{
//CPaintDC dc(this); // device context for painting
ValidateRect(NULL);
}

void COpenGLControl::OnSize(UINT nType, int cx, int cy)
{
wglMakeCurrent(hdc, hrc);
CWnd::OnSize(nType, cx, cy);

if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;

// Map the OpenGL coordinates.
glViewport(0, 0, cx, cy);
// Projection view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set our current view perspective
gluPerspective(35.0f, (float)cx / (float)cy, 0.01f, 2000.0f);
// Model view
glMatrixMode(GL_MODELVIEW);
wglMakeCurrent(NULL, NULL);
}

int COpenGLControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;

oglInitialize();

return 0;
}

void COpenGLControl::OnDraw(CDC *pDC)
{
wglMakeCurrent(hdc,hrc);
// If the current view is perspective...
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -m_fZoom);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
wglMakeCurrent(NULL, NULL);
}

void COpenGLControl::OnTimer(UINT nIDEvent)
{
wglMakeCurrent(hdc,hrc);
switch (nIDEvent)
{
    case 1:
    {
        // Clear color and depth buffer bits
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Draw OpenGL scene
        oglDrawScene();

        // Swap buffers
        SwapBuffers(hdc);

        break;
    }

    default:
        break;
}

CWnd::OnTimer(nIDEvent);
wglMakeCurrent(NULL, NULL);
}

void COpenGLControl::OnMouseMove(UINT nFlags, CPoint point)
{
wglMakeCurrent(hdc,hrc);
int diffX = (int)(point.x - m_fLastX);
int diffY = (int)(point.y - m_fLastY);
m_fLastX  = (float)point.x;
m_fLastY  = (float)point.y;

// Left mouse button
if (nFlags & MK_LBUTTON)
{
    m_fRotX += (float)0.5f * diffY;

    if ((m_fRotX > 360.0f) || (m_fRotX < -360.0f))
    {
        m_fRotX = 0.0f;
    }

    m_fRotY += (float)0.5f * diffX;

    if ((m_fRotY > 360.0f) || (m_fRotY < -360.0f))
    {
        m_fRotY = 0.0f;
    }
}

// Right mouse button
else if (nFlags & MK_RBUTTON)
{
    m_fZoom -= (float)0.1f * diffY;
}

// Middle mouse button
else if (nFlags & MK_MBUTTON)
{
    m_fPosX += (float)0.05f * diffX;
    m_fPosY -= (float)0.05f * diffY;
}

OnDraw(NULL);

CWnd::OnMouseMove(nFlags, point);
wglMakeCurrent(NULL, NULL);
}

void COpenGLControl::oglCreate(CRect rect, CWnd *parent,CString windowName)
{
CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, (HBRUSH)GetStockObject(BLACK_BRUSH), NULL);
CreateEx(0, className,windowName, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0);
// Set initial variables' values
m_oldWindow    = rect;
m_originalRect = rect;
hWnd = parent;
}

void COpenGLControl::oglInitialize(void)
{
// Initial Setup:
//
static PIXELFORMATDESCRIPTOR pfd =
{
    sizeof(PIXELFORMATDESCRIPTOR),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,
    32, // bit depth
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    24, // z-buffer depth
    8,0,PFD_MAIN_PLANE, 0, 0, 0, 0,
};

// Get device context only once.
hdc = GetDC()->m_hDC;
// Pixel format.
m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, m_nPixelFormat, &pfd);
// Create the OpenGL Rendering Context.
hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
// Basic Setup:
//
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
// Send draw request
OnDraw(NULL);
wglMakeCurrent(NULL, NULL);
}

void COpenGLControl::oglDrawScene(void)
{
wglMakeCurrent(hdc, hrc);
// Wireframe Mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
        // Front Side
        glVertex3f( 1.0f,  1.0f, 1.0f);
        glVertex3f(-1.0f,  1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f( 1.0f, -1.0f, 1.0f);

        // Back Side
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f,  1.0f, -1.0f);
        glVertex3f( 1.0f,  1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);

        // Top Side
        glVertex3f( 1.0f, 1.0f,  1.0f);
        glVertex3f( 1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f,  1.0f);

        // Bottom Side
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f, -1.0f,  1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);

        // Right Side
        glVertex3f( 1.0f,  1.0f,  1.0f);
        glVertex3f( 1.0f, -1.0f,  1.0f);
        glVertex3f( 1.0f, -1.0f, -1.0f);
        glVertex3f( 1.0f,  1.0f, -1.0f);

        // Left Side
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f,  1.0f);
        glVertex3f(-1.0f,  1.0f,  1.0f);
        glVertex3f(-1.0f,  1.0f, -1.0f);
glEnd();
wglMakeCurrent(NULL, NULL);
}  

MyOpenGLTestDlg.h

COpenGLControl m_oglWindow;
COpenGLControl m_oglWindow2;  

MyOpenGLTestDlg.cpp

// TODO: Add extra initialization here
CRect rect;    
// Get size and position of the picture control
GetDlgItem(ID_OPENGL)->GetWindowRect(rect);
// Convert screen coordinates to client coordinates
ScreenToClient(rect);
// Create OpenGL Control window
CString s1("OPEN_GL");
m_oglWindow.oglCreate(rect, this,s1);
// Setup the OpenGL Window's timer to render
m_oglWindow.m_unpTimer = m_oglWindow.SetTimer(1, 1, 0);


CRect rect2;
GetDlgItem(ID_OPENGL2)->GetWindowRect(rect2);
ScreenToClient(rect2);
CString s2("OPEN_GL2");
m_oglWindow2.oglCreate(rect2, this,s2);
m_oglWindow2.m_unpTimer = m_oglWindow2.SetTimer(1, 1, 0);  

The problem is when I only create one OpenGL window, the system shows:

physical memoey: 48%
CPU usage: 54%

and when I create two windows, it shows:

physical memoey: 48%
CPU usage: 95%

I'm concerned that, it is only for such simple geometries!!!
How will be the usage for two opengl windows showing textures??
Is there anyway to reduce the usage?
BTW: why is the usage so much as mensioned?

Upvotes: 0

Views: 1041

Answers (2)

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

CPU usage doesn't actually indicate anything about the complexity of your application. If you draw in a tight loop, one frame after the other with no delay or VSYNC enabled you can achieve 100% CPU utilization. What this tells you is you are not GPU bound. The same way if your GPU usage (yes, you can measure this with vendor-specific APIs) is >95% then you are not CPU bound.

In short, you should expect to see very high CPU usage if the GPU is not doing anything particularly complicated :) You can always increase the sleep/timer interval to reduce CPU utilization. Remember that CPU utilization is measured as the time spent doing work versus the total time the OS gave a thread/process. Time spent working is inversely related to time spent waiting (for I/O, sleep, etc.). If you increase the time spent waiting, it will reduce the time spent working, and therefore your reported utilization.

You can also reduce the CPU usage just by enabling VSYNC. Since that will block the calling thread until the VBLANK interval comes around (often 16.666 ms).

It should also be noted that a 1 ms timer interval on your OpenGL timer is excessively low. I cannot think of a lot of applications that need to draw 1000 times a second :) Try something slightly below your target refresh rate (e.g. Monitor = 60 Hz, then try a 10-15 ms timer interval)

Upvotes: 3

fen
fen

Reputation: 10115

This needs more investigation but you may have problems with your main-loop.

This probably is not a problem with OpenGL, but with usage of WinApi. When you add textures, models, shaders... your cpu usage should be similar.

You use SetTimer(1, 1, 0); it means 1 millisecond of delay as I understand? Can you change it to 33 milliseconds (33 FPS)? That way you will not kill your message pump in mfc app. Note that this timer is very imprecise.

link to [Basic MFC + OpenGL Message loop], (http://archive.gamedev.net/archive/reference/articles/article2204.html), using OnIdle()

Here is a great tutorial about MFC + opengl + threading - @songho

https://gamedev.stackexchange.com/questions/8623/a-good-way-to-build-a-game-loop-in-opengl - discussoion regarding mail loop in GLUT

Upvotes: 1

Related Questions