是什么导致这个简单的 SDL 渲染循环中帧速率出现卡顿?

发布于 2024-12-09 19:39:07 字数 1778 浏览 0 评论 0原文

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

我希望我做了一些愚蠢的事情。我担心的是代码没问题,但我的 Windows 7 机器无法与 SDL 很好地配合。我已经过多地修补和谷歌搜索,但我无法弄清楚发生了什么。更有知识的人能看到问题吗?代码如下:

#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 毫秒,正如预期的那样。这向我表明问题出在配置的某些方面,而不是我的渲染循环。

I wrote a very basic test to see if SDL would work properly on my system. I assumed it would run perfectly smoothly because the drawing code is very simple, but it is not smooth at all, and looks bad in different ways depending on the frame rate that I specify.

My hope is that I have done something silly. My worry is that the code is fine, but my Windows 7 machine won't play nicely with SDL. I've tinkered and googled excessively, but I can't figure out what's going on. Can someone more knowledgeable see a problem? The code is below:

#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;
}

Edit: I ran a framerate test over the course of 10 seconds and got 49.76, which is very close to the 50fps I was expecting. I also printed out a huge number of individual frame timings and found that every frame took 20ms, as expected. This suggests to me that the problem is with some aspect of the configuration, rather than my rendering loop.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眉黛浅 2024-12-16 19:39:07

您可能只需要设置双缓冲。如果没有它,即使是简单的程序也会出现一点闪烁。

You may just need to set up double buffering. Without it you can get a little bit of flickering, even on simple programs.

我只土不豪 2024-12-16 19:39:07

我认为问题在于你正在使用繁忙的循环,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);
        }
    }
}

I think that the problem is that you are using a busy loop, and Windows probably throttles your process, or something like that.

Also, if you want the animation to run smoothly you should add g_frameWaitInterval to g_lastFrameTime, instead of updating it to the return of SDL_GetTicks(). Otherwise you may accumulate differences and make the animation uneven.

Try the following:

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);
        }
    }
}
溺深海 2024-12-16 19:39:07

为了获得完美平滑的图像序列,您需要设置双缓冲(在其中绘制一个图像,同时在屏幕上显示另一张图像,并在绘制过程完成后交换它们)和垂直同步(在其中限制您的图像)。帧速率与显示器的刷新率保持一致,从而避免撕裂效果。在现代系统上,这两种效果是我能想到的唯一可能导致动画不稳定、闪烁的因素。

To get perfectly smooth sequences of images, you need to both set up double buffering (where you draw into one image, while another is shown on the screen, and swap them after your drawing procedure is done), and vsync, where you cap your frame rate to the refresh rate of your monitor, thus avoiding tearing effects. On modern systems, these two effects are the only probable factors I can think of that could result in choppy, flickery animation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文