IMG_Animation Frame Timing and Rendering

I am writing a C# application that uses interop with SDL in order to handle rendering.
So far, I have managed to load an IMG_Animation from a gif and render individual frames, but the resulting animation seems to be slower than it should be and I am unsure about the best practices for animations.

  1. Frame Rendering

At the moment, when rendering a frame of the animation the code creates a new SDL_Texture from the SDL_Surface that is the current frame (only when switching between frames). I don’t know if this is inefficient. I tried converting all of the surfaces to textures up front, but this caused SDL_RenderPresent to stall.

  1. Frame Timing

My best guess for the unit of the delays in the IMG_Animation struct is milliseconds.
The animation logic uses a delta time value (in seconds) that is calculated using logic like this:

ulong lastCounter = performanceCounter;
performanceCounter = SDL_GetPerformanceCounter();
ulong frequency = SDL_GetPerformanceFrequency();

double deltaTime = (double) ((performanceCounter - lastCounter) / (double) frequency);

(assume performanceCounter is stored elsewhere)

When the animation moves to a frame, it resets a counter. On every update, the counter is incremented by the deltaTime value calculated above converted to milliseconds. Once the counter exceeds the ‘delay’ for the current frame (as defined in the IMG_Animation struct), the animation moves on to the next frame.

I’m not sure what could be wrong with this logic, or whether there are other issues I have been unable to identify.

Is there an easier way to handle animated gifs and/or videos in a way that is compatible with SDL rendering? I’m not opposed to introducing other C libraries that extend SDL.

Converting a SDL_Surface to SDL_Texture can be slow. That’s why you generally only want to do it once during the “load phase”.

Something is wrong. SDL_RenderPresent shouldn’t stall.

When you do this you “lose” the time that has passed since the new frame should have been shown until now. If your code runs quickly then it might not be noticeable but if it’s slowed down by vsync, texture creation or other things then it might be a problem. Instead of setting the counter to zero you might want to subtract the duration for the frame that you have just finished showing.

1 Like

I don’t have a concrete load phase in this case since I am loading the gif files procedurally from streams retrieved from web requests. I have an initialization moment before the rendering begins, which is where I tried to convert the surfaces to textures before.

Do you know what else could cause SDL_RenderPresent to stall?
I have created two animation abstractions - one converts all of the surfaces to textures up front, and the other converts them when they are requested and then caches the result. For some reason, using the up front conversions causes the stall, but using the lazy conversions does not, even though after the animation has played all frames the textures will all have been created.

You are 100% right here - I changed the logic and it seems to be working perfectly.
It looks more like this now:

        var frameDelaySeconds = animation.GetFrameDelay(frame) / 1000D;

        if (frameDelaySeconds <= durationSeconds)
        {
            durationSeconds -= frameDelaySeconds;
            Texture = animation.GetNextTexture(ref frame);
        }

        durationSeconds += deltaTime;