0

考虑一下我使用了OpenGL Control 类,如下所示:(无需阅读代码,我只是稍作改动 ,以便能够在多个 opengl 窗口中使用代码)

OpenGL控制.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:为什么用法如此之多?

4

2 回答 2

3

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 的计时器间隔)

于 2013-08-21T19:16:53.177 回答
1

这需要更多调查,但您的main-loop可能有问题。

这可能不是 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 + 线程的很棒的教程- @songho

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

于 2013-08-21T19:07:13.710 回答