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

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

  1. TimaFt

    TimaFt New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2005
    Сообщения:
    13
    Насеколько я понял - это из-за того что перерисовка совпадает с отрисовкой экрана.

    Можно лдикак нибудь в оконном приложеении от этого избавится?
     
  2. KiNDeR

    KiNDeR New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2003
    Сообщения:
    258
    Адрес:
    Russia
    код увидеть можно?
     
  3. TimaFt

    TimaFt New Member

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

    После чего с переодичностью (от 10 мс и больше) расчитываются новые координаты - что строка "бежала"

    После расчёта координат делаю Invalidate() - при этом перехватываю WM_ERASEBKGND - в нем ничего не рисую.



    void CIndicatorWnd::OnPaint()

    {

    CPaintDC dc(this); // device context for painting

    // TODO: Add your message handler code here

    // Do not call CWnd::OnPaint() for painting messages



    RECT rc;

    GetWindowRect(&rc);



    int width = rc.right - rc.left;

    int height = rc.bottom - rc.top;



    CRgn rgn;

    rgn.CreateRectRgn(0, 0, width, height);

    dc.SelectClipRgn(&rgn, RGN_AND);



    CMemDC mem_dc(&dc); // создаётся compatible DC в деструкторе происходит копирование на dc



    mem_dc.FillSolidRect(0, 0, width, height, m_bkColor



    if ( (m_State == iwsEmpty) || (m_pclString == 0) )

    return ; // нечего выводить



    DrawString(&mem_dc);

    }



    // отрисовка строки по последним расчитанным координатам

    // m_destRect - область куда копировать

    // m_sourceRect - область копирования из растра строки

    void CIndicatorWnd::lol: rawString(CDC* pDC)

    {

    int retv = ::StretchDIBits(

    pDC->m_hDC,

    m_destRect.left, m_destRect.top,

    m_destRect.right - m_destRect.left, m_destRect.bottom - m_destRect.top,

    m_sourceRect.left, m_sourceRect.top,

    m_sourceRect.right - m_sourceRect.left, m_sourceRect.bottom - m_sourceRect.top,

    m_pclString->idr_rastr.pRastr,

    reinterpret_cast<const BITMAPINFO*>(m_pclString->idr_rastr.pRastrHeader),

    DIB_RGB_COLORS, SRCCOPY);

    }
     
  4. TimaFt

    TimaFt New Member

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

    После чего с переодичностью (от 10 мс и больше) расчитываются новые координаты - чтобы строка "бежала"

    После расчёта координат делаю Invalidate() - при этом перехватываю WM_ERASEBKGND - в нем ничего не рисую.



    void CIndicatorWnd::OnPaint()

    {

    CPaintDC dc(this); // device context for painting

    // TODO: Add your message handler code here

    // Do not call CWnd::OnPaint() for painting messages



    RECT rc;

    GetWindowRect(&rc);



    int width = rc.right - rc.left;

    int height = rc.bottom - rc.top;



    CRgn rgn;

    rgn.CreateRectRgn(0, 0, width, height);

    dc.SelectClipRgn(&rgn, RGN_AND);



    CMemDC mem_dc(&dc); // создаётся compatible DC в деструкторе происходит копирование на dc



    mem_dc.FillSolidRect(0, 0, width, height, m_bkColor



    if ( (m_State == iwsEmpty) || (m_pclString == 0) )

    return ; // нечего выводить



    DrawString(&mem_dc);

    }



    // отрисовка строки по последним расчитанным координатам

    // m_destRect - область куда копировать

    // m_sourceRect - область копирования из растра строки

    void CIndicatorWnd::lol: rawString(CDC* pDC)

    {

    int retv = ::StretchDIBits(

    pDC->m_hDC,

    m_destRect.left, m_destRect.top,

    m_destRect.right - m_destRect.left, m_destRect.bottom - m_destRect.top,

    m_sourceRect.left, m_sourceRect.top,

    m_sourceRect.right - m_sourceRect.left, m_sourceRect.bottom - m_sourceRect.top,

    m_pclString->idr_rastr.pRastr,

    reinterpret_cast<const BITMAPINFO*>(m_pclString->idr_rastr.pRastrHeader),

    DIB_RGB_COLORS, SRCCOPY);

    }
     
  5. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TimaFt



    exe-шник давай. При blit-е ничего дергаться не должно.
     
  6. TimaFt

    TimaFt New Member

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

    а как мне его дать? он в архиве 150К занимает - MFC приложение...

    Разве что убрать динамическую линковку...
     
  7. TimaFt

    TimaFt New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2005
    Сообщения:
    13
    exe-шник с опцией Use MFC in shared...



    Сейчас раз в 10 милисекунд m_sourceRect.left увеличивается на 2.

    В окошке - это время выполнения ::StretchDIBits в наносекндах...

    [​IMG] 1242543249__GDIIndicator.rar
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TimaFt



    1. Юзай тройную буферизацию. Перегоняй стреччем в мемори контекст, а на видимый уже блитом.

    2. Какая у тебя тачка? Все ли в порядке с дровами на видео?

    У меня все идеально гладко. AMD Athlon x64 3000+, GeForce 6600GT
     
  9. TimaFt

    TimaFt New Member

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



    >> 1. Юзай тройную буферизацию. Перегоняй стреччем в

    >> мемори контекст, а на видимый уже блитом



    Та вроде так и делается. В CMemDC стрэтчем.

    А сам CMemDC на видимый копирует BitBlt...

    CMemDC(CDC* pDC) : CDC()

    {

    m_pDC = pDC;

    // дальше создание compatible DC

    pDC->GetClipBox(&m_rect);

    // ....

    }



    ~CMemDC()

    {

    // Copy the offscreen bitmap onto the screen.

    m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),this, m_rect.left, m_rect.top, SRCCOPY);







    У меня AMD Athlon 2.2+ (x32), ATI Radeon 9000

    Частота экрана 100Гц.



    Та вроде все нормально с драйверами на первый взгляд - глюков незаметно...



    У тебя идеально гладко???? Тю блин - а у меня подёргивания иногда происходят...

    Неужели из-за компа??? Вот это да... Недумал...
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TimaFt







    Ты только не плач :) У меня при этом паралельно derive уравнение второй час решает и грузит проц на 95 процентов :))))
     
  11. TimaFt

    TimaFt New Member

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



    :)

    Та тут уже и слёзы не помогут...



    Но я не пойму - а как же фильмы в окошках замечательно проигрываются и ничего не дёргается?
     
  12. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TimaFt



    Фильмы это не GDI. Там, если так можно сказать, "более аппаратные" блиты :)
     
  13. TimaFt

    TimaFt New Member

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



    На скока "более аппаратно"? :)



    Я вначале сделал с помощью DirectX - нить ждала обратного хода луча - и потом рисовала.

    Но WaitForVertcalBlank 100% времени сьедает - это не дело... Стал высчитывать время отрисовки после чего спать на время: время отрисовки экрана-время отрисовки. После чего уже вызывал WaitForVertcalBlank. Пришлось правда помучится чтобы Sleep спал 7,6 или 8 милисекунд - а не больше (оказуется можна это сделать..)

    Время процессора теперь съедается на 20-25% - и всё гладко и хорошо - токо иногда всё таки происходят пропуски обратного хода луча - тоже не очень радует...

    Но это полбеды - тут блин нада что бы оно заробатоло на Celeron 2 Гц - запустил - проц загружается на 50-60 % процентов и пропуски участились. Но веь на том же Celeron'e фильмы идут замечательно!



    Решил попробовать с помощью GDI... Результат как говорицца на лицо...



    И всё таки - каким образом у других получается делать в окнном режиме вывод без дёрганий????
     
  14. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    TimaFt



    Ну что я тут тебе могу сказать... Как делается vsync я не знаю. Тоесть я могу рассказать тебе все про vsync на OpenGL :) Про остальное - понятия не имею. На GL-е все впорядке, нет рендера нет и загрузки и кадры не выпадают.



    Идея бредовая конечно, но попробуй на GL-е через glDrawPixels выводить :)
     
  15. TimaFt

    TimaFt New Member

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



    :)

    Та да... Требование к моей проге - OpenGL... :)



    Я видел на DirectX разные демки - и там всё нормально.

    Я то на DirectX делаю довольно просто - формирую рисунок в back surface - а потом из back surface копирую на основную поверхность - всё бы хорошо токо эта операция в оконном режиме несихронизируется с обратным ходом луча... :dntknw:

    Приходится извращатся самому..



    Уже и не знаю что и делать: читал есть какие-то BeginScene, копирование шейдеров (или шрейдеров), EndScene - и всё в порядке... .

    Извратится и каким нить макаром между BeginScene и EndScene запихнуть растр как нибудь что бы он отрисовался???? :)



    Попробую под DirectX 9 UpdateSurface... Блин а когда начиналось всего лиш нада было вывести растр - заканчивается OpenGL... :)
     
  16. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Нужно использовать синхронизацию с обратным ходом луча средствами DX! Она работает и в оконном режиме.
    Код (Text):
    1.  
    2. unsigned __int64 inline rdtsc(){ __asm   rdtsc }
    3.  
    4.     unsigned previous_tsc, fps = 0;
    5.  
    6.         while( true )
    7.         {
    8.             // по возможности будем ждать по GetScanLine,
    9.             // иначе используем WaitForVerticalBlank (который загружает CPU)
    10.             unsigned long   scanline;
    11.             if( fps < (refresh_rate ? refresh_rate : 60) - 5
    12.              || direct_draw->GetScanLine(&scanline) == DDERR_UNSUPPORTED
    13.             ){
    14.                 direct_draw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
    15.                 break;
    16.             }
    17.             if( scanline >= max_visible_scanlines - 50) break;
    18.             Sleep( max_visible_scanlines - scanline
    19.                  > max_visible_scanlines * refresh_rate / 800 );
    20.         }
    21.  
    22.         // Мгновенное значение fps.
    23.         unsigned tsc  = rdtsc();
    24.         unsigned tics = tsc - previous_tsc;
    25.         previous_tsc  = tsc;
    26.         if( tics )  fps = cpu_frequency / tics;
    Хотя дёргаться всёравно будет иногда, это же писюк :/
     
  17. TimaFt

    TimaFt New Member

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

    я чуть по другому делал...



    Почему проверяется только DDERR_UNSUPPORTED в

    direct_draw->GetScanLine(&scanline) ??

    Ведь может возвратить и DDERR_VERTICALBLANKINPROGRESS тогда можно сразу выйти.

    Если выходить по DDERR_VERTICALBLANKINPROGRESS могут быть какие-то глюки?



    cpu_frequency - это частота в герцах?

    У меня fps иногда становится равным 5000 или 45600...
     
  18. S_T_A_S_

    S_T_A_S_ New Member

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




    Я тоже как только не делал, пока это самый хороший способ. Совсем забыл - обязательно нужно перед этим всем сделать timeBeginPeriod(1), иначе Sleep(1) на некоторых NT системах будет порядка 15мс занимать.



    >




    Потомучто в этом случае GetScanLine использовать нельзя, и остаётся только WaitForVerticalBlank.



    >




    Учитено здесь:

    if( scanline >= max_visible_scanlines - 50) break;

    max_visible_scanlines - это разрешение по вертикали



    >




    Изначально было в мегагерцах, и fps вычислялось так:

    fps = 1000000 * cpu_frequency / tics;

    в коде выше множитель 1000000 сокращён.



    >




    А обычно оно какое?
     
  19. TimaFt

    TimaFt New Member

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



    > Я тоже как только не делал, пока это самый хороший способ.

    Способо хороший - мой потреблял 15-20% времени процессора.





    > Совсем забыл - обязательно нужно перед этим всем сделать timeBeginPeriod(1), иначе Sleep(1) на некоторых NT системах будет порядка 15мс занимать.

    Я поставил - вызывается до первого запуска нити ожидающей обратный ход луча...



    > А обычно оно какое?



    Я тут в файл скинул результаты...

    При частоте монитора 100 Гц:

    0

    217

    2917

    109

    2207

    4615

    5298

    110

    1091

    103

    2300

    107

    3186

    4437

    4994

    110

    2524

    4262

    4745

    100

    100

    104

    3190

    4425

    108

    1781

    4603

    99

    103

    2704

    106

    2333

    107

    2578

    4656

    5380

    100

    101

    102

    2074

    107

    2913

    4381

    4940

    100

    102

    102



    При частоте монитора 85Гц:

    0

    146

    2396

    84

    87

    85

    2172

    94

    2092

    4847

    5572

    5744

    5757

    89

    2083

    88

    2065

    5170

    90

    2089

    5127

    90

    1739

    4592

    44

    82

    2197

    84

    91

    1956

    5135

    84

    85

    85

    85

    85

    85

    85

    85

    3090

    87

    2741

    87

    85



    В нити кроме ожидания и PostMessage для отсылки fps больше пока ничего и не делается...

    Может большие значения из-за того-что после ожидания обратного хода луча - я ничего кроме PostMessage не вызываю - обратно вхожу в цикл ожидания, а обратный ход луча ещё продолжается и я сразу из цикла выхожу?
     
  20. S_T_A_S_

    S_T_A_S_ New Member

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

    Попробуй что-нибудь рисовать.

    Иначе действительно запросто успеть под проверку:

    if( scanline >= max_visible_scanlines - 50) break;

    // число 50 получено эмпирическим путём

    или можно проверку fps немного усложнить, как нибудь так:

    if( fps < (refresh_rate ? refresh_rate : 60) - 5 || fps > 200

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