【问题标题】:CPU usage is high when using opengl control class?使用opengl控制类时CPU使用率很高?
【发布时间】:2013-08-21 18:43:48
【问题描述】:

考虑一下我已经使用了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窗口将如何使用?
有没有办法减少用量?
BTW:为什么用法如此之多?

【问题讨论】:

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


    【解决方案1】:

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

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

    您也可以通过启用 VSYNC 来减少 CPU 使用率。因为这将阻塞调用线程,直到 VBLANK 间隔到来(通常为 16.666 毫秒)。

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

    【讨论】:

    • 除此之外,Windows 有一种不幸的方式来确定 CPU 利用率。如果一个程序在系统上下文中阻塞(就像它在调用 wglSwapBuffers 时所做的那样),它花费在阻塞上的时间会被误解为实际的 CPU 时间消耗,即使时间片立即让给其他进程也是如此。最终效果是,即使启用了 VSync,在紧密循环中渲染的 OpenGL 程序也会显示(接近)100% 的 CPU 利用率。在wglSwapBuffers 之后添加Sleep(1); 可以使显示的值更合理。
    • 啊,听起来驱动程序正在选择自旋锁式等待以提高它不会错过 VBLANK 的几率。忙碌的等待使我在上面写的内容受到影响:)
    • 与其说是自旋锁(它会消耗大量的 CPU 时间,在最坏的情况下等待 16 毫秒是不可接受的),不如说它只是一种计算 CPU 使用率的不幸方式。有些人甚至称其为错误。
    • 哦,是的,你完全正确。我记得在 Win32 上做一个本科研究项目,发现(documented)内核只使用一个计数器来跟踪 CPU 时间,该计数器以预定的时间间隔对 CPU 状态进行采样。它很难解释占用样本间隔的一小部分的操作。因此,CPU 时间往往会在看起来像最大整数函数的情况下增长,我可以看到这将如何完全弄乱 CPU 利用率数字。有更准确的方法来确定 CPU 使用率,但 taskman.exe 不使用它们:P
    【解决方案2】:

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

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

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

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

    这是一个关于MFC + opengl + threading - @songho的很棒的教程

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      • 2020-11-13
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多