При выводе движущегося рисунка - изображение иногда дёргается

Тема в разделе "WASM.GUI", создана пользователем TimaFt, 25 авг 2005.

  1. TimaFt

    TimaFt New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2005
    Сообщения:
    13
    S_T_A_S_



    > ...если делать какую-то полезную работу, что бы лучик успел уйти за кадр.

    та работы хватить - скоро нужно будет успевать всё сделать до следующего обратного хода... :)



    Огромное спасибо!
     
  2. S_T_A_S_

    S_T_A_S_ New Member

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

    когда GetScanLine(&scanline) возвращает DDERR_VERTICALBLANKINPROGRESS

    то scanline как правило равно 0xffffffff, т.е. моя проверка проходит.

    Но _изредка_ почему-то scanline == 0.

    Так что дейчтвительно, лучше на всякий случай проверять это, можно избежать пропуска кадров.



    Судя по DX7 SDK, 0 не может вернуться когда vblank in progress:



    А в новом MSDN и DX9 SDK эту цитату вырезали =)
     
  3. TimaFt

    TimaFt New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2005
    Сообщения:
    13
    S_T_A_S_

    Та я как-то всё таки оставил проверочку на DDERR_VERTICALBLANKINPROGRESS на всякий случай...



    А в 9-ом я смотрю они вообще убрали WaitForVerticalBlank.

    Я так понял нормально реализвать такую функцию они не смогли и решили от неё избавится вообще.
     
  4. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    WaitForVerticalBlank в конечном счёте сводится к callback'у DdWaitForVerticalBlank, который должен (но не обязан) быть реализован в драйвере видоекарты, так что в DX9 WaitForVerticalBlank отсутствует по какой-то другой причине. Но никто не мешаетс использовать старые версии интерфейса, где WaitForVerticalBlank есть. Спасибо MS за технологию COM =)
     
  5. MrMadguy

    MrMadguy New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2006
    Сообщения:
    19
    Адрес:
    Russia
    У меня такая-же хрень была с OpenGL. Я в обработчике таймера каждые 10мс обновлял координаты и изображение подергивалось. И дергалось оно тем сильнее, чем загруженнее система. Прикол в том, что это присходило при 60fps, т.е. что-то нитак с этим методом. Прикол в том, что таймер работает нестабильно, т.е. задержка плавает.

    Нужно писать так:



    Period:=GetTimerTick-LastTime;Сколько прошло мс;

    Delta:=Phi*Period;РасстояниеЖ=Скорость*Время;

    Inc(Object.X,Delta);X:=X+Delta;



    И дергаться не будет
     
  6. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Если авторы темы еще не ушли с этого форума, то у меня несколько вопросов:

    1. Насколько я понял, DirectX используется только для синхронизации? То есть к рисованию непосредственно он никакого отношения не имеет и все рисуется лишь с помощью GDI?

    2. Что проверяется здесь: fps < (refresh_rate ? refresh_rate : 60) - 5

    3. Что это за знак ]" в Sleep и что означает "800"? :
    Sleep( max_visible_scanlines - scanline > max_visible_scanlines * refresh_rate / 800 );

    Вот этот кусок тоже не понятен. Он идет в коде нити синхронизации?

    unsigned tsc = rdtsc();
    unsigned tics = tsc - previous_tsc;
    previous_tsc = tsc;
    if( tics ) fps = cpu_frequency / tics;

    Благодарю, если кто что-нибудь подскажет.
     
  7. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    К сожалению, или к счастью, при смене движка я чудесным образом вышел из бани :))

    Да, DirectX только для синхронизации. Рисовать можно через что угодно.

    Это попытка определить, был ли пропуск кадра или нет. fps - мгновенное значение частоты для предыдущего кадра (см. далее).

    Оператор > даёт в результате 0 либо 1 (аргумент для Sleep).
    Смысл - отдать такты CPU другим тредам (если это не делать - планировщик заберёт его сам, когда ему вздумается).

    Если текущая строка развёртки меньше некоторого предельного значения, то можно усыпить тред. Значение это получается по эмпирической формуле:
    (max_visible_scanlines * refresh_rate / 800).
    Поскольку для разных частот и разрешений количество "безопасных для Sleep" строк развёртки в конце кадра различно. Правильнее, конечно, использовать не 800, а некоторое вычисляемое в runtime число...

    Да в общем-то весь тот код так сплошным куском и идёт (за исключением объявлений функции и переменных).

    В этом месте вычисляется мгновенное значение fps - частота процессора делится на количество потраченных за кадр тактов CPU.
     
  8. WishMaster

    WishMaster New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    54
    Адрес:
    Ukraine
    Благодарю за ответ!
    Если я все правильно понимаю, то обновление окна следует после цикла перед пересчетом мгновенного значения fps? Вообще, этот весь этот код у тебя выполняется в отдельном от общего приложения потоке? Каков его приоритет?
    Непонятно также, зачем в случае, если мгновенная частота меньше частоты обновления экрана минус 5 вызывать WaitForVerticalBlank - разве в этом случае нельзя так же само обойтись функцией GetScanLines?
    Относительно Sleep'а - спасибо, я понял. Решение довольно элегантное. Вместо (max_visible_scanlines * refresh_rate / 800), как мне кажется, можно использовать среднее число строк, которое луч проходить за время Sleep(1), которое можно получить непосредственным измерением в ходе выполнения программы.

    Но у меня еще такая проблема возникает. Если форма развернута на весь экран и мне необходимо обновлять всю канву формы (например, по ней график бежит), то если я перед обновлением сначала жду, пока луч добежит до конца экрана и только тогда начинаю копировать из Bitmap на канву формы с помощью функции BitBlt, то я попросту не успеваю - луч уже скользит по верхним строкам экрана, а у меня еще не закончилось обновление канвы, в результате чего первые строчек 50 (по крайней мере это у меня, у других может быть больше или меньше) экрана оказываются еще старыми. То есть имеет место эффект расхождения. И это при том, что разрешение экрана то у меня всего-на-всего 800х600. Если я ставлю больше, то ситуация становится еще хуже.
    Отсюда и возникает вопрос - как успеть обновить в памяти весь экран за время обратного хода луча? Или может есть какое-нибудь другое решение этой проблемы?
    ПС. Еще раз отмечу, что речь идет об изображении на форме, а не о полноэкранном режиме. Переключение страниц с помощью DirectX в этом случае не работает.
     
  9. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    В моём коде обновление окна следует за расчётом fps, но это не принципиально, т.к. все эти операции выполняются в цикле.

    Да, поток отдельный - что бы не мешали оконные сообщения.
    Приоритет у этого треда THREAD_PRIORITY_HIGHEST (тред с выборкой оконных сообщений - THREAD_PRIORITY_ABOVE_NORMAL, еще есть тред с музыкой - THREAD_PRIORITY_TIME_CRITICAL)
    Какую-то старую версию сорцов можно найти здесь (только линки побиты, надо к "http://www.wasm.ru/forum/" добавлять "files/_239914352__cr.part1.rar"). Только там синхронизация еще старой версии, и timeBeginPeriod(1) не вызывается (а надо обязательно, поэтому не везде правильно работает).

    Дык WaitForVerticalBlank вызывается, если GetScanLines возвращает DDERR_UNSUPPORTED.

    Тоже думал об этом, но оставил на потом :)

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

    Я пришел к выводу, что переключение страниц совершенно бессмысленная операция (и ведь когда-то мне это говорили на win32asmcommunity). Все равно нужно делать блиттинг из системной памяти в экранную - так что можно сразу на primary... В сорце по ссылке так и сделано - хоть в окне, хоть в полном экране.
     
  10. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Кстати, какой монитор? На LCD подключенных по DVI входу могут быть артефакты - это косяк сомого монитора.
     
  11. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    2 S_T_A_S_:
    Ага, есть такое дело в minifmod и tunefish. Какая-то странная для меня тенденция наблюдается - для аудио приоритет выше, чем для графики. И такое даже в ресурсоёмких демках видно. Не вижу смысла. Лучше заюзать буфер побольше для музыки и спокойно назначить ей минимальный приоритет. Короче, не согласен ;)

    Нет под рукой экзешничка чтобы проверить? У меня как раз LCD на DVI.
     
  12. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    у всех LCD на DVI :)
    Вот только не пойму каким боком в артефактах может быть виноват DVI,
    скорее это зависит от свойства(типа) ЖК матрицы и используемых в ней технологий
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Дык ты тока музыку воспроизводишь, вот и смысла нет :)

    На самом деле, причина кроется глубже. Тред с выборкой сообщений должен иметь повышенный приоритет - тогда при перекрытии окна другими, анимация не будет очень сильно тормозить. Рисующий тред должен иметь еще более высокий приоритет, что бы обработка сообщений не мешала анимации при перетаскивании окна. А тред синтеза музыки - еще выше, чем у предыдущих, что бы они не мешали.

    Большой буфер имеет свои проблемы - например, латентность.

    На самом деле, даже тред с высоким приоритетом не решает полностью проблему прерывания звука, а лишь делает её менее вероятной.

    Direct Sound, кстати, для своих тредов ставит максимальные приоритет - они-то могут и воспроизводить содержимое твоего буфера :)

    Зависит, подстраивается ли внутренний генератор к VSync или нет.
     
  14. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Есть ещё LCD на RGB и вообще CRT без всяких DVI. И ещё S-video может быть.

    Я же про демки говорю, а не про себя. Допустим, решил разработчик написать мега-крутую игру типа Doom III. На всё и про всё насоздавал пол сотни тредов, но наивысший приоритет назначил еле-слышной (если вообще колонки включены) фоновой музыке. А графика и физика тем временем тормозят, т.к. остаётся им около 50% процессорного времени или меньше. Где же логика?

    Как раз против этого я и выступаю.

    Во-первых, большой для аудио - не такой уж большой по сравнению с видео, т.к. всё-таки одномерный. Ну, выделим для каждого канала по мегабайту памяти, чтоб музон не глючил даже если в течении пары секунд тред синтеза не получит контроль. Во-вторых, ощутимой латентности не будет, если размер кратен "гранулярности" буферов DirectSound и выравнивание начала буфера учтено. Причём PCM лучше всего сразу выводить на частоте 48К, чтобы кодеку не приходилось дополнительно задействовать SSRC. Таким образом, связь со звуковухой должна проходить почти так гладко, как в случае с CD, практически не загружая CPU, и все задержки будут только в синтезе.

    Во-во!

    Естественно. Иначе и быть не может.
     
  15. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Во-первых, не надо утрировать. Обработка звука при всём желании не займёт так много времени, это будет 2-5%.

    Во-вторых, артефакты в графике не так заметны, как артефакты в звуке. Пропущенный кадр скорее всего не будет замечен, а вот (любые!) паузы в звуке ухо сразу услышит.

    Такой размер совершенно не пригоден где-либо, за исключением демок:
    1048576 / 2 / 48000 = 11.7 секунд
    Представим игру, где на каждую локацию своя музыка. Переходим в другую локацию, и ждём 12 секунд почти, пока музон поменяется ;) Что бы это избежать, придётся делать хитрую логику, в результате от мегабайтного буфера будет использоваться процентов 5 и загрузка треда-синтезатора будет сильно неравномерная (а стало быть - хуже для других тредов)..

    Я про латентность в собственном рендере звука говорю, про остальное ещё рановато :)

    Интересная идея, спасибо! Только надо учесть, что не всё поддерживает 48KHz. :dntknw:

    Ну дык и не решить её никогда на системе нереального времени (виндос). Так хоть под ковер надо побольше успеть замести :))

    И тут приходим мы со своим низким приоритетом и убиваем все потуги ребят из МС на корню :)
     
  16. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Если задать TIME_CRITICAL, то этот тред будет постоянно отбирать время у других тредов в данном процессе и тутже засыпать. Положительно на соседях это никак сказаться не может. Почему 2-5%? Тут процент зависит от количества тредов в процессе, т.е. 50% более правдоподобно. Тотже tunefish в холостую (консоль) почти не загружает CPU, но стоит добавить GUI, как загрузка подскакивает до ~10%. Понижаем приоритет треда - загрузка снова в норме. В отладчике потом видно, что кроме основного потока в GUI есть ещё по крайней мере 4 системных. Так что, чем больше потоков, тем выше загрузка от TIME_CRITICAL. Такая же фигня наблюдается на WinCE/ARM с использованием популярной либы FMOD, т.е. тестовые проги почти не влияют на CPU usage, а в реальном приложении начинаются дикие тормоза. По крайней мере, такой багрепорт недавно появился у них на офф. форуме от разработчиков какой-то игры.

    Код (Text):
    1. IDirectSoundBuffer->Stop()
    2. IDirectSoundBuffer->SetCurrentPosition()
    Вот, собственно, и вся хитрая логика. Хотя вместо мгновенного Stop() лучше сделать плавный fade-out, чтобы не возникало артефактов, но это не имеет отношения к проблеме с приоритетом треда.

    Это в худшем случае и с этом можно жить, IMHO.

    Ну, теоретически, всё поддерживает AC97, а, стало быть, и 48K. У меня на SB Live 48K звучит качественне, чем 44.1, а на старом Creative - наоборот. Замер времени (по RDTSC) в первом тесте тоже выявил преимущество 48К на "хорошей" карточке, а во втором 48К оказалось медленнее. Видимо, стандарт воспринимается производителями железа и кодеков как-то субьективно.

    Нет, использование большого буфера даёт возможность вполне точно определить с какой минимальной частотой система должна вызывать тред с синтезатором. Реже 1 Гц, думаю, трудно представить ситуацию, но можно дать ещё запас.
     
  17. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Процессы отношения к планировщику не имеют, трэд будет отбирать врямя у _всех_. Про соседей - это другие приложения? Да и дзен с ними, когда играешь в игрушку, лучше бы их вообще не было.

    Потому что я сам тестировал, и получил такие цифры. Про 5% написал с более чем двухкратным запасом.

    Всё же, не вижу связи с приоритетом. Ну реализовали что-то криво, всего делов-то :). Тот же медиаплеер жрёт проц, когда его окно закрыто другими, а вполне мог бы так не далать.

    Не всё так просто, нужно ещё заново пересчитать 2 мега звука (просчитанных впустую) - вот и причина пожирания CPU.

    Фактически, получается обмен одного ресурса (приоритет), на другой. Планировщику в общем-то совершенно всё равно, какие там приоритеты у тредов, он просто чаще пропускает с более высоким. Т.е. мне не понятно, что мы теряем, подняв приоритет. А вот память - вполне ощутимый ресурс (хотя 2 мега сейчас и копейки) - попадёт этот буфер в своп, получим тормоза.

    Дык зависит, как поддердивает. У Live 48К - родной формат, остальное ресэмплится в него, а у старых карт (может быть?) родной 44.1.

    Спасибо, ещё одна классная идея! Ведь так можно определить, какой формат "родной".

    А смысл определять частоту? Синтезатор может запросто ждать на событиях (IDirectSoundNotify). Это более точно, чем таймеры.
     
  18. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    В первую очередь, у своих, т.е. у других тредов в своём процессе. На тредах в других процессах это будет сказываться в меньшей степени.

    Так понятно, что в коммерческом приложении, типа хитовой игры, не должна подскакивать загрузка. Пару часов поиграет юзер - ребут :) Тот же WOW юзает FMOD и загрузка в пределах 10%, как того требует негласный стандарт. Приоритет у треда с музыкой обычный. TIME_CRITICAL с такими параметрами никак не согласуется, IMHO.

    Ну, прогресс загрузки локации увеличится на пол секунды - не страшно. Кстати, когда загружается локация, CPU usage неизбежно подскакивает - на разных играх замечал.

    Я с кодеками ещё не разбирался. Возможно, есть более прямые методы определения родных форматов. На некоторых картах есть по 2 кристалла - так что "родных" частот может оказаться 2 и более.

    Интерфейс уведомлений появился, кажется, в 7м DX, так? Это минус. Далее, всё-равно нужно ждать через WaitForSingleObject по событию (event). Так что опять возникает проблема с приоритетом треда, который ждёт.
     
  19. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Это не так:
    В общем понятно, сначала одно разбазаривание ресурсов, потом другое... =)
    А если музыка должна меняться в любой момент времени?

    Не будем копировать чужие ошибки когда это возможно.

    А DX7 появился в 98SE. Мне кажется, в 2006м году думать про более ранние системы -немного странно :)

    Какая именно проблема? Нотификатор просигналит эвент - это приведёт к вызову шедьюлера и переключению на контекст ждущего треда.
     
  20. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    2 S_T_A_S:
    Читал я это, только забыл где. Спасибо, что напомнил. На практике это почему-то не подтверждается, а экспериментировал я и на 2к и на XP. Время между процессами не делится поровну - согласен, но между тредами разных процессов оно тоже поровну не делится. Хотя, может быть, планировщик динамически меняет приоритет классов... Таким образом, треды с одинаковым бызовым приоритетом в разных процессах на самом деле имеют различные приоритеты... В общем, надо будет повторить эксперимент, а то врядли Руссинович ошибается.

    Если нужно реализовать что-то вроде SFX, т.е. коротких (так сказать, реактивных) звуковых эффектов (выстрел, взрыв, стук и т.д.), эти эффекты прекрасно умещаются в один буфер, т.е. тред для их синтеза вообще не нужен. Раньше в играх использовался тред для смешивания разных звуковых каналов, но т.к. это теперь умеет делать DX, тред для SFX больше не нужен.

    Хочешь сказать, что он сразу переключится на тред, который вызвал WaitForSingleObject, минуя цепочку остальных тредов?