Кто протормаживает: я или Винда?

Тема в разделе "WASM.WIN32", создана пользователем inew, 30 ноя 2004.

  1. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Помогите разобраться, кто может.

    Я написал прогу, которая должна 30 раз в сек.

    обновлять экран (через DirectX), отрисовывая анимацию.

    Время между двумя последовательными вызовами Главного тела - в среднем около 15 миллисекунд.

    Моя программная задержка доводит его до 33 млсек при отрисовки каждого кадра (чтобы fps был 30)

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

    Не могу вкурить, почему так происходит?

    Я использую стандартный каркас приложения, а главное тело вызываю после выполнения PeekMessage, TranslateMessage и DispathMessage перед зацикливанием вышеуказанных трех функций.

    Может кто-то знает, как решить проблему, подскажите, пожалуйста.

    P.S. Оконная процедура очень простая и ничего не делает, кроме как отслеживает нажатие ESC
     
  2. ProgramMan

    ProgramMan New Member

    Публикаций:
    0
    Регистрация:
    13 янв 2004
    Сообщения:
    263
    На чём прога? Ассемблер? Библиотеки DirectX стандартные?

    Много факторов...

    Выложи код, посмотрю...

    Может у тебя ещё какая-то прога периодически тратит ресурсы?
     
  3. n0p

    n0p 10010000b

    Публикаций:
    0
    Регистрация:
    7 май 2003
    Сообщения:
    256
    Адрес:
    Новосиbeerск
    inew

    Насколько я понял, "программная задержка" это нечто вроде void Sleep(time)? Я в свое время делал через таймер и было все нормально. Он, конечно, не совсем точен, но 30 ФПС выдаст на ура. А если твоим методом делать (если я правильно тебя понял), то ты привязан к железу и на более быстрой тачке это будет далеко не 30 ФПС.
     
  4. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    inew



    Ответ на вопрос узнать не сложно - нужно запустьть прогу на другом компе или под другой ОС :derisive:

    А вообще, покажи хоть цикл выборки сообщений.
     
  5. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Привожу исходник. Извините за плохую читабельность. Это не оригинал, а результат транслирования оригинала в ASM файл. (Оригинал написан в нестандартной оболочке)



    [​IMG] 1535401416__KUBLO.ASM
     
  6. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Забыл уточнить, что:

    run - это аналог invoke, но параметры перечисляются в порядке занесения их в стек!

    iffe, iffa, iffb и т.п. - это последовательность cmp ... je ... (соответственно ja, jb и т.д.)

    iffz eax,m10 - это последовательность or eax,eax; jz m10

    iffnz - то же, но jnz ...
     
  7. ProgramMan

    ProgramMan New Member

    Публикаций:
    0
    Регистрация:
    13 янв 2004
    Сообщения:
    263
    Извините за плохую читабельность.

    это мягко сказанно...

    Бинарник есть? может проше дизасемблером проитись?



    P.S.: лучьше подождать что скажут профи...
     
  8. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    IMHO цикл вполне нормальный, можно ещё попробовать TranslateMessage убрать.

    А лучше экзешник приаттач, может у других будет нормально работать, у меня была похожая проблема пока дрова не обновил. И скажи какая ОС у тя.





    ЗЫ

    Это даркбейсик какой-то что-ли ?
     
  9. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Бинарник обязательно скину, но только завтра, т.к. сегодня у меня его нет с собой



    S_T_A_S_

    Это облочка над АСМом (собственного производства), которая транслирует выражения в последовательность АСМ-команд, формирует на выходе АСМ-файл и передает его дальше компилятору. (Ничего особенного ,просто упрощает ввод последовательностей команд. Например, еах=евх+(+есх) транслируется в

    inc ecx

    mov eax,ebx

    add eax,ecx

    и т.п.)
     
  10. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Хм, интересная штука, и листинг вполне понятный, в отличае от того, что выдаёт на выходе.

    только лучше транслировать в:



    inc ecx

    lea eax,dword ptr[ebx+ecx]





    По поводу проги: Ты делаешь GetTickCount и ждёшь пока значение не будет такое, какое нужно. При этом наверняка задача забирает 100% процессорного времени, и возможно какая-то другая задача начинает тормозить в бэкграунде и временами забирает часть времени себе - из-за этого тормоза в твоей. Лучше использовать Sleep(), параметр = 1 или 2, в твоём случае можно и больше.

    Ещё, как правилино заметил n0p, лучше таймер использовать для синхронизации или привязаться к развёртке монитора. Твой метод никогда не выдаст постоянные 30fps - в некоторый промежуток времени это будет 29, а в следующий может быть 30 или 31. возможно именно "интерференцию" твоей частоты смены кадров и частоты развёртки ты и видишь раз в 100 кадров.
     
  11. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Скидываю экзешник. Кстати, как выяснил недавно, он не хочет работать на WinXP, хотя ни один вызов DirectX-функции с ошибкой не заканчивается. На Win98 работает нормально. Может, кто подскажет, в чем дело?



    [​IMG] 1403506928__KUBLO.EXE
     
  12. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    По-моему, нежелание работать в ХР связано с функцией Lock. Аналогичная программа, которая исползует Blt, а не прямой вывод в память, работает нормально в ХР. Кто знает, чем вызов Lock отличается в Винде 98 и ХР
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    На XP SP2 (DX9c) всё работает нормально, причём никаких тормозов я не заметил.



    Кстати, если рисовать не в видео-ОЗУ, а на внеэкранной поверхности в оперативе (DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY), а потом использовать BltFast, то должно быть быстрее.
     
  14. Sanya

    Sanya New Member

    Публикаций:
    0
    Регистрация:
    6 дек 2004
    Сообщения:
    4
    Адрес:
    Russia
    inew, ты конечно, неплохо зделал, даже зашибись, но откуда ты так уверен в том, что это программная задержка, а не аппаратная или системная?



    Железо у тебя не тормозит? Это удивительно, но если винт медленный или ещё какая-то другая хрень, то тормозить будет ужасно.



    Может быть и такое, что винда сохраняет файл подкачки на винт...



    Короче, ты крут, может ты меня уже и понял. Желаю удачи. Прога зверь...
     
  15. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Может быть и такое, что винда сохраняет файл подкачки на винт...



    Ух ты! А что, она может сохранять его куда-нибудь еще???
     
  16. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    S_T_A_S_

    Спасибо за подсказки и советы. Попробую проверить. Только твой ответ на счет ХР и Директ9 меня окончательно запутал. Я проверил прогу на еще пару машинах. Интересно, что на Винде 2000 с ДиректХ 9.0 она не рисует первый кадр, а после нажатия Пробела последующую анимацию отрисовывает нормально. С чем может быть связан этот (третий уже) вариант поведения проги ?
     
  17. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Вообще-то у меня так и работает, как на Windos 2000.

    Я думал так и должно быть, как я понял
    Код (Text):
    1.  
    2. G_main:
    3.     mov al,state
    4. iffe al,1,m140


    проверяет, нажат ли ранее space и начинает рисовать только после этого.

    (т.к. 1 заносится туда только после нажатия space)



    Хотя я мало что могу понять в том листинге 8-() лучше кинь для "нестандартной оболочки"

    Вообще, imho немного странный код - зачем QueryInterface и Release после DirectDrawCreate ?



    Да, вот ещё что: прога вылетает при потере фокуса (Alt+Tab, Ctrl+Alt+Del), т.к. нет проверки Draw::TestCooperativeLevel и DrawSurface::IsLost
     
  18. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Нашел, где собака порылась!

    В винде ХР программа не выводит первый кадр, потому что я использую прямой вывод на первичную поверхность.

    Как только я изменил этот фрагмент, заставив рисовать начальный кадр в бэкбуфере с последующем флиппингом, все работает нормально и в Вин98 и в ВинХР.

    Наверное, я что-то не до конца предусмотрел на счет прямого вывода на первичную поверхность, хотя точно не знаю, что именно. Буду теперь использовать вывод в бэк и последующий флиппинг.



    S_T_A_S_

    Код странноватый, согласен. Просто я делаю пока только каркас, а начинку время от времени вставляю разную (в качестве тестов)



    По твоей просьбе скидываю исправленный DOC-вариант исходника для "нестандартной оболочки".

    # - это XOR

    | - это OR

    стрелка вверх - PUSH

    стрелка вниз - POP





    [​IMG] _517409338__KUBLO.doc
     
  19. inew

    inew New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2004
    Сообщения:
    26
    Одна проблема решена (побочная), но главная осталась. Не могу вкурить, как лучше всего организовать временную задержку при помощи WinAPI.

    Под "лучше всего" имеется в виду:

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

    2) чтобы заставить Винду вернуть управление нашему коду через нужное время (с достаточной степенью точности).

    Может у кого-то есть мысли по этому поводу.
     
  20. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    1) Поставь Sleep() в цикл выборки сообщений:
    Код (Text):
    1.  
    2.     while(true)
    3.         if( PeekMessageA(&msg,NULL,0,0,PM_REMOVE) )
    4.         {
    5.             if( msg.message == WM_QUIT )
    6.                 return(msg.wParam);
    7.  
    8.             DispatchMessageA(&msg);
    9.         }
    10.         else
    11.         {
    12.             if( active )
    13.                 draw();
    14.             Sleep(2);
    15.         }


    2) Здесь сложно, однозначного решения IMHO нет. Для твоего случая я бы делал так:

    - Lock (DDLOCK_DONOTWAIT)

    - рисуем во внеэкранном буфере (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY - это должно быть быстрее, т.к. доступ CPU к видеопамяти медленный)

    - Unlock

    - WaitForVerticalBlank (DDWAITVB_BLOCKBEGIN)

    - BltFast (offsecreen buffer -> primary). Вариант - копируем в бэкбуфер, а потом Flip, но по скорость выгрыша скорее всего не будет.

    Периодичность вертикальной развёртки постоянна!



    Теперь новая проблема: поскольку синхронизация идёт по VSync, скорость движения объектов на экране будет зависеть от неё. В общем случае расхождение раза в 2 может быть (60..120Гц).

    Решается это введением коэфициента скорости для всех объектов, т.е. для 60Гц он будет, например, 2, а для 120 - 1. Для развёртки 90Гц получится коэфициент 1.5 и т.п. Придётся пользоваться нецелой арифметикой, FPU в этом случае не к чему, подойдёт фиксированная точка.

    Сложно? А что делать :-(