martinkunev
martinkunev

Reputation: 1405

GLX animation slower than expected

I have an application using XCB and openGL. At the beginning, I choose a framebuffer configuration with the following attributes:

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);

I run a simple animation which is supposed to last a fixed duration (1s), but showing it on the screen takes much longer (about 5s). After adding logs to show the value of progress, I found out the actual loop only lasts 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;
    }
}

I am not sure what is really going on. I suppose on each iteration glXSwapBuffers() enqueues the opengl commands for drawing and most of them are yet to be executed when the loop is over.

Tweaking the parameter of usleep() has no effect other than to make the animation less smooth or to make the animation much slower. The problem disappears when I switch to single buffering (but I get the problems associated with single buffering).

It seems I'm not doing something right, but I have no idea what.

Upvotes: 1

Views: 196

Answers (1)

datenwolf
datenwolf

Reputation: 162164

The exact timing behaviour of glXSwapBuffers is left open to each implementation. NVidia and fglrx opt to block glXSwapBuffers until V-Sync (if V-Sync is enabled), Mesa and Intel opt to return immediately and block at the next call that would no longer fit into the command queue, where calls that would modify the back buffer before V-Sync are held up.

However if your desire is an exact length for your animation, then a loop with a fixed amount of frames and performing delays will not work. Instead you should redraw as fast as possible (and use delays only to limit your drawing rate). The animation should be progressed by the actual time that elapsed between the actual draw iterations instead of a fixed timestep (this is in contrast to game loops that should in fact do use a fixed time step, albeit at a much faster rate than drawing).

Last but not least you must not use gettimeofday for controlling animations. gettimeofday reports wall clock time, which may jump, slow down or up or even run backwards. Use high precision timers instead (clock_gettime(CLOCK_MONOTONIC, …)).

Upvotes: 2

Related Questions