2016-08-19 50 views
1

我有一个使用XCB和OpenGL的应用程序。在开始的时候,我选择一个帧缓存的配置具有以下属性:GLX动画慢于预期

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()的参数除了使动画更不流畅或使动画变得更慢之外没有其他效果。当我切换到单缓冲时,问题消失(但我遇到与单缓冲相关的问题)。

看来我没有做正确的事,但我不知道是什么。

回答

2

glXSwapBuffers的确切时间行为对每个实现保持开放。 NVidia和fglrx选择阻止glXSwapBuffers直到V-Sync(如果启用了V-Sync),Mesa和Intel选择立即返回并阻止下一次不再适合命令队列的调用,其中调用后面的调用在V-Sync暂停之前的缓冲区。

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

最后但并非最不重要的你绝不能使用gettimeofday控制动画。 gettimeofday报告挂钟时间,其可能跳跃,减慢或上升,或者甚至反向运行。使用高精度计时器(clock_gettime(CLOCK_MONOTONIC, …))。

+0

我只使用延迟来限制绘图速度。 'timer_progress()'返回'start'和'draw()'使用该值后的时间。 – martinkunev