使用opengl控件类时CPU使用率很高?

使用opengl控件类时CPU使用率很高?

问题描述:

考虑我已经使用了OpenGL Control class如下:(无需读取代码,我刚才提出slight changes能够使用代码在多于一个OpenGL窗口)使用opengl控件类时CPU使用率很高?

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窗口,则系统显示:

物理memoey:48%
CPU使用率:54 %

,当我创建两个风OWS,它表明:

物理memoey:48%
CPU使用率:95%

我担心,它只是这样简单的几何形状!
两个opengl窗口显示纹理的用法如何?
是否有减少使用量?
顺便说一句:为什么使用量如此之大?

CPU使用率邮件循环discussoion实际上并没有说明你的应用程序的复杂性。如果你画一个紧密的循环,一帧接一帧,没有延迟或VSYNC启用,你可以达到100%的CPU利用率。这告诉你,你是而不是 GPU绑定。如果您的GPU使用率(是的,您可以使用特定于供应商的API进行测量)大于95%,那么您也不会受到CPU限制。

总之,如果GPU没有做任何特别复杂的事情,您应该会看到非常高的CPU使用率。您可以随时增加睡眠/计时器间隔以降低CPU利用率。请记住,CPU使用率是根据工作时间与OS给出线程/进程的总时间来衡量的。花在工作上的时间与等待的时间(I/O,睡眠等)成反比。如果您增加等待的时间,这将减少工作时间,并因此减少您报告的利用率。

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

还应该注意的是,OpenGL定时器的1 ms定时器间隔过低。我想不到需要每秒钟抽取1000次的很多应用程序:)尝试稍微低于目标刷新率的内容(例如Monitor = 60 Hz,然后尝试10-15 ms的定时器间隔)

+0

除此之外Windows有一个确定CPU利用率的不幸方式。如果一个程序在系统上下文中被阻塞(就像在调用wglSwapBuffers时一样),但它花费的时间被误解为实际的CPU时间消耗,即使时间片立即被放到其他进程中。实际效果是,即使启用了VSync,OpenGL程序在紧密循环中的渲染也会显示(接近)100%的CPU利用率。在'wglSwapBuffers'之后加上'Sleep(1);'就可以使得显示的值更加合理。 – datenwolf

+0

啊,听起来像是司机正在选择spinlock-esque等待来提高它不会错过VBLANK的几率。忙碌的等待将扳机放入我上面写的东西:) –

+0

它不是一个自旋锁(它会消耗大量的CPU时间,在最坏的情况下等待16ms是不可接受的),但只是一个不幸的方式来考虑CPU用法。有些人甚至称它为错误。 – datenwolf

这需要更多的调查,但你可能有你的主回路问题。

这可能不是用OpenGL的一个问题,但与WINAPI的使用。当你添加纹理,模型,着色器...你的CPU使用率应该是相似的。

您使用SetTimer(1, 1, 0);这意味着延迟1毫秒,因为我明白了吗?你可以改变它为毫秒(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