我目前正在开发一个将标准win32转换为C ++类的OpenGL win32项目。在最初的实现过程中,我遇到了一个问题,当窗口调整大小时,框架冻结,窗口的大小变化非常缓慢,从一个大小跳到另一个大小。当窗口完成调整大小时,在窗口更新绘图表面之前会有明显的犹豫。
我正在使用WM_TIMER尽可能频繁地更新显示。在“正常”操作期间,程序清除屏幕,慢慢更新红色组件以在视觉上显示表面图纸的变化。考虑到测试的极其简单的设计,我无法想象在调整大小事件期间openGL代码是问题。我做了测试,看看是否通过按下鼠标按钮手动调整窗口大小,调用带有调整值的setwindowpos会导致相同的行为,并且确实如此。如果我保持大小相同并且调用SetWindowPos,则屏幕不会停止。这让我相信调整大小处理代码中的某些东西会以某种方式锁定HDC,从而阻止交换缓冲区以高速执行。可能在Win32调整代码的某个地方等待多线程锁定。
下面是一个小程序,它表现出与较大程序完全相同的行为。 只使用外部lib是opengl32.lib。
#include "stdafx.h"
#include "OpenGLTest.h"
#include <gl\GL.h>
#define MAX_LOADSTRING 100
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
ATOM MyRegisterClass(HINSTANCE hInstance,LPCTSTR strClassName,WNDPROC wndProc,HBRUSH brBackground);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND _hWnd;
HDC _hDC;
HGLRC _glRC;
BOOL DrawWindow();
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_OPENGLTEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance,szWindowClass,WndProc,NULL);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OPENGLTEST));
// Main message loop:
bool bRun=true;
while (bRun)
{
if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message==WM_QUIT)
{
break;
}
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance,LPCTSTR strClassName,WNDPROC wndProc,HBRUSH brBackground)
{
WNDCLASSEX wcex;
//Register Main Window Class
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = wndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = brBackground;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = strClassName;
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!_hWnd)
{
return FALSE;
}
_hDC=GetDC(_hWnd);
if (_hDC!=nullptr)
{
//Create OpenGL 3.2 context
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
32, //Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, //Number of bits for the depthbuffer
8, //Number of bits for the stencilbuffer
0, //Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int nPixelFormat=ChoosePixelFormat(_hDC,&pfd);
SetPixelFormat(_hDC,nPixelFormat,&pfd);
if ((_glRC=wglCreateContext(_hDC))!=nullptr)
{
//Make Context Current
wglMakeCurrent(_hDC,_glRC);
}
}
ShowWindow(_hWnd, nCmdShow);
UpdateWindow(_hWnd);
SetTimer(_hWnd, 0, 1, NULL);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_TIMER:
DrawWindow();
break;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
BeginPaint(_hWnd,&ps);
EndPaint(_hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
float fRed=0.0f;
BOOL DrawWindow()
{
RECT rc;
GetClientRect(_hWnd,&rc);
HDC hDC=GetDC(_hWnd);
if ((hDC!=nullptr)&&(_glRC!=nullptr))
{
//Print Client Data to Window Title for debugging
TCHAR strTitle[MAX_LOADSTRING];
wsprintf(strTitle,L"%d, %d, %d, %d",rc.left,rc.top,rc.right,rc.bottom);
SetWindowText(_hWnd,strTitle);
wglMakeCurrent(hDC,_glRC);
glViewport(rc.left,rc.top,(rc.right-rc.left),(rc.bottom-rc.top));
glClearColor(fRed,1.0f,0.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(hDC);
fRed+=0.1;
if (fRed>1.0f) fRed=0.0f;
ReleaseDC(_hWnd,hDC);
}
return TRUE;
}
编辑:问题是硬件问题而不是软件问题。我转移到另一个系统,问题不存在。谢谢你的帮助。