我有一个使用XCB和openGL的应用程序。开始时,我选择具有以下属性的帧缓冲配置:
const int attributes[] = {GLX_BUFFER_SIZE, 32, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, True, GLX_RENDER_TYPE, GLX_RGBA_BIT, None};
fb_configs = glXChooseFBConfig(display, screen_index, attributes, &fb_configs_count);
我运行一个应该持续固定持续时间(1秒)的简单动画,但在屏幕上显示它需要更长的时间(大约5秒)。添加日志以显示进度值后,我发现实际循环只持续1秒。
struct timeval start; // start time of the animation
gettimeofday(&start, 0);
while (1)
{
double progress = timer_progress(&start);
if (progress > 1.0)
break; // end the animation
draw(progress);
glXSwapBuffers(display, drawable);
xcb_generic_event_t *event = xcb_poll_for_event(connection);
if (!event)
{
usleep(1000);
continue;
}
switch (event->response_type & ~0x80)
{
case XCB_EXPOSE:
default:
free(event);
continue;
}
}
我不确定究竟发生了什么。我想在每次迭代glXSwapBuffers()
都会将opengl命令排入队列,并且当循环结束时大部分命令都要执行。
调整usleep()
的参数除了使动画不太平滑或使动画慢得多之外没有任何效果。当我切换到单缓冲时,问题就消失了(但是我遇到了与单缓冲相关的问题)。
我似乎没有做对,但我不知道是什么。
答案 0 :(得分:2)
glXSwapBuffers的确切时序行为对每个实现都是开放的。 NVidia和fglrx选择阻止glXSwapBuffers直到V-Sync(如果启用了V-Sync),Mesa和Intel选择立即返回并在下一次调用时阻塞,该调用将不再适合命令队列,其中调用将修改后退保持V-Sync之前的缓冲区。
但是,如果您的愿望是动画的精确长度,则具有固定数量的帧并执行延迟的循环将无法正常工作。相反,您应该尽快重绘(并且仅使用延迟来限制绘图速率)。动画应该按照实际绘制迭代之间经过的实际时间而不是固定的时间步长来进行(这与实际上应该使用固定时间步长的游戏循环形成对比,尽管速度比绘制速度快得多)。
最后但并非最不重要的是,您不得使用gettimeofday
来控制动画。 gettimeofday
报告挂钟时间,可能会跳跃,减速或上升甚至倒退。请改用高精度计时器(clock_gettime(CLOCK_MONOTONIC, …)
)。