0

次のように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 ウィンドウを 1 つだけ作成すると、システムに次のように表示されることです。

物理メモリ: 48%
CPU 使用率: 54%

2 つのウィンドウを作成すると、次のように表示されます。

物理メモリ: 48%
CPU 使用率: 95%

私は心配しています、それはそのような単純な形状のためだけです!!!
テクスチャを表示する 2 つの OpenGL ウィンドウの使用方法は??
とにかく使用量を減らすことはありますか?
ところで:なぜ使用法が言及されているのですか?

4

2 に答える 2

3

CPU 使用率は、実際にはアプリケーションの複雑さを示すものではありません。遅延や VSYNC を有効にせずにフレームを次々とタイトなループで描画すると、100% の CPU 使用率を達成できます。これは、 GPU に縛られていないことを示しています。同じように、GPU 使用率 (そうです、ベンダー固有の API で測定できます) が 95% を超える場合、CPU バウンドではありません。

要するに、GPU が特に複雑なことをしていない場合、CPU 使用率が非常に高くなることが予想されます:) CPU 使用率を下げるために、いつでもスリープ/タイマー間隔を増やすことができます。CPU 使用率は、作業に費やされた時間と、OS がスレッド/プロセスに与えた合計時間の対比として測定されることに注意してください。作業に費やされる時間は、待機に費やされる時間 (I/O、スリープなど) に反比例します。待機に費やす時間を増やすと、作業に費やす時間が短縮されるため、報告される使用率が減少します。

VSYNC を有効にするだけで、CPU 使用率を削減することもできます。これにより、VBLANK 間隔 (多くの場合 16.666 ミリ秒) が来るまで、呼び出し元のスレッドがブロックされます。

また、OpenGL タイマーの 1 ミリ秒のタイマー間隔は短すぎることに注意してください。1 秒間に 1000 回描画する必要がある多くのアプリケーションは考えられません :) 目標のリフレッシュ レートを少し下回る値を試してみてください (例: モニター = 60 Hz、次に 10 ~ 15 ミリ秒のタイマー間隔を試してください)。

于 2013-08-21T19:16:53.177 に答える
1

これにはさらに調査が必要ですが、メインループに問題がある可能性があります。

これはおそらく OpenGL の問題ではなく、WinApi の使用の問題です。テクスチャ、モデル、シェーダーを追加すると、CPU 使用率は同様になります。

SetTimer(1, 1, 0);私が理解しているように、1ミリ秒の遅延を意味しますか?33ミリ秒 (33 FPS)に変更できますか? そうすれば、mfc アプリでメッセージ ポンプを強制終了することはありません。このタイマーは非常に不正確であることに注意してください。

[Basic MFC + OpenGL Message loop] へのリンク ( http://archive.gamedev.net/archive/reference/articles/article2204.html ), usingOnIdle()

これは、 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 に答える