在这个简单的SDL渲染循环中导致口吃帧率的原因是什么?

时间:2011-10-14 21:26:07

标签: c++ windows-7 sdl

我写了一个非常基本的测试,看看SDL是否能在我的系统上正常工作。我认为它会非常流畅地运行,因为绘图代码非常简单,但它根本不光滑,并且根据我指定的帧速率以不同的方式看起来很糟糕。

我希望我做了些傻话。我担心代码很好,但我的Windows 7机器不能很好地与SDL一起使用。我已经过度修改和google了,但我无法弄清楚发生了什么。更有知识的人能看到问题吗?代码如下:

#include "SDL.h"

static int g_width = 1024;
static int g_height = 768;

static int g_frameWaitInterval = 20;   // 50fps
static int g_lastFrameTime = 0;

static int g_ballx = 200;
static int g_bally = 200;
static int g_ballSize = 20;
static int g_ballxVelocity = 5;

void Step();
void Draw();

// Main application loop
void Run(){        
    while(true){
        if(SDL_GetTicks() - g_lastFrameTime >= g_frameWaitInterval){
            g_lastFrameTime = SDL_GetTicks();
            Step();
            Draw();
        }
    }
}

// Bounces the ball back and forth across the screen
void Step(){
    g_ballx += g_ballxVelocity;
    if(g_ballx+g_ballSize>=g_width){
        g_ballx = g_width - (g_ballSize+1);
        g_ballxVelocity = -g_ballxVelocity;
    }
    if(g_ballx<0){
        g_ballx = 0;
        g_ballxVelocity = -g_ballxVelocity;
    }
}

// Draws the ball as a square
void Draw(){
    SDL_Surface* p_screen = SDL_GetVideoSurface();
    SDL_FillRect(p_screen, NULL, 0xff000000);

    SDL_Rect rect;
    rect.x = g_ballx; rect.y = g_bally;
    rect.w = rect.h = g_ballSize;
    SDL_FillRect(SDL_GetVideoSurface(), &rect, 0xffff00ff);

    SDL_UpdateRect(p_screen,0,0,0,0);
}

// Initialises SDL, etc (checking removed for brevity)
int main(int argc, char *argv[]){
    SDL_Init(SDL_INIT_VIDEO);
    SDL_SetVideoMode(g_width, g_height, 0, SDL_SWSURFACE);
    Run();
    return 0;
}

编辑:我在10秒的时间内进行了帧率测试,获得了49.76,这非常接近我所期待的50fps。我还打印出大量单独的帧时序,发现每帧都需要20毫秒,正如预期的那样。这告诉我,问题在于配置的某些方面,而不是我的渲染循环。

3 个答案:

答案 0 :(得分:1)

您可能只需要设置双缓冲。没有它,你可以获得一点点闪烁,即使在简单的程序上也是如此。

答案 1 :(得分:1)

我认为问题在于您正在使用繁忙的循环,而Windows可能会限制您的流程,或类似的东西。

此外,如果您希望动画顺利运行,则应将g_frameWaitInterval添加到g_lastFrameTime,而不是将其更新为返回SDL_GetTicks()。否则,您可能会积累差异并使动画不均匀。

尝试以下方法:

void Run(){        
    while(true){
        Uint32 now = SDL_GetTicks();
        Uint32 dif = now - g_lastFrameTime;

        if (now  >= g_lastFrameTime + g_frameWaitInterval){
            g_lastFrameTime += g_frameWaitInterval;
            Step();
            Draw();
            if (now  >= g_lastFrameTime + g_frameWaitInterval){
                //You are losing time! Correct it!
                g_lastFrameTime = now;
            }
        }
        else {
            //Play nice with CPU time
            SDL_Delay(g_frameWaitInterval - dif);
        }
    }
}

答案 2 :(得分:1)

要获得完美平滑的图像序列,您需要设置双缓冲(在此处绘制一个图像,而另一个在屏幕上显示,并在绘制过程完成后交换它们)和vsync,其中您将帧速率限制为显示器的刷新率,从而避免撕裂效果。在现代系统中,这两种效应是我能想到的唯一可能导致波动,动画效果的因素。