【问题标题】:Android OpenGL stuttering - vsync?Android OpenGL 口吃 - 垂直同步?
【发布时间】:2013-06-19 16:53:22
【问题描述】:

我的渲染循环有问题。在移动对象期间,我看到一个看起来像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() ) );
        }
    }
}

如果需要,我也可以发布我的 EGLOpenGL 设置。

更新 1:

UINT32 定义为

typedef unsigned int 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 在这个 Frame 上什么都不做???但为什么 ???一问一答:)

【问题讨论】:

  • 您确定没有将 m_pScreenBase 重置为 NULL 吗?
  • 嗨,我敢肯定,没有什么正在重置 m_pScreenBase。我快疯了:(什么可能导致这个问题???
  • 我认为小三角洲可能会出现在更大的三角洲之后。它应该在 60fps 时平均达到 0.0167; 0.026178 + .006349 == .032527,平均 0.0163。
  • 您好 Fadden,这可能是 VSYNC 问题吗?您是否有一个带有 EGL 和 OpenGL 的 Native-Activity 示例。我没有更多的想法:(....
  • 您并没有完全使用 vsync。您正在运行eglSwapBuffers(),它在 vsync 到达后的一段时间内完成。 (vsync唤醒surfaceflinger,surfaceflinger获取下一个buffer,eglSwapBuffers返回)。只要 eglSwapBuffers 在表面合成器锁定下一帧之前完成,就可以了;即使您偶尔丢帧,您的基于 delta-time 的更新功能也应该让它看起来很流畅。其他尝试:设置 f32DeltaTime = 0.0167 并查看它的外观(即完全排除等式)。

标签: android opengl-es android-ndk native native-activity


【解决方案1】:

看起来您的时基以纳秒为单位,但保存在 32 位整数中。如果您在 GetTime() 函数中从 clock_gettime() 中提取值,则需要秒和纳秒,并且应该将其保存在 64 位整数中。否则,当您计算增量时,时间有时会向后跳跃。

例如,如果您只使用 tv_nsec:

  • 前一帧开始时间为0s 900000ns
  • 当前帧开始时间为1s 100000ns

如果你只减去纳秒,你将获得 800000ns 的向后跳跃,而不是 200000ns 的向前跳跃。

您可以通过记录 f32DeltaTime 值来检查它们是否一致。

【讨论】:

  • 嗨,我更新了我的问题并添加了 GetTime 函数。我也尝试过将时间计算为 64 位整数,但问题仍然存在...... :(
  • 当时好像不是这样的。 :-(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多