Android OpenGL заикается - vsync?

У меня проблема с циклом рендеринга. Во время перемещения объекта я вижу небольшое заикание, похожее на eglSwapBuffers перестановку одного и того же буфера дважды. Мой FPS постоянно находится в пределах 59-60 FPS. Движение учитывает deltaTime при расчете новой позиции.

Что это может быть??? Может ли двойная буферизация решить эту проблему???

Вот небольшое видео (надеюсь, вы поймете, что я имею в виду). http://youtu.be/bQYiqHUzPuI

Вот мой цикл рендеринга

BOOL CEngine::OnStep()
{
    BOOL    bResult = TRUE;
    UINT32  u32CurrFrameStartTime = GetTime();
    FLOAT32 f32DeltaTime;

    f32DeltaTime = ( u32CurrFrameStartTime - m_u32LastFrameStartTime ) / 1000000000.0f;
    m_u32LastFrameStartTime = u32CurrFrameStartTime;

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    GLERROR();

    if ( m_pScreenBase == NULL )
    {
        if ( eglSwapBuffers( m_pDisplay, m_pSurface ) == EGL_FALSE )
        {
            LogError( "eglSwapBuffers function failed." );
        }

        if ( ( m_pScreenBase = new CStartScreen() ) == NULL )
            LogError( "Can't allocate memory for CStartScreen." );

        m_pScreenBase->Initialize();
    }

    m_pScreenBase->Update( f32DeltaTime );
    m_pScreenBase->Render();

    if ( eglSwapBuffers( m_pDisplay, m_pSurface ) == EGL_FALSE )
    {
        LogError( "eglSwapBuffers function failed." );
    }

    m_i32FramesPerSecond += 1;

    if ( GetTime() - m_u32FPSResetTimer >= 1000000000 )
    {
        LogFPS( "%d", m_i32FramesPerSecond );
        m_i32FramesPerSecond = 0;
        m_u32FPSResetTimer = GetTime();
    }

    // return false when app should be exit
    return bResult;
}

Вот функция обновления

void CStartScreen::Update( FLOAT32  f32DeltaTime )
{
    for ( INT32 i = 0; i < MAX_SQUARES; i++ )
    {
        m_pSquare[ i ]->IncPosX( ( 400.0f * f32DeltaTime ) );

        if ( m_pSquare[ i ]->GetPosX() >= 800.0f )
        {
            m_pSquare[ i ]->IncPosX( -( 800.0f + m_pSquare[ i ]->GetWidth() ) );
        }
    }
}

Если это необходимо, я также могу опубликовать свои настройки EGL и OpenGL.

ОБНОВЛЕНИЕ 1:

UINT32 определяется как

typedef беззнаковое целое UINT32;

inline UINT32 GetTime()
{
    timespec    sTime;
    UINT32      u32Return = 0;

    clock_gettime( CLOCK_MONOTONIC, &sTime );
    u32Return = ( sTime.tv_sec * 1000000000LL ) + sTime.tv_nsec;

    return u32Return;
}

А вот и дельта времени на 1 секунду

f32DeltaTime : 0.012029
f32DeltaTime : 0.016487
f32DeltaTime : 0.016548
f32DeltaTime : 0.023608
f32DeltaTime : 0.017631
f32DeltaTime : 0.023363
f32DeltaTime : 0.012963
f32DeltaTime : 0.026373
f32DeltaTime : 0.016470
f32DeltaTime : 0.012811
f32DeltaTime : 0.016439
f32DeltaTime : 0.016852
f32DeltaTime : 0.025931
f32DeltaTime : 0.012679
f32DeltaTime : 0.013243
f32DeltaTime : 0.014694
f32DeltaTime : 0.016561
f32DeltaTime : 0.016589
f32DeltaTime : 0.020299
f32DeltaTime : 0.014101
f32DeltaTime : 0.016626
f32DeltaTime : 0.016892
f32DeltaTime : 0.016347
f32DeltaTime : 0.018130
f32DeltaTime : 0.019623
f32DeltaTime : 0.012288
f32DeltaTime : 0.016677
f32DeltaTime : 0.016895
f32DeltaTime : 0.016405
f32DeltaTime : 0.018474
f32DeltaTime : 0.017564
f32DeltaTime : 0.014213
f32DeltaTime : 0.016659
f32DeltaTime : 0.016830
f32DeltaTime : 0.016486
f32DeltaTime : 0.018657
f32DeltaTime : 0.026178
**f32DeltaTime : 0.006349**
f32DeltaTime : 0.014091
f32DeltaTime : 0.016504
f32DeltaTime : 0.016617
f32DeltaTime : 0.024325
f32DeltaTime : 0.013866
f32DeltaTime : 0.015417
f32DeltaTime : 0.014500
f32DeltaTime : 0.016950
f32DeltaTime : 0.016418
f32DeltaTime : 0.018194
f32DeltaTime : 0.016803
f32DeltaTime : 0.017097
f32DeltaTime : 0.013594
f32DeltaTime : 0.016732
f32DeltaTime : 0.016599
f32DeltaTime : 0.017600
f32DeltaTime : 0.021286
f32DeltaTime : 0.012039
f32DeltaTime : 0.016735
f32DeltaTime : 0.017146
f32DeltaTime : 0.020083

Не уверен, но я думаю, что строка " f32DeltaTime : 0.006349 " может быть проблемой... Но почему f32DeltaTime настолько мал в некоторых кадрах??? eglSwapBuffers ничего не делает в этом кадре??? Но почему ??? Вопрос вместо вопроса :)


person Hasan Caliskan    schedule 22.06.2013    source источник
comment
Вы уверены, что ничто не сбрасывает m_pScreenBase на NULL?   -  person fadden    schedule 23.06.2013
comment
Привет, я уверен, что ничто не сбрасывает m_pScreenBase. Я схожу с ума :( Что может быть причиной этой проблемы???   -  person Hasan Caliskan    schedule 23.06.2013
comment
Я думаю, что маленькую дельту можно было бы ожидать вслед за большей дельтой. В среднем он должен составлять 0,0167 при 60 кадрах в секунду; 0,026178 + 0,006349 == 0,032527, в среднем 0,0163.   -  person fadden    schedule 24.06.2013
comment
Привет, Фадден, может ли это быть проблемой VSYNC ??? Был ли у вас пример Native-Activity с EGL и OpenGL. У меня больше нет идей :(....   -  person Hasan Caliskan    schedule 25.06.2013
comment
Вы точно не запускаете vsync. Вы запускаете eglSwapBuffers(), который завершается через некоторое время после прибытия vsync. (vsync будит SurfaceFlinger, SurfaceFlinger получает следующий буфер, возвращается eglSwapBuffers). Пока eglSwapBuffers завершается до точки, в которой компоновщик поверхности фиксирует следующий кадр, все в порядке; и даже если вы иногда пропускаете кадр, ваша функция обновления на основе дельта-времени должна сделать его плавным. Попробуйте еще кое-что: установите f32DeltaTime = 0,0167 и посмотрите, как это выглядит (т. е. полностью исключите время из уравнения).   -  person fadden    schedule 25.06.2013
comment
Привет, как вы упомянули, я пытался установить для f32DeltaTime фиксированное значение раньше, но заикание все еще существует. Есть ли способ синхронизировать eglSwapBuffers с vsync? Это не может быть так сложно, чтобы плавно двигать объект :(   -  person Hasan Caliskan    schedule 25.06.2013


Ответы (1)


Похоже, что ваша временная база находится в наносекундах, но хранится в виде 32-битного целого числа. Если вы извлекаете значения из clock_gettime() в своей функции GetTime(), вам понадобятся как секунды, так и наносекунды, и вы должны хранить их в виде 64-битного целого числа. В противном случае время будет время от времени отскакивать назад при вычислении дельты.

Например, если вы используете только tv_nsec:

  • время начала предыдущего кадра 0 с 900000 нс
  • текущее время начала кадра составляет 1 с 100000 нс

Если вы просто вычтете наносекунды, вы получите скачок назад на 800 000 нс вместо шага вперед на 200 000 нс.

Вы можете проверить это, записав значения f32DeltaTime, чтобы убедиться, что они согласованы.

person fadden    schedule 23.06.2013
comment
Привет, я обновил свой вопрос и добавил функцию GetTime. Я пробовал вычисление времени как 64-битное целое число, но проблема все еще существует... :( - person Hasan Caliskan; 24.06.2013
comment
Кажется, тогда этого не было. :-( - person fadden; 24.06.2013