Конференция "Игры" » как выловить начало кадровой развертки. [D7, WinXP]
 
  • ol'ka (20.06.08 03:33) [0]
    как известно для рендерингав 3D-играх часто используется привязка начала рисования картинки к моменту импульса запуска кадровой развертки, чтобы получить картинку без наложения кадров. Существует ли компонент для обработки события типа onScreenRefresh? подобный TTimer например, который к сожалению не позволяет решить проблему.
  • DimaBr © (20.06.08 08:36) [1]
    Скорее всего существует, НО

    Внимание! Здесь обсуждаются вопросы, связанные с разработкой компонентов, редакторов свойств, редакторов компонентов и экспертов IDE.
    Вопросы по поиску и использованию готовых компонентов, редакторов или экспертов являются нарушением тематики и могут быть удалены.
  • ol'ka (20.06.08 11:08) [2]
    как раз в данном случае не снимается вопрос "разработки" ,  такого компонента или хотябы просто процедуры перехвата соответствующего прерывания от видеокарты, думаю текст займет меньше места чем это обсуждение, надеюсь найдутся профи, которым не составит труда помочь.
  • МистерТ (20.06.08 11:51) [3]
    ИМХО - не существует.

    А вообще - опиши задачу, может её можно решить другим методом ?
  • ol'ka (20.06.08 12:13) [4]
    все примитивно просто, рисую на канвасе изменяющуюся со временем картинку. Событие  onTimerEvent запускает просчет новой сцены и он же, пока, отрисовывает полученное на канвасе методом Canvas.Repaint, так вот интервал таймера 50мс в идеале равный 3м целым кадрам (60Гц) оказывается на практике не совсем точно равен, и как следствие проявляется мерцание. Понятно что .Repaint нужно привязать к началу растра чтобы убрать нежелательный эффект, вопрос - как? Тема должна быть хорошо изучена в определенных кругах так как во многих играх когда FPS приближается к Refresh Rate данный эффект проявляется в значительной степени и существует галочка в настройках включающая привязку рендеринга к началу кадра как способ борьбы с этим злом.
  • @!!ex © (20.06.08 13:07) [5]
    Мерцание никакого отношения к кадровой развертке не имеет.
    DoubleBuffer в помощь.
  • ol'ka (20.06.08 13:41) [6]

    > Мерцание никакого отношения к кадровой развертке не имеет.

    Формально вы правы, отношение как раз имеет строчная развертка, только началу рисаования 1-й строки предшествует кадровый синхроимпульс, а дальше 2-я, 3-я и т.д. строки до следующего кадра. К примеру, монитор успел отобразить 300 строк в текущем кадре, а вы рисуете начиная с 200-й, тогда все что вы нарисуете там где луч уже побывал не будет отображено до следующего кадра, а если FPS превышает кадровую частоту, то не будет отображено вообще. Зрительно это и проявляется в виде мерцаний, наложения кадров и бесит конкретно. А вот если выловить кадровый импульс и расчитать вывод на экран начиная  оттуда, где луч еще не бегал эффекта удастся избежать, нужно только прерывание от видеокарты сигнализирующее о начале кадра получить в виде события и обработать его процедурой. С процедурой справлюсь, а вот как событие выхватить - пока ступор


    > DoubleBuffer в помощь.

    ... чета не помогает, не нахожу я <property DoubleBuffered: Boolean;> у канваса ... уж потрудитесь разжевать если гдето ошибаюсь
  • ol'ka (20.06.08 13:51) [7]
    в конце концов событие onTimerEvent по сути есть тоже самое - прерывание от системного таймера!
  • Sapersky (20.06.08 14:05) [8]
    не нахожу я <property DoubleBuffered: Boolean;> у канваса

    У формы, панели есть. Или можно вручную создать битмап, рисовать в него, потом копировать битмап на экран.
    Синхронизировать обновление экрана с развёркой в принципе можно (через DirectX/OpenGL), но это, как правило, требуется в случае очень уж активной анимации, в играх, например. В большинстве приложений достаточно  буферизации.
  • @!!ex © (20.06.08 14:06) [9]
    > [6] ol'ka   (20.06.08 13:41)

    Поверьте. Вертикальная синхронизация ничего не даст.
    Возьмите любую игру. Принудительно отключите вертикальную синхронизацию... И вы не увидите мерцания. Хотя кадры и будут не синхронизированы.

    DoubleBuffer - это двойная буфферизация. Когда весь выводит идет в память, а потом одной командой(BitBlt, например) выводится в видеопамять.

    Если речь о канвасе и дельфи, то проще всего делать вывод на TBitMap, а потом через BitBlt выводить на DC формы.
  • ol'ka (20.06.08 14:43) [10]
    кхе кхе, а у формы канвас тоже есть? тоесть у меня получится сделать

    ...
    MyForm.DoubleBuffered: = True
    ...

    а потом

    ...
    with MyForm.Canvas do ......... end;
    и все у меня получится?

    а то зачем-то мною на форму TPaintBox был прикручен ради канваса...
  • @!!ex © (20.06.08 15:20) [11]
    > [10] ol'ka   (20.06.08 14:43)

    У формы тоже канвас есть.
    Лично я за 10 лет проганья на дельфе, не использовал ни разу PaintBox. ПРи том, что очень часто и много рисую на форме.
  • @!!ex © (20.06.08 15:22) [12]
    > [10] ol'ka   (20.06.08 14:43)

    Создай TbitMap. При изменении размера окна, меняй и размез битмапа. ВЕСЬ вывод делай в этот битмап. У него есть канвас. :)
    А в конце командой BitBlt копируй битмап на форму.
    BitBlt(Form.Canvas.Handle,0,0,Form.ClientWidth, Form.ClientHeight,BitMap.Canvas.Handle,0,0, SRCCOPY);
  • Sapersky (20.06.08 15:40) [13]
    Возьмите любую игру. Принудительно отключите вертикальную синхронизацию... И вы не увидите мерцания.

    Там не мерцание, а т.н. расхождение (tearing) может быть, сдвиг картинки горизонтальными полосками. У меня на этом примере на вертикальных сторонах квадратов хорошо видно:
    http://sapersky.narod.ru/files/VSync_test.rar
    (синхронизация переключается нажатием 'S').
    Конечно, это экстремальный случай, в реальных играх расхождение сложнее разглядеть.
  • @!!ex © (20.06.08 15:54) [14]
    > [13] Sapersky   (20.06.08 15:40)

    Сдвиг картинки бывает, я не спорю. Но оно мало похоже на мерцание. :)
  • ol'ka (20.06.08 15:59) [15]

    > Создай TbitMap. При изменении размера окна, меняй и размез
    > битмапа. ВЕСЬ вывод делай в этот битмап. У него есть канвас.
    >  :)
    > А в конце командой BitBlt копируй битмап на форму.
    > BitBlt(Form.Canvas.Handle,0,0,Form.ClientWidth, Form.ClientHeight,
    > BitMap.Canvas.Handle,0,0, SRCCOPY);

    методика понятна и вполне приемлема, спасибо за идею!
    Идея использовать битмап натолкнула меня на мысль оптимизировать рендеринг.
      Дело в том что TPaintBox имеел удобный для меня метод .repaint, для формы не подойдет потому как на ней кроме пэйнтбокса еще куча всяких панелек с кнопочками прикручено и перерисовывать их repaint - ом крайне криво будет. Кроме того выводимое изображение содержит статические элементы перерисовывать которые тоже бессмысленно (хотя repaint успевал перерисовывать и проблем не создавал)
     Раз уж пользоваться битмапом то рационально отделить статику от динамики и создать 2 битмапа 1-й один раз, а 2-й рендерить с заданным интервалом, потом их объединить и cгрузить на канвас формы.
     Вопрос. Как битмапы склеить чтобы второй на первый накладывался как Transparent ?
  • @!!ex © (20.06.08 16:14) [16]
    > [15] ol'ka   (20.06.08 15:59)

    TransparentBlt
    В качестве одного из параметров идет цвет, который должен быть прозрачным.
    Blendinga(насколько мне известно) у канваса можно только вручную добиться.
  • ol'ka (20.06.08 16:17) [17]

    > Сдвиг картинки бывает, я не спорю. Но оно мало похоже на
    > мерцание. :)

    по сути да, эффект мерцания в моем случае проявляется  т.к. repaint трет канвас и по новой все рисует а пока он это делает монитор ту тьму показует а картинка только в следующем кадре уже видна вот и мерцает усе! ;)
  • @!!ex © (20.06.08 16:22) [18]
    > [17] ol'ka   (20.06.08 16:17)

    Кстати, BitMap не обязательно должен быть размером с форму.
    Ничего не мешает, например, сделать БитМап размером 100х100 и рисовать его в координатах 500, 600 на форме:
    BitBlt(Form.Canvas.Handle,500,600,100,100,BitMap.Canvas.Handle,0,0, SRCCOPY);
  • @!!ex © (20.06.08 16:22) [19]
    Внимательно почитай хелп по BitBlt. Прозреешь, :)
  • ol'ka (20.06.08 16:22) [20]

    > TransparentBlt
    > В качестве одного из параметров идет цвет, который должен
    > быть прозрачным.
    > Blendinga(насколько мне известно) у канваса можно только
    > вручную добиться.

    т.е. что-то руками приделывать нада? это жуть, я наверное сделаю 2 битмапа один со статикой а в другой буду статику каждый раз копировать и дорисовывать остальное ну и на канвас его потом ... как вам такое видится?
  • Sapersky (20.06.08 16:36) [21]
    я наверное сделаю 2 битмапа один со статикой а в другой буду статику каждый раз копировать и дорисовывать остальное ну и на канвас его потом ... как вам такое видится?.

    Нормально, хотя не факт, что копирование будет быстрее чем перерисовка, смотря что там рисуется. Если всякая мелочь вроде линий - наверняка быстрее будет перерисовать.

    Blendinga(насколько мне известно) у канваса можно только вручную добиться.

    AlphaBlend
  • ol'ka (20.06.08 16:46) [22]
    сетка из точечных линий там рисуется, средней густоты, впрочем оба метода легко можно будет проверить на деле и судить по факту, хотя судя по тому что даже на 800-м селероне загрузка проца на нуле разница несущественная
  • ol'ka (20.06.08 16:54) [23]
    и еще, может проще будет для формы:
       Canvas.Draw(0,0,BitMap1); вместо этого ужасного BitBlt .... ?
  • @!!ex © (20.06.08 18:04) [24]
    > [23] ol'ka   (20.06.08 16:54)

    Блитинг быстрее. че в нем ужаснее?
  • ol'ka (20.06.08 18:24) [25]
    да ниче в принципе, как говорится "слишкам многа букаф", но если быстрее работает, то это аргумент ... кстати прога уже переписана и чета черен канвас форменный как ворон, пытаюсь побороть ...
  • ol'ka (20.06.08 18:56) [26]
    Я смотрю устали от меня все ...

    Проблему поборол - битмапам размеры не были заданы, теперь вопрос стоит как битмапу задать черный фон по умолчанию и оказывается BitBlt не трет канвас формы а накладывает изображение поверх почемуто ...
    полезные советы вовремя приветствуются!
  • @!!ex © (20.06.08 19:07) [27]
    > [26] ol'ka   (20.06.08 18:56)

    А почему он должен тереть Кэнвас формы?
    Черный цвет задается с помощью:
    Canvas.Brush.Color := clBlack;
    Canvas.FillRect(RECT(0,0,Width,Height));
  • Sapersky (20.06.08 19:26) [28]
    Блитинг быстрее. че в нем ужаснее?

    Примерно на 3%, по моим измерениям :)
    Хотя Canvas.Draw использует StretchBlt, он, видимо, соображает вызвать BitBlt при DstSize = SrcSize.
  • ol'ka (20.06.08 19:46) [29]

    > А почему он должен тереть Кэнвас формы?

    нет, таки трет, ибо с канвасом формы работает, ведь так и должно быть ... а иначе ерунда какая-то получится

    > Черный цвет задается с помощью:
    > Canvas.Brush.Color := clBlack;
    > Canvas.FillRect(RECT(0,0,Width,Height));


    да, да , все именно так и было сделано, пришлось догадаться, и влепить ето для bitmap1 в обработке TForm.onCreate, там же и статика прорисована.

    Короче все работает, облом был когда мне показалось что BitMap1:=BitMap2 скопирует статику из BitMap1 в BitMap2, уж чего оно там натворило разбираться вломы, и чтобы недалеко ходить BitBlt рулит 2 раза - когда BitMap1 в BitMap2 загоняем и когда BitMap2 на канвас формы скидываем. А DoubleBuffer в принципе отдыхает все так быстро происходит что независимо от его значения все проблемы с которых началась тема ушли сами по себе.

    Низкий вам поклон господа крутые програмеры, респект и все такое!
  • ol'ka (20.06.08 19:56) [30]
    P.S. ... забавно было бы все-таки узнать как перехватить прерывание от видеокарты, так чтобы попроще, без всяких там OpenGl, ведь это же всего лишь навсего прерывание, коих в системе много разных, так что вопрос выходит за рамки решенной теперь уже задачи ...
  • @!!ex © (20.06.08 20:39) [31]
    > мне показалось что BitMap1:=BitMap2 скопирует статику из
    > BitMap1 в BitMap2, уж чего оно там натворило разбираться
    > вломы

    Переменная классовая - это указатель.
    Есть два экземпляра класса, на которые указывают переменные BitMap1 и BitMap2.
    А вы взяли и сказали, что BitMap1 указывает не на свой экземпляер, а на BitMap2.
    Если выражаться метафорически, есть два города, Питер и Москва. И есть на дороге два указателя: На Питер и на Москву. А вы взяли и сказали, нифига... Указатель с надписью Питер путь показывает на Москву.. И стали оба указателя указывать на Москву... Хотя написано на них разное... А Питер оказался вообще без указателей... и к нему больше никак не приехать... ибо непонятно куда ехать...


    > чтобы недалеко ходить BitBlt рулит 2 раза - когда BitMap1
    > в BitMap2 загоняем и когда BitMap2 на канвас формы скидываем.
    > А DoubleBuffer в принципе отдыхает все так быстро происходит
    > что независимо от его значения все проблемы с которых началась
    > тема ушли сами по себе.

    Я не понял фразы. :) Так Даблбуффер рулит, или без даблбуффера?
  • ol'ka (20.06.08 21:12) [32]

    > Я не понял фразы. :) Так Даблбуффер рулит, или без даблбуффера?

    даблбуфер получается не при делах, рулит рисование в битмап как мне тут посоветовали он и есть наш буфер! рисуй себе что хочешь и сколько хочешь (по времени), а когда это нада отобразить просто кидаешь на Form.Canvas и ниче не нада буферить, переброска изображения из битмапа на экран происходит мгновенно, значительно быстрее чем движется развертка потому ниче не рвет и не моргает, на маленьких размерах по крайней мере так, а что там будет на больших кто его там знает, но уж если рвать будет то и даблбуфер не решит проблему ведь он тоже суть область памяти в которую все рисуется допустим медленно а потом вся область насколько позволяет скорость шины и частота проца скидывается в видеопамять ...
  • ol'ka (20.06.08 21:24) [33]
    А что касается BitBtl хоть он и быстрее - все же не прижился, выражение громоздкое, тяжелочитаемое, значительно красивее и понятнее с Draw получается а разницы не видно вообще.
  • Сергей М. © (20.06.08 21:29) [34]

    > как перехватить прерывание от видеокарты


    Оч просто - написать драйвер режима ядра)
  • @!!ex © (20.06.08 21:48) [35]
    > [32] ol'ka   (20.06.08 21:12)

    Гы. ЛОЛ.
    Это и есть двойная буфферизация. :)))
    Когда рисуешь в памяти(на битмапе), а потом одной командой выкидываешь это на экран. :))))
  • ol'ka (20.06.08 21:49) [36]
    to @!!ex

    специально чтобы разобраться с DoubleBuffer подменяем в процедуре работу с Bitmap2.Canvas на Form.Canvas с включенным и выключенным DoubleBuffer и разницы не видно, рисует на экране со всеми первоначальными траблами, т.е. нет никакой буферизации все на экране происходит так что загадкой для меня пока остался DoubleBuffer ...
  • @!!ex © (20.06.08 22:14) [37]
    > [36] ol'ka   (20.06.08 21:49)

    Тк хрень, которая называется DoubleBuffer у компонентов - она хрень и есть.
    Я описал что есть двойная буфферизация. :) А вы ее успешно реализовали.
  • @!!ex © (20.06.08 22:23) [38]
    Я когда писал о двойной буфферизации ни словом не обмолвился об компонентах и их свойствах...
    Сказал лишь, что рисовать надо на битмапе. :__
  • ol'ka (20.06.08 22:24) [39]
    да уж "ручной даблбуффер получился" ...

    вот цитата из хелпа на аглицком диалекте :)

    DoubleBuffered property (TWinControl)
    Determines whether the control’s image is rendered directly to the window or painted to an in-memory bitmap first.

    When DoubleBuffered is false, the windowed control paints itself directly to the window. When DoubleBuffered is true, the windowed control paints itself to an in-memory bitmap that is then used to paint the window. Double buffering reduces the amount of flicker when the control repaints, but is more memory intensive.

    When a windowed control is a dock site and has an associated dock manager, it must be double-buffered.

    Note: Some controls, such as TRichEdit, can’t paint themselves into a bitmap. For such controls, DoubleBuffered must be set to false.

    ... из текста следует что даблбуффер работает для объектов которые мы помещаем на форму а саму форму не буферит ... может если влепить на форму панельку тогда ее канвас будет буфериться автоматом, стоит ли проверять?
  • ol'ka (20.06.08 22:32) [40]
    тем не менее фраза ваша

    > @!!ex ©   (20.06.08 13:07) [5]
    > Мерцание никакого отношения к кадровой развертке не имеет.
    >
    > DoubleBuffer в помощь.

    мною была воспринята буквально - как совет использовать DoubleBuffered property.
  • ol'ka (20.06.08 23:01) [41]
    В общем получилось разобраться с DoubleBuffered property.
    Эта "хрень" проявляет себя в обработчике TFTForm.onPaint.

    Для эксперимента рендеринг был переписан для обработчика onPaint и перерисовывался методом TForm.Repaint (что есть криво т.к. всю форму со всеми причиндалами перерисовывает) причем рендерилось не во второй битмап а в канвас формы, и при DoubleBuffered:=true все работало с буферизацией как будто рисовали в битмап а потом на экран, при DoubleBuffered:=false всепроисходило на экране как есть со всеми вытекающими последствиями. Только практической пользы от этого мало т.к. перерисовывать форму каждый раз все же кривизна. Попытаться воспользоваться TPanel? но у нее нет метода Repaint хотя DoubleBuffered property есть, у TPaintBox наоборот Repaint есть, а DoubleBuffered property нет так что полностью согласен с  @!!ex  "Хрень она и есть Хрень"
  • @!!ex © (21.06.08 09:54) [42]
    > мною была воспринята буквально - как совет использовать
    > DoubleBuffered property.

    Понятно. Надо было сразу описать что я имеб ввиду, а не в [12] :)
  • ol'ka (21.06.08 19:50) [43]
    господа, если кто-то решил что тема закрыта могу подкинуть свежий хворост в костер познания истин, может кто-нибудь заглянет сюда еще. Проблема с выводом картинки вроде бы решена, но как оказалось, причем не сразу, это дороговато стоило с точки зрения ресурсов машины, загрузка процессора (не ахти какого правда -Celeron800) скаканула с 3х аж до 53х % !!! Причем налицо противоречие: примененный метод полностью решил проблему с выводом на экран, а значит переброска из памяти в видеопамять происходит значительно быстрее чем процесс рендеринга, который в свою очередь абсолютно не грузит процессор, в итоге получается что на ровном месте процессор сам придумал себе работу? В поисках виновного был проверен каждый находящийся в цепочке:
    1.переброска из битмап1 в битмап2
    2.Рендеринг в битмапе2
    3.переброска из битмап2 в форму
    и как бывает в жизни виновных не нашлось, каждая процедура по отдельности грузит процессор не больше 1%.
    чудеса начинаются только когда команда в сборе, причем методы разные применялись и Draw и BitBlt и даже DoubleBuffer работал в п.3 вышеуказанной цепочки ... Полтергейст блин ...
  • @!!ex © (21.06.08 21:00) [44]
    Как мерили?
    Рекомендую установить AQTime и померить им. А если найдете крэк - поделится. :))
  • ol'ka (21.06.08 21:54) [45]

    > Как мерили?

    что мерили? загрузку проца если, то в TaskManager все процессы кроме Project на нулях.

    если вопрос в том как попроцедурно мерялось то оставлял только 1 из трех в работе и смотрел загрузку.

    Думал может некорректно TBitmap юзается? во всех примерах он в конструкцию Ditmap.Create; try .... finaly ... end;  засунут, а у меня не так, но ведь с DoubleBuffered property тоже самое, там уж наверняка все корректно сделано
  • @!!ex © (21.06.08 22:34) [46]
    GetTickCount в руки - и вперед считать время затраченное на рендер одного кадра.
    Ну и AQTime конечно тоже.
  • ol'ka (21.06.08 22:45) [47]
    нету у меня того что вы написали, у меня только стандартная установка delphi7 без всяких довесков.
  • @!!ex © (21.06.08 23:57) [48]
    GetTIckCount - это функция WinAPI
    AQTime -  сдельфи не идет. Надо отдельно качать.
  • ol'ka (22.06.08 12:59) [49]
    Какую версию AQTime посоветуете?
    А странности продолжаются, был исключен 1-й битмап и рендерилось сразу во 2-й вместе с сеткой, а проблема осталась, и снова если рендерить на форме без буфера все нормально-загрузки нет. Эксперимент с TForm.Repaint c фоном формы отличным от битмапа показывает (зрительно) что проблема действительно в переброске.   Кстати откомпилированный проект запущенный на ноутбуке с Турионом1,8-64x2 не проявил никаких задержек в исполнении кода, врядли он в 50 раз быстрее работает. Это наталкивает на нехорошие подозрения либо в проблемах в работе с памятью или видеопамятью или еще в дровах матери или видяхи трабла ... интересно что в этом случае в помощь?
  • @!!ex © (22.06.08 13:44) [50]
    > [49] ol'ka   (22.06.08 12:59)

    99% проблема в вашем коде. Где нить накосячили просто. AQtime - любой версии.
  • ol'ka (22.06.08 14:26) [51]
    честно говоря для косяков там просто места нет, это весьма примитивный код, скорее допускаю какую нибудь неучтенную особенность используемых методов, потому до сих пор вожусь с кодом вместо обновления дров в системе ... хотя скоро до этого дойдет. Очередная проверка на другой машине примерно равного уровня той на которой все происходит показала отсутствие проблем с загрузкой проца в весьма жестких условиях - 200FPS
  • ol'ka (22.06.08 15:06) [52]
    Отвлеченный вовопрос.

    Почему инициализация битмапа записывается так:

    var myBitMap: TBitmap;
    ...
    ...
    myBitMap:=TBitMap.Create

    вместо

    myBitMap.Create, который вызывает исключение класса (Access Violation) при исполнении?
  • @!!ex © (22.06.08 19:20) [53]
    > [52] ol'ka   (22.06.08 15:06)

    Я могу только поматерится. :)
    Вы в дебаггере поставьте точку останова на myBitMap.Create запустите и посмотрите(для этого надо навести мышку на переменную), какое значение у myBitMap. Оно NIL! Как можно выполнить метод, если переменная указывает в пустоту????
    Читайте пожалуйста, что такое ООП и как оно работает. На форуме "Прочее" вам с удовольствием подскажут что лучше почитать.
  • ol'ka (22.06.08 20:31) [54]
    Да начиталися уже всяческого, тока в голове все перепуталося, я уж примерно так и думал, только с вопросом поспешность получилась.
    В общем тему наверное можно закрывать спасибо всем за подсказки.
  • ol'ka (22.06.08 20:31) [55]
    Да начиталися уже всяческого, тока в голове все перепуталося, я уж примерно так и думал, только с вопросом поспешность получилась.
    В общем тему наверное можно закрывать спасибо всем за подсказки.
  • MultIfleX (04.07.08 13:55) [56]
    загрузка проца скорее всего изза несоответствия форматов пикселей SRC & DST DC
  • quaid (25.12.09 11:19) [57]

    > Возьмите любую игру. Принудительно отключите вертикальную
    > синхронизацию... И вы не увидите мерцания. Хотя кадры и
    > будут не синхронизированы.


    Это не так. Просто будет не мерцание, а эффект, так называемый Tear-drop
 
Конференция "Игры" » как выловить начало кадровой развертки. [D7, WinXP]
Есть новые Нет новых   [134429   +43][b:0][p:0.001]