Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

opengl + winapi пример дайте, чтоб 100% проца не занимал

25K
27 февраля 2007 года
vadim100
2 / / 18.02.2007
Здравствуйте!

Проблема такая.
Не могу найти примера opengl+чистый WinApi , чтоб программа была с меню,тоолбаром и opengl
и при выполнении не загружала процессор на 100%. То есть перерисовывалась не постоянно, а по сообщениям.
Перерисовка по таймеру мне не нравится.
На MFC такие примеры нашел - все классно, но не хочу его.
А на чистом winapi не нашел - все проги сразу 100% проца жрут. Весь инет облазил.
Подскажите куда рыть, а лучше примерчик киньте пожалуйста.

Вадим.
8.2K
28 февраля 2007 года
Akela
64 / / 13.05.2005
Функция WinMain должна иметь примерно такой вид:

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG Message;

while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);

DrawScene();
}
}
25K
28 февраля 2007 года
vadim100
2 / / 18.02.2007
Цитата: Akela

while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);

DrawScene();
}
}



До этого я дошел тоже, но перерисовка осуществляется по всем событиям окна, что на мой взгляд неправильно.
если у меня например область рисования не на все окно а на часть будет.
Эх похоже придется на mfc разбираться. :(

9
28 февраля 2007 года
Lerkin
3.0K / / 25.03.2003
Ну, а реакцию на события расписать не судьба?
Код:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    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;
}


Тут перерисовка выполняется, только если изменяется размер окна.
534
01 марта 2007 года
HarryAxe
448 / / 19.01.2006
Цитата: Lerkin
Ну, а реакцию на события расписать не судьба?


Дофига делов. Любое непредвиденное событие (как то: часть окна закрыта другим окном, выбран пункт меню, возникло всплывающее сообщение и т. п.) - и всё, гейм овер. Часть области вывода окажется белым прямоугольником.

Цитата:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG Message;

while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);

DrawScene();
}
}



Ты, наверное, хотел написать так:

Код:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    while (TRUE)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            Render();
        }
    }
}
Но это - слишком жирно для оконного приложения. На заднем плане могут быть запущены иные программы, которые процессорного времени хотят столько, сколько им необходимо для нормальной обработки сообщений и отрисовки своих окон. По-моему, самый нормальный вариант - либо таймер с тридцаточкой в качестве интервала срабатывания, либо вышеприведённый цикл с искусственной задержкой после рендера. Типа
 
Код:
const DWORD dwDelayTime = 30;

    DWORD dwTime = GetTickCount();

    Render();

    dwTime = GetTickCount() - dwTime;
    if (dwTime < dwDelayTime)
        Sleep(dwDelayTime - dwTime);
Это может вызвать некоторую (чрезвычайно малую) задержку обработки сообщений, но интервал задержки менее 40 миллисекунд делает её совершенно незаметной человеческому глазу. Ну, а ещё можно контролировать, сколько раз подряд происходит заход в функцию отрисовки, и, скажем, после второго производить переключение на другой поток:
Код:
DWORD dwCount = 0;
    while (1)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            ...
            dwCount = 0;
        }
        else
        {
            if (dwCount > 1)
                SwitchToThread();

            Render();
            dwCount++;
        }
    }
302
02 марта 2007 года
Sagittarius
648 / / 12.04.2003
А по событию WM_PAINT никак чтоли? Если нужна перерисовка, то вызываешь Invalidate.
8.2K
02 марта 2007 года
Akela
64 / / 13.05.2005
Цитата: HarryAxe


Ты, наверное, хотел написать так:
Код:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    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% ;).

534
03 марта 2007 года
HarryAxe
448 / / 19.01.2006
Цитата: Akela
Я так написать НЕ хотел, потому что в этом случае приложение при отсутствии сообщений все время осуществляет перерисовку => процессор практически всегда загружен на 100% ;).

В твоём случае проц всё равно будет загружен почти на всю катушку, поскольку перерисовка будет происходить и при возникновении таких событий, как WM_SETCURSOR или WM_NCHITTEST, которые поступают в очередь сообщений окна почти непрерывно.

534
03 марта 2007 года
HarryAxe
448 / / 19.01.2006
Цитата: Sagittarius
А по событию WM_PAINT никак чтоли? Если нужна перерисовка, то вызываешь Invalidate.


Нормально. Но если сцена анимированная, то WM_PAINT придётся форсить по таймеру, а автор их за что-то не взлюбил и посему просит иного решения.

33K
12 октября 2007 года
aamonster
2 / / 12.10.2007
Прошу прощения, что поднимаю древнюю тему, но возник похожий вопрос:

Допустим, рисуем в окне с double buffering.
Если вызвать кучу функций отрисовки (ну там, скажем, DrawArrays), а потом сразу SwapBuffers - программа (точнее, thread) ждет, пока видеокарта отрисует картинку, и только потом собственно свопит буферы и продолжает выполнение. Собственно, все равно что вызвать
glFinish();
SwapBuffers(hdc);

Получается, что в то время, как программа могла бы делать что-то полезное (в моем случае - обработку входной информации), она крутится в каком-то тупом цикле внутри SwapBuffers/glFinish. Что делать? Снижать приоритет треда?

Эх, было бы что-нибудь типа glReady() - проблем бы не было... Замутил бы while(!glReady()) Sleep(0);

UPD: Сейчас перед SwapBuffers стоит Sleep(1) - сильно снижает загрузку проца, но нутром чую, что можно сделать лучше. К тому же недоумеваю, почему Sleep(0) практически не дает эффекта.
534
13 октября 2007 года
HarryAxe
448 / / 19.01.2006
Вопрос не совсем понятен. Что именно ты хочешь делать между отрисовкой и переключением буфферов? Сообщения обрабатывать? Если нет, то обработку данных своих ты можешь вынести в отдельный поток, и никаких проблем...
К тому же, не ясно, в какой ситуации ты производишь рендер. Если отрисовка вызывается при простое, то, может, имеет смысл поменять местами вызовы?
 
Код:
bool OnIdle(INT_PTR someParameter)
    {
        SwapBuffers();
        Render();
        return true;
    }

При таком раскладе, пока идёт отрисовка, мы можем пообрабатывать сообщения.
33K
15 октября 2007 года
aamonster
2 / / 12.10.2007
Я хочу, чтобы тред отрисовки по возможности не тратил время CPU (благо, вся его работа - вызвать десяток-другой команд OpenGL). Вся основная обработка идет в других тредах.

Да, отрисовка - не по 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); // на всякий случай
}
53K
02 октября 2009 года
jaranero
1 / / 02.10.2009
Перечитал все посты, но так и не нашел способа избавиться от 100% загрузки проца кроме 2-х способов:

1. Использовать MFC + OpenGL.
2. Использовать задержку Sleep(1) в главном цикле программы.

Первый метод явно устарел (это я о MFC). А вот второй очень уж непрофессиональный, хотя в посте выше метод вполне обдуманый (хотя лучше t0=(t0+t)/2), но это тоже очень неспортивно...

Попробовал создать таймер в WinAPI, но загрузка так и осталась 100%, хотя интервал таймера был высок (77 милисекунд). И более того, даже при полном отсутствии прорисовки загрузка проца 100%!!! Почему?

Итак, все же не понятно! Как это в MFC устроено так, что программа не загружает процессор? И что же тогда загружает процессор в WinAPI?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог