opengl + winapi пример дайте, чтоб 100% проца не занимал
Проблема такая.
Не могу найти примера opengl+чистый WinApi , чтоб программа была с меню,тоолбаром и opengl
и при выполнении не загружала процессор на 100%. То есть перерисовывалась не постоянно, а по сообщениям.
Перерисовка по таймеру мне не нравится.
На MFC такие примеры нашел - все классно, но не хочу его.
А на чистом winapi не нашел - все проги сразу 100% проца жрут. Весь инет облазил.
Подскажите куда рыть, а лучше примерчик киньте пожалуйста.
Вадим.
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG Message;
while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
DrawScene();
}
}
while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
DrawScene();
}
}
До этого я дошел тоже, но перерисовка осуществляется по всем событиям окна, что на мой взгляд неправильно.
если у меня например область рисования не на все окно а на часть будет.
Эх похоже придется на mfc разбираться. :(
{
switch(uMsg)
{
case WM_CREATE: ...
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE: // при изменении размера окна
GL_ReDraw();
break;
...
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
Тут перерисовка выполняется, только если изменяется размер окна.
Дофига делов. Любое непредвиденное событие (как то: часть окна закрыта другим окном, выбран пункт меню, возникло всплывающее сообщение и т. п.) - и всё, гейм овер. Часть области вывода окажется белым прямоугольником.
{
MSG Message;
while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
DrawScene();
}
}
Ты, наверное, хотел написать так:
{
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render();
}
}
}
DWORD dwTime = GetTickCount();
Render();
dwTime = GetTickCount() - dwTime;
if (dwTime < dwDelayTime)
Sleep(dwDelayTime - dwTime);
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
...
dwCount = 0;
}
else
{
if (dwCount > 1)
SwitchToThread();
Render();
dwCount++;
}
}
Ты, наверное, хотел написать так:
{
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render();
}
}
}
Я так написать НЕ хотел, потому что в этом случае приложение при отсутствии сообщений все время осуществляет перерисовку => процессор практически всегда загружен на 100% ;).
В твоём случае проц всё равно будет загружен почти на всю катушку, поскольку перерисовка будет происходить и при возникновении таких событий, как WM_SETCURSOR или WM_NCHITTEST, которые поступают в очередь сообщений окна почти непрерывно.
Нормально. Но если сцена анимированная, то WM_PAINT придётся форсить по таймеру, а автор их за что-то не взлюбил и посему просит иного решения.
Допустим, рисуем в окне с double buffering.
Если вызвать кучу функций отрисовки (ну там, скажем, DrawArrays), а потом сразу SwapBuffers - программа (точнее, thread) ждет, пока видеокарта отрисует картинку, и только потом собственно свопит буферы и продолжает выполнение. Собственно, все равно что вызвать
glFinish();
SwapBuffers(hdc);
Получается, что в то время, как программа могла бы делать что-то полезное (в моем случае - обработку входной информации), она крутится в каком-то тупом цикле внутри SwapBuffers/glFinish. Что делать? Снижать приоритет треда?
Эх, было бы что-нибудь типа glReady() - проблем бы не было... Замутил бы while(!glReady()) Sleep(0);
UPD: Сейчас перед SwapBuffers стоит Sleep(1) - сильно снижает загрузку проца, но нутром чую, что можно сделать лучше. К тому же недоумеваю, почему Sleep(0) практически не дает эффекта.
К тому же, не ясно, в какой ситуации ты производишь рендер. Если отрисовка вызывается при простое, то, может, имеет смысл поменять местами вызовы?
{
SwapBuffers();
Render();
return true;
}
При таком раскладе, пока идёт отрисовка, мы можем пообрабатывать сообщения.
Да, отрисовка - не по Idle, а по некоему периодическому событию (пришел блок данных, другой тред его обработал - все готово для отрисовки... хотя если окажется, что удобнее обрабатывать в треде отрисовки - так и сделаю).
Вариант поменять местами отрисовку и SwapBuffers - интересный, спасибо. Конечно, получится небольшое запаздывание отрисовки, зато уж точно никаких лишних затрат CPU.
Но вообще, конечно, удивительно. Неужели нет никакого вызова типа BufferReady или glQueueEmpty? Логично было бы его сделать, раз уж отрисовка идет независимо.
P.S. Подумал и придумал решение (ориентированное на то, что отрисовка всегда занимает примерно одинаковое время):
double t0 = 0;
while(...)
{
дождаться данных
Render();
Sleep(t0);
t = GetTickCount();
SwapBuffers();
t = GetTickCount() - t;
t0 = t0*0.95 + t; // t0 потихоньку выйдет на такой уровень, что SwapBuffers будет занимать минимум времени
t0 = max(t0,25); // на всякий случай
}
1. Использовать MFC + OpenGL.
2. Использовать задержку Sleep(1) в главном цикле программы.
Первый метод явно устарел (это я о MFC). А вот второй очень уж непрофессиональный, хотя в посте выше метод вполне обдуманый (хотя лучше t0=(t0+t)/2), но это тоже очень неспортивно...
Попробовал создать таймер в WinAPI, но загрузка так и осталась 100%, хотя интервал таймера был высок (77 милисекунд). И более того, даже при полном отсутствии прорисовки загрузка проца 100%!!! Почему?
Итак, все же не понятно! Как это в MFC устроено так, что программа не загружает процессор? И что же тогда загружает процессор в WinAPI?