使用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的定时器间隔)
这需要更多的调查,但你可能有你的主回路问题。
这可能不是用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
除此之外Windows有一个确定CPU利用率的不幸方式。如果一个程序在系统上下文中被阻塞(就像在调用wglSwapBuffers时一样),但它花费的时间被误解为实际的CPU时间消耗,即使时间片立即被放到其他进程中。实际效果是,即使启用了VSync,OpenGL程序在紧密循环中的渲染也会显示(接近)100%的CPU利用率。在'wglSwapBuffers'之后加上'Sleep(1);'就可以使得显示的值更加合理。 – datenwolf
啊,听起来像是司机正在选择spinlock-esque等待来提高它不会错过VBLANK的几率。忙碌的等待将扳机放入我上面写的东西:) –
它不是一个自旋锁(它会消耗大量的CPU时间,在最坏的情况下等待16ms是不可接受的),但只是一个不幸的方式来考虑CPU用法。有些人甚至称它为错误。 – datenwolf