OpenGL - 渲染定时抖动使动画不稳定

时间:2013-01-19 15:52:58

标签: linux opengl timing

一个小的测试程序(见下文)显示了生涩的输出,我认为这是由OpenGL glutSwapBuffer()期间的奇怪定时抖动引起的。与平均值相比,测试程序经常显示单帧的渲染时间非常长(~330微秒与我机器上的~5.8毫秒) 该程序的输出显示:

[...]
render time:   330us
render time:   372us
render time:   330us
render time:   331us
render time:  5820us
render time:   335us
render time:   332us
render time:   324us
render time:   346us
[...]

设定: 快速PC(Intel i7 CPU @ 3.2GHz),Ubuntu 12.04,NVIDIA GTS450主板,最近的GL驱动程序: OpenGL渲染器字符串:GeForce GTS 450 / PCIe / SSE2 OpenGL版本字符串:4.3.0 NVIDIA 310.19 三星显示器(23“@ 60Hz我假设,所有那些都有60Hz)

在上面的测试用例中,我明确否决了vblank sync:   __GL_SYNC_TO_VBLANK = 0

启用vblank后,我也会得到非常不稳定的时间:

__ GL_SYNC_TO_VBLANK = 1

[...]
render time:  9169us
render time: 14548us
render time: 14613us
render time: 16057us
render time: 18075us
[...]

我还玩过其他参数,例如将X服务器置于高优先级 (sudo schedtool -p 0 -n -20 -N pgrep X)或将程序本身置于高优先级(chrt -p -a --fifo 99 ......)

仍然是生涩的动画 - 这(这是我的假设)是由奇怪的时机引起的。

没有`glutSwapBuffers();'的时间在代码中显示非常稳定的输出:

[...]
render time:     2us
render time:     2us
render time:     2us
render time:     1us
render time:     2us
[...]

因此可以排除外部(其他过程)的影响。

任何人都可以解释这种行为吗?

知道如何改进吗?

该计划:

#include <stdio.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <time.h>

GLfloat gfPosX = 0.0;
GLfloat gfDeltaX = .01;

#define TS_TOUSEC(x) (x.tv_sec * 1000000L + (x.tv_nsec / 1000))
struct timespec t1, t2;

void Draw() {
    int x = 0;

    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    clock_gettime(CLOCK_REALTIME, &t1);
    glBegin(GL_LINES);
        glVertex3f(gfPosX, 0.25, 0.0);
        glVertex3f(gfPosX, 0.75,0.0);
    glEnd();
    clock_gettime(CLOCK_REALTIME, &t2);
    glutSwapBuffers();
    printf("render time: %5uus\n", TS_TOUSEC(t2) - TS_TOUSEC(t1));

    gfPosX += gfDeltaX;
    if (gfPosX >= 1.0 || gfPosX <= 0.0) {
        gfDeltaX = -gfDeltaX;
    }
}

void Timer(int iUnused)
{
    glutPostRedisplay();
    glutTimerFunc(5, Timer, 0);
}

void Initialize() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

int main(int iArgc, char** cppArgv) {
    glutInit(&iArgc, cppArgv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(250, 250);
    glutInitWindowPosition(200, 200);
    glutCreateWindow("XoaX.net");
    Initialize();
    glutDisplayFunc(Draw);
    Timer(0);
    glutMainLoop();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

我不会用这个:

clock_gettime(CLOCK_REALTIME, &t1);

CLOCK_REALTIME显示墙壁时间(即挂在墙上的时钟所示的时间),即不保证是单调的。它可能有点前进或后退,因为时间守护者会对其进行调整。

测量帧渲染时间需要CLOCK_MONOTONIC_RAW。

在没有SwapBuffers的时间中,您只测量发出渲染调用所需的时间。不是渲染时间本身。你必须添加一个glFinish才能得到它,以便实际执行命令队列。

出于所有的目的,你不应该花时间渲染帧,而是单个帧之间的时间,即调用显示函数之间的间隔。这样可以提供更精确的动画。

考虑到输入延迟,我会使用卡尔曼滤波器来预测渲染完成时的输入状态(为此需要帧渲染时间,只需收集统计数据)并使用预测输入状态进行帧前移。