1

我有一个使用 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 秒)。添加日志以显示进度值后,我发现实际循环仅持续 1s。

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()除了使动画不那么平滑或使动画更慢之外没有任何效果。当我切换到单缓冲时,问题就消失了(但我遇到了与单缓冲相关的问题)。

看来我做的不对,但我不知道是什么。

4

1 回答 1

2

glXSwapBuffers 的确切计时行为对每个实现都是开放的。NVidia 和 fglrx 选择阻止 glXSwapBuffers 直到 V-Sync(如果启用了 V-Sync),Mesa 和 Intel 选择立即返回并阻止下一个不再适合命令队列的调用,其中调用会修改后面垂直同步之前的缓冲区被阻止。

但是,如果您希望动画的精确长度,那么具有固定帧数和执行延迟的循环将不起作用。相反,您应该尽可能快地重绘(并且仅使用延迟来限制您的绘图速率)。动画应该按照实际绘制迭代之间经过的实际时间而不是固定时间步长进行(这与实际上应该使用固定时间步长的游戏循环形成对比,尽管速度比绘制快得多)。

最后但并非最不重要的是,您不能用于gettimeofday控制动画。gettimeofday报告挂钟时间,它可能会跳跃、减速或加速,甚至倒退。请改用高精度计时器 ( clock_gettime(CLOCK_MONOTONIC, …))。

于 2016-08-19T15:39:17.023 回答