Плавный гуишный процесс (без загруза CPU)

Тема в разделе "WASM.ASSEMBLER", создана пользователем Jin X, 22 фев 2018.

  1. Jin X

    Jin X Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    172
    Адрес:
    Кольца Сатурна
    Нужно реализовать плавный гуишный процесс. Например, процесс игры, где что-то плавно движется и отображается в окне. Либо что-то рисуется.
    Варианты:
    1. Использовать таймер.
    2. Использовать цикл с задержкой через Sleep (а обработку сообщений окна – через PeekMessage).
    3. Какой-то другой(?)
    Проблема п.1 и 2 заключается в том, что сделать достаточно короткую задержку весьма проблематично. У меня (на 10-ке) Sleep(1) работает примерно как Sleep(2), а Sleep(4) – как Sleep(5).
    Использование таймера работает ещё хуже, там при установке интервалов в 1 мс процедура таймера вызывается раз в 10-20 мс или что-то в этом духе.
    Вариант задержки через цикл с GetTickCount (или через QueryPerformanceCounter) вместо использования Sleep – отличный вариант, но грузит процессор по самое не хочу. Sleep(0), естественно, тут не помогает.

    Что можно сделать в данной ситуации. Может, с оконной функцией можно как-то поиграться?
    Как это вообще делается обычно?
     
  2. Jin X

    Jin X Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    172
    Адрес:
    Кольца Сатурна
    Точность задержки желательна до сотен миллисекунд (если можно ещё точнее, будет ещё лучше).
    Есть ещё NtDelayExecution, он работает поточнее, чем Sleep, но всё равно не фонтан (точность 1 мс примерно).
     
  3. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    357
    Используй мультимедийные таймеры. А вообще для игры лучше делать без задержек, и высчитывать дельту для физики между кадрами.
     
    Последнее редактирование: 22 фев 2018
    Jin X нравится это.
  4. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    808
    Адрес:
    Jabber: darksys@sj.ms
    Задержку можно создать функцией NtDelayExecution из ntdll.dll, она по круче Sleep.
    Про таймеры:
    Из прецизионных таймеров есть уже готовый timeSetEvent из winmm.dll.
    А самый точный таймер можно слепить самому (QueryPerformanceFrequency - сначала частоту таймера на данном железе узнаем) потом через QueryPerformanceCounter измеряем интервал в тиках. Это можно поместить в отдельный поток и задать ему хоть RealTime приоритет.
    Если двигаться ниже к асемблеру - там есть команда rtdsc, ей можно замерять производительность даже отдельных машинных кодов. Ну там уж если определять проц, то го ту то диван и интел ман ;)
     
  5. Jin X

    Jin X Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    172
    Адрес:
    Кольца Сатурна
    Я ж писал про неё: она выдаёт точность 1 мс.
    Но точность можно увеличить до 0,5 мс через NtQueryTimerResolution (или без неё, но с ней вроде как правильнее) + NtSetTimerResolution.
    Про это я тоже писал, проблема-то в другом: высокая загрузка проца...
     
    Последнее редактирование: 22 фев 2018
  6. Jin X

    Jin X Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    172
    Адрес:
    Кольца Сатурна
  7. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    1
    Регистрация:
    11 июн 2004
    Сообщения:
    2.997
    Адрес:
    Russia
    Jin X, вы почему-то к задаче подходите не с той стороны. В компах нет понятия плавно. Есть четкие рамки. У вас есть некоторая анимация\движение. Это значит идет рендеринг (расчет) каждого кадра. Пользователю, для комфортного просмотра, достаточно обновлять картинку со скоростью 30 кадров в секунду. То есть на 1 кадр у вас есть 0,034 сек - 34 миллисекунды. Это оочень далеко не одна миллисекунда. И за это время можно сделать очень многое.

    Теперь рассмотрим само рисование.

    Можно рисовать по таймеру, поставив его на срабатывание 30 кадров в секунду - будет присылаться допустим WM_PAINT и вы в нем обновляете кадр.
    Либо можно делать рисование в бесконечном цикле - тогда мы загрузим проц\видюху на максимум и будем рисовать намного больше кадров в секунду - в этом случае вам придется контролировать время обновления, чтоб анимация не пролетела слишком быстро (то о чем говорил вам Thetrik ). Ну и не забыть встроить обработку сообщение после апдейта кадра (проверив осталось ли время на обработку очереди).
     
    Jin X нравится это.
  8. Jin X

    Jin X Member

    Публикаций:
    0
    Регистрация:
    15 янв 2009
    Сообщения:
    172
    Адрес:
    Кольца Сатурна
    30 Гц недостаточно. Я сейчас попробовал сделать 50 Гц – видно дергание картинки дёргается, при том, что движение идёт по 1 пикселю. 66 Гц (задержка 15 мс) уже нормально.

    Можно поставить таймер на 10 мс, по идее (по крайней мере, мультимедийный... либо делать GetTickCount+Sleep(1)/NtDelayExecution(-1)+PeekMessage). Если уж очень хочется исключительной плавности, можно сделать 4 мс (типа некоторые мониторы имеют обновление кадра 4 мс).

    Вообще, задумка была в том, чтобы менять скорость движения (а её нужно менять) не за счёт увеличения дистанции (кол-ва прорисовок за 1 обновление рисунка), а за счёт изменения задержки, прорисовывая всё время одно и то же кол-во изменений.
    В целом согласен, что это неверный подход, ибо он грузит проц лишними промежуточными прорисовками, которых всё равно не видно...

    Всем спасибо за мысли.