2013-08-21 41 views
0

考慮我已經使用了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窗口顯示紋理的用法如何?
是否有減少使用量?
順便說一句:爲什麼使用量如此之大?

回答

3

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

1

這需要更多的調查,但你可能有你的主迴路問題。

這可能不是用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