一个小的测试程序(见下文)显示了生涩的输出,我认为这是由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;
}
答案 0 :(得分:0)
我不会用这个:
clock_gettime(CLOCK_REALTIME, &t1);
CLOCK_REALTIME显示墙壁时间(即挂在墙上的时钟所示的时间),即不保证是单调的。它可能有点前进或后退,因为时间守护者会对其进行调整。
测量帧渲染时间需要CLOCK_MONOTONIC_RAW。
在没有SwapBuffers的时间中,您只测量发出渲染调用所需的时间。不是渲染时间本身。你必须添加一个glFinish才能得到它,以便实际执行命令队列。
出于所有的目的,你不应该花时间渲染帧,而是单个帧之间的时间,即调用显示函数之间的间隔。这样可以提供更精确的动画。
考虑到输入延迟,我会使用卡尔曼滤波器来预测渲染完成时的输入状态(为此需要帧渲染时间,只需收集统计数据)并使用预测输入状态进行帧前移。