使用opengl控件类时CPU使用率是多少?

时间:2013-08-21 18:43:48

标签: visual-studio-2010 opengl mfc rendering cpu-usage

考虑我使用OpenGL Control class如下:(无需阅读代码,我刚刚使slight changes能够在多个opengl窗口中使用代码)

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

问题是当我只创建一个OpenGL窗口时,系统会显示:

物理记忆:48%
CPU使用率:54%

当我创建两个窗口时,它会显示:

物理记忆:48%
CPU使用率:95%

我担心的是,它只适用于如此简单的几何形状!!! 如何使用两个显示纹理的opengl窗口? 无论如何要减少使用量?
顺便说一句:为什么用量如此之多?

2 个答案:

答案 0 :(得分:3)

CPU使用率实际上并未表明应用程序的复杂性。如果您绘制一个紧密的循环,一帧接一个没有延迟或启用VSYNC,您可以实现100%的CPU利用率。这告诉你的是你 GPU绑定。如果您的GPU使用率(是的,您可以使用特定于供应商的API来衡量),那么同样的方式是> 95%,那么您就不受CPU限制。

简而言之,如果GPU没有做任何特别复杂的事情,你应该会看到非常高的CPU使用率:)你总是可以增加睡眠/定时器间隔以降低CPU利用率。请记住,CPU利用率是指工作时间与操作系统提供线程/进程的总时间之间的关系。工作时间与等待时间(I / O,睡眠等)成反比。如果增加等待的时间,将减少工作时间,从而减少报告的利用率。

您也可以通过启用VSYNC来降低CPU使用率。因为这会阻塞调用线程,直到VBLANK间隔到来(通常是16.666 ms)。

还应注意,OpenGL定时器的1 ms定时器间隔过低。我想不出很多需要每秒绘制1000次的应用程序:)尝试略低于目标刷新率的东西(例如Monitor = 60 Hz,然后尝试10-15 ms的定时器间隔)

答案 1 :(得分:1)

这需要更多调查,但您的主循环可能会出现问题。

这可能不是OpenGL的问题,而是使用WinApi。当你添加纹理,模型,着色器......你的cpu使用应该是相似的。

你使用SetTimer(1, 1, 0);这意味着我理解延迟1毫秒?你能把它改成 33 毫秒(33 FPS)吗? 这样你就不会在mfc app中杀死你的消息泵。请注意,此计时器非常不精确。

使用OnIdle()链接到[基本MFC + OpenGL消息循环],(http://archive.gamedev.net/archive/reference/articles/article2204.html

以下是关于MFC + opengl + threading - @songho

的精彩教程

https://gamedev.stackexchange.com/questions/8623/a-good-way-to-build-a-game-loop-in-opengl - 关于GLUT邮件循环的讨论