Помогите разобраться, кто может. Я написал прогу, которая должна 30 раз в сек. обновлять экран (через DirectX), отрисовывая анимацию. Время между двумя последовательными вызовами Главного тела - в среднем около 15 миллисекунд. Моя программная задержка доводит его до 33 млсек при отрисовки каждого кадра (чтобы fps был 30) Проблема в том, что 1 раз на несколько сотен кадров (а иногда и пару тысяч) почему-то пауза между циклами почему-то становится очень большой (порядка 90 млсек.), а это аж 3 кадра. В результате время от времени на экране наблюдается небольшая одновременная остановка ВСЕХ движущихся объектов, что сильно подпорчивает картину их плавного движения (а они должны двигаться с постоянной скоростью). Не могу вкурить, почему так происходит? Я использую стандартный каркас приложения, а главное тело вызываю после выполнения PeekMessage, TranslateMessage и DispathMessage перед зацикливанием вышеуказанных трех функций. Может кто-то знает, как решить проблему, подскажите, пожалуйста. P.S. Оконная процедура очень простая и ничего не делает, кроме как отслеживает нажатие ESC
На чём прога? Ассемблер? Библиотеки DirectX стандартные? Много факторов... Выложи код, посмотрю... Может у тебя ещё какая-то прога периодически тратит ресурсы?
inew Насколько я понял, "программная задержка" это нечто вроде void Sleep(time)? Я в свое время делал через таймер и было все нормально. Он, конечно, не совсем точен, но 30 ФПС выдаст на ура. А если твоим методом делать (если я правильно тебя понял), то ты привязан к железу и на более быстрой тачке это будет далеко не 30 ФПС.
inew Ответ на вопрос узнать не сложно - нужно запустьть прогу на другом компе или под другой ОС А вообще, покажи хоть цикл выборки сообщений.
Привожу исходник. Извините за плохую читабельность. Это не оригинал, а результат транслирования оригинала в ASM файл. (Оригинал написан в нестандартной оболочке) 1535401416__KUBLO.ASM
Забыл уточнить, что: run - это аналог invoke, но параметры перечисляются в порядке занесения их в стек! iffe, iffa, iffb и т.п. - это последовательность cmp ... je ... (соответственно ja, jb и т.д.) iffz eax,m10 - это последовательность or eax,eax; jz m10 iffnz - то же, но jnz ...
Извините за плохую читабельность. это мягко сказанно... Бинарник есть? может проше дизасемблером проитись? P.S.: лучьше подождать что скажут профи...
IMHO цикл вполне нормальный, можно ещё попробовать TranslateMessage убрать. А лучше экзешник приаттач, может у других будет нормально работать, у меня была похожая проблема пока дрова не обновил. И скажи какая ОС у тя. ЗЫ Это даркбейсик какой-то что-ли ?
Бинарник обязательно скину, но только завтра, т.к. сегодня у меня его нет с собой S_T_A_S_ Это облочка над АСМом (собственного производства), которая транслирует выражения в последовательность АСМ-команд, формирует на выходе АСМ-файл и передает его дальше компилятору. (Ничего особенного ,просто упрощает ввод последовательностей команд. Например, еах=евх+(+есх) транслируется в inc ecx mov eax,ebx add eax,ecx и т.п.)
Хм, интересная штука, и листинг вполне понятный, в отличае от того, что выдаёт на выходе. только лучше транслировать в: inc ecx lea eax,dword ptr[ebx+ecx] По поводу проги: Ты делаешь GetTickCount и ждёшь пока значение не будет такое, какое нужно. При этом наверняка задача забирает 100% процессорного времени, и возможно какая-то другая задача начинает тормозить в бэкграунде и временами забирает часть времени себе - из-за этого тормоза в твоей. Лучше использовать Sleep(), параметр = 1 или 2, в твоём случае можно и больше. Ещё, как правилино заметил n0p, лучше таймер использовать для синхронизации или привязаться к развёртке монитора. Твой метод никогда не выдаст постоянные 30fps - в некоторый промежуток времени это будет 29, а в следующий может быть 30 или 31. возможно именно "интерференцию" твоей частоты смены кадров и частоты развёртки ты и видишь раз в 100 кадров.
Скидываю экзешник. Кстати, как выяснил недавно, он не хочет работать на WinXP, хотя ни один вызов DirectX-функции с ошибкой не заканчивается. На Win98 работает нормально. Может, кто подскажет, в чем дело? 1403506928__KUBLO.EXE
По-моему, нежелание работать в ХР связано с функцией Lock. Аналогичная программа, которая исползует Blt, а не прямой вывод в память, работает нормально в ХР. Кто знает, чем вызов Lock отличается в Винде 98 и ХР
На XP SP2 (DX9c) всё работает нормально, причём никаких тормозов я не заметил. Кстати, если рисовать не в видео-ОЗУ, а на внеэкранной поверхности в оперативе (DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY), а потом использовать BltFast, то должно быть быстрее.
inew, ты конечно, неплохо зделал, даже зашибись, но откуда ты так уверен в том, что это программная задержка, а не аппаратная или системная? Железо у тебя не тормозит? Это удивительно, но если винт медленный или ещё какая-то другая хрень, то тормозить будет ужасно. Может быть и такое, что винда сохраняет файл подкачки на винт... Короче, ты крут, может ты меня уже и понял. Желаю удачи. Прога зверь...
Может быть и такое, что винда сохраняет файл подкачки на винт... Ух ты! А что, она может сохранять его куда-нибудь еще???
S_T_A_S_ Спасибо за подсказки и советы. Попробую проверить. Только твой ответ на счет ХР и Директ9 меня окончательно запутал. Я проверил прогу на еще пару машинах. Интересно, что на Винде 2000 с ДиректХ 9.0 она не рисует первый кадр, а после нажатия Пробела последующую анимацию отрисовывает нормально. С чем может быть связан этот (третий уже) вариант поведения проги ?
Вообще-то у меня так и работает, как на Windos 2000. Я думал так и должно быть, как я понял Код (Text): G_main: mov al,state iffe al,1,m140 проверяет, нажат ли ранее space и начинает рисовать только после этого. (т.к. 1 заносится туда только после нажатия space) Хотя я мало что могу понять в том листинге 8-() лучше кинь для "нестандартной оболочки" Вообще, imho немного странный код - зачем QueryInterface и Release после DirectDrawCreate ? Да, вот ещё что: прога вылетает при потере фокуса (Alt+Tab, Ctrl+Alt+Del), т.к. нет проверки Draw::TestCooperativeLevel и DrawSurface::IsLost
Нашел, где собака порылась! В винде ХР программа не выводит первый кадр, потому что я использую прямой вывод на первичную поверхность. Как только я изменил этот фрагмент, заставив рисовать начальный кадр в бэкбуфере с последующем флиппингом, все работает нормально и в Вин98 и в ВинХР. Наверное, я что-то не до конца предусмотрел на счет прямого вывода на первичную поверхность, хотя точно не знаю, что именно. Буду теперь использовать вывод в бэк и последующий флиппинг. S_T_A_S_ Код странноватый, согласен. Просто я делаю пока только каркас, а начинку время от времени вставляю разную (в качестве тестов) По твоей просьбе скидываю исправленный DOC-вариант исходника для "нестандартной оболочки". # - это XOR | - это OR стрелка вверх - PUSH стрелка вниз - POP _517409338__KUBLO.doc
Одна проблема решена (побочная), но главная осталась. Не могу вкурить, как лучше всего организовать временную задержку при помощи WinAPI. Под "лучше всего" имеется в виду: 1) чтобы было корректным взаимодействие с Виндой, т.е. чтобы прога возвращала управление системе, пока сама ничего не делает - на время задержки (и Винда успевала порешать все свои внутренние вопросы, не тормозя в дальнейшем); 2) чтобы заставить Винду вернуть управление нашему коду через нужное время (с достаточной степенью точности). Может у кого-то есть мысли по этому поводу.
1) Поставь Sleep() в цикл выборки сообщений: Код (Text): while(true) if( PeekMessageA(&msg,NULL,0,0,PM_REMOVE) ) { if( msg.message == WM_QUIT ) return(msg.wParam); DispatchMessageA(&msg); } else { if( active ) draw(); Sleep(2); } 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 в этом случае не к чему, подойдёт фиксированная точка. Сложно? А что делать :-(