Sign in to follow this  

Double Buffering With SDL

This topic is 3142 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all! :) As some of you might now, I just started learning SDL. One problem I came across is that when I move something on the screen, sometimes a tear/rip will show. What I heard is that a double-buffer would eliminate this problem. Now my problem is this: I have no idea on how to use a double buffer in SDL. If someone would be so kind, could you please show me how to Set up 2 Surfaces that can be blitted to, and swapping them around as viewable? Thank you for you time and effort. :) Please do not mark threads 'solved' in this forum. -- jpetrie [Edited by - jpetrie on May 4, 2009 11:33:32 PM]

Share this post


Link to post
Share on other sites
Just use SDL in software mode, it does double buffering by default. (When creating the window, pass the SDL_SWSURFACE flag, instead of SDL_HWSURFACE)

Also, only call SDL_Flip() once per frame, after doing all your drawing. Don't call it more than once a frame.

Share this post


Link to post
Share on other sites
^Wouldn't I have to set up two surfaces for double buffering (one in the background that I can swap around, and one that is being displayed right now)? I was pretty sure I would have to do that... :-/
By the way, I am flipping the screen only once per frame, and I am using the SDL_SWSURFACE flag when creating my surface.

Share this post


Link to post
Share on other sites
No, don't use software mode, add this flag to SDL_SetVideoMode:
SDL_DOUBLEBUF

for example, you could use this line:

SDL_SetVideoMode(800, 600, 32, SDL_DOUBLEBUF | SDL_HWSURFACE);

software mode does tend to use double buffering by default but you really want hardware acceleration.

Also, no, you don't have to manually handle different buffers, SetVideoMode actually sets the display surface, this is not the same as using a surface for holding an image. In hardware mode, the GPU memory will be used for the back and front buffers.

Share this post


Link to post
Share on other sites
Thanks for your help guys. However, my application (just a ball that you can move around the screen with the arrow keys) still Tear/Rips and seems to freeze in/out for a split second sometimes. Could it be the way I am blitting the images? Or is there some other reason why this happens?

Here is my rendering code:
(screen is the screen surface, background the background image and hero the movable ball)

void render() {
SDL_FillRect(screen, NULL, 0);
SDL_BlitSurface(background, NULL, screen, &backgroundRect);
SDL_BlitSurface(hero, NULL, screen, &heroRect);
SDL_Flip(screen);
}



Thanks in advance. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by pseudobot
^Wouldn't I have to set up two surfaces for double buffering (one in the background that I can swap around, and one that is being displayed right now)? I was pretty sure I would have to do that...

That's what double buffering is, yes, but SDL handles it for you, so you don't need to. If you were writing your game using Win32, or some other API, then yeah, you might need to manually handle two different buffers, but SDL swaps/flips the buffers for you, when you call SDL_Flip(). [smile]
Quote:
Original post by pseudobot
Thanks for your help guys. However, my application (just a ball that you can move around the screen with the arrow keys) still Tear/Rips and seems to freeze in/out for a split second sometimes. Could it be the way I am blitting the images? Or is there some other reason why this happens?

Is your 'render()' function the only place where you do any blitting, or SDL_Flip()ing? Is your render() function only called once per frame?

What exactly do you mean by ripping/tearing? Does the screen flash white for a fraction of a second, or flash the color of the background? Does the ball 'jitter' from side to side (or up/down)? And if so, are you using floats anywhere?

What exactly do you mean by 'freezing' in and out for a moment? The game ceases to respond to your input, and you can't move the ball?
Quote:
Original post by speciesUnknown
software mode does tend to use double buffering by default but you really want hardware acceleration.

There's no point to optimize unneccasarily. If and when he needs the extra speed, then he can always change it, but if this is his first project with SDL, he probably won't need to run the game on the videocard anyway. I've never had to use hardware acceleration with my SDL projects. I admit, my most recent game wasn't really fast-paced, but I was doing plenty of alpha-surface blits per frame, with a smooth framerate.

I understand your point though; why not gain extra speed just by changing the flags? I just never found it necessary with my small projects. If it had become necessary , then I'd make the appropriate changes, but until then, I don't think there's any reason to do so (Except to brag that your game runs at 200 fps per second while mine only runs at 40. [wink]).

Share this post


Link to post
Share on other sites
Quote:
Is your 'render()' function the only place where you do any blitting, or SDL_Flip()ing? Is your render() function only called once per frame?

What exactly do you mean by ripping/tearing? Does the screen flash white for a fraction of a second, or flash the color of the background? Does the ball 'jitter' from side to side (or up/down)? And if so, are you using floats anywhere?

Yes, I am calling SDL_Flip() only once (at the end of the rendering function). With tearing, I mean that the ball that you can move jitters from side to side sometimes. And yes, I am using a double to store the X and Y Velocity of the ball, that gets then added to the SDL_Rect holding the hero. Is this the cause of the problem?

Btw, that with the freezing up was my own fault - messed up a calculation of friction so it LOOKED like it was freezing up. But that's fixed now. :)


Share this post


Link to post
Share on other sites
Quote:
Original post by pseudobot
Yes, I am calling SDL_Flip() only once (at the end of the rendering function). With tearing, I mean that the ball that you can move jitters from side to side sometimes. And yes, I am using a double to store the X and Y Velocity of the ball, that gets then added to the SDL_Rect holding the hero. Is this the cause of the problem?

Most likely, yes. If it was a double-buffering problem, you'd see the screen get cleared, and it'd take too long (fractions of a second) to draw the image, so the program would 'flash' the background color before it'd finish draw the image, and your quick eyes would notice it. But that's not happening here.
A lack of double buffering wouldn't make your images move from side to side, so it has to be something with your positioning of the images. I assumed it was a float; sometimes floats behave that way because they aren't too accurate, they sometimes cause these kind of problems.

Unfortunately, I don't have too much experience with floats/doubles; I only have casual familiarity with them, so hopefully someone with more experience with them could tell you how to resolve your problem.
Quote:
Btw, that with the freezing up was my own fault - messed up a calculation of friction so it LOOKED like it was freezing up. But that's fixed now. :)

Glad that that has been fixed, at least. [smile]

Share this post


Link to post
Share on other sites
Hmm, I still get the jiggling even though I do this:

finalXVel = heroXVel;
finalYVel = heroYVel;

heroRect.x += finalXVel;
heroRect.y += finalYVel;
//End of Movement


//Physics...
heroXVel *= (1-FRICTION);
heroYVel *= (1-FRICTION);




finalXVel & finalYVel are both ints, so they should round by default when I pass them a double value. If it would be of any help I could post the whole source code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Servant of the Lord
Quote:
Original post by speciesUnknown
software mode does tend to use double buffering by default but you really want hardware acceleration.
There's no point to optimize unneccasarily. If and when he needs the extra speed, then he can always change it, but if this is his first project with SDL, he probably won't need to run the game on the videocard anyway. I've never had to use hardware acceleration with my SDL projects. I admit, my most recent game wasn't really fast-paced, but I was doing plenty of alpha-surface blits per frame, with a smooth framerate.
The point here is that these flags allows SDL to make use of hardware page flipping in fullscreen mode. With it your video card is probably capable of switching between pages in perfect sync with the vertical retrace simply by swapping some internal pointers around, whereas SDL makes no attempt to make sure that a software SDL_Flip blit doesn't "collide" with the raster beam and cause ugly tearing.

Quote:
Original post by pseudobot
finalXVel & finalYVel are both ints, so they should round by default when I pass them a double value. If it would be of any help I could post the whole source code.
You really want to perform *all* of your movement logic in floating point. That is you need to keep your hero's X and Y coordinates as floats as well, otherwise you'll never be able to move less than one pixel per frame. The only thing you should be using integers for is to temporarily fill in the rectangle structure for blitting, not to maintain any state between frames.

Oh, and you probably want to round floats to integer with floor() (perhaps bias of 0.5) or you'll get inconsistent results around zero. That is the standard cast rounds both positive and negative values towards zero, which means that pixel zero will end up being twice as "large" as any other pixel.

Share this post


Link to post
Share on other sites
It still tears, even if I keep everything as floats. Here is the whole code, in case anyone has the time to look through it. It appears to lag sometimes, and tears a little too. :(
I have no clue what I am doing wrong. :(

#include <iostream>
#include <string>
#include <SDL.h>
#include <SDL_image.h>

using namespace std;

//Set up the variables for the screen...
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;
const int FRAMES_PER_SECOND = 31;

//Set up Physics Variables
const double FRICTION = 0.1;
//Set up variables fore the player...
const int HERO_SPEEDINCREASE = 1;
const int HERO_MAXSPEED = 10;

double heroXVel = 0;
double heroYVel = 0;

//Key press bools...
bool upPressed = false;
bool downPressed = false;
bool rightPressed = false;
bool leftPressed = false;
//Surfaces...
SDL_Surface *screen;
SDL_Surface *hero;
SDL_Surface *background;

//Rectangles...
SDL_Rect heroRect;
SDL_Rect backgroundRect;

//Events...
SDL_Event event;
//Initalize Functions...
void events();
void logic();
void render();

//Main
int main (int args, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO);
SDL_WM_SetCaption("Movement Try", NULL);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_DOUBLEBUF | SDL_HWSURFACE);

background = IMG_Load("gfx/background.png");
hero = IMG_Load("gfx/hero.png");

bool running = true;
//Main Loop
while (running) {
events();
if (event.type == SDL_QUIT) {
return 0;
}

logic();

render();
}
//Exiting
//cleanup();
return 0;
}

void events() {
if (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
case SDLK_UP: upPressed = true; break;
case SDLK_DOWN: downPressed = true; break;
case SDLK_RIGHT: rightPressed = true; break;
case SDLK_LEFT: leftPressed = true; break;
default: break;
}
}

else if (event.type == SDL_KEYUP) {
switch (event.key.keysym.sym) {
case SDLK_UP: upPressed = false; break;
case SDLK_DOWN: downPressed = false; break;
case SDLK_RIGHT: rightPressed = false; break;
case SDLK_LEFT: leftPressed = false; break;
default: break;
}
}
}
}

void logic() {
// Movement
if (upPressed == true) {
heroYVel -= HERO_SPEEDINCREASE;
}
if (downPressed == true) {
heroYVel += HERO_SPEEDINCREASE;
}

if (rightPressed == true) {
heroXVel += HERO_SPEEDINCREASE;
}
if (leftPressed == true) {
heroXVel -= HERO_SPEEDINCREASE;
}



if (heroXVel > HERO_MAXSPEED) {
heroXVel = HERO_MAXSPEED;
}
else if (heroXVel < -HERO_MAXSPEED) {
heroXVel = -HERO_MAXSPEED;
}

if (heroYVel > HERO_MAXSPEED) {
heroYVel = HERO_MAXSPEED;
}
else if (heroYVel < -HERO_MAXSPEED) {
heroYVel = -HERO_MAXSPEED;
}


if (heroXVel < .9 && heroXVel > -.9) {
heroXVel = 0;
}
if (heroYVel < .9 && heroYVel > -.9) {
heroYVel = 0;
}
heroRect.x += heroXVel;
heroRect.y += heroYVel;
//End of Movement


//Physics...
heroXVel *= (1-FRICTION);
heroYVel *= (1-FRICTION);
}

void render() {
SDL_FillRect(screen, NULL, 0);
SDL_BlitSurface(background, NULL, screen, &backgroundRect);
SDL_BlitSurface(hero, NULL, screen, &heroRect);
SDL_Flip(screen);
}




Share this post


Link to post
Share on other sites
Quote:
Original post by pseudobot
It still teras, even if I keep everything as floats. Here is the whole code, in case anyone has the time to look through it. It appears to lag sometimes, and teras a little too. :(
I have no clue what I am doing wrong. :(
You need floating point heroXPos/heroYPos variables in addition to your heroXVel/heroYVel variables. Don't keep the position inside of the struct as a simple integer.

That is instead of this:
heroRect.x += heroXVel;
heroRect.y += heroYVel;


You should have something like this:

double heroXPos = 0;
double heroYPos = 0;
double heroXVel = 0;
double heroYVel = 0;

.
.
.

heroXPos += heroXVel;
heroYPos += heroYVel;

heroRect.x = floor(heroXPos + 0.5);
heroRect.y = floor(heroYPos + 0.5);

Share this post


Link to post
Share on other sites
Hmm...it is till tearing & appearing to lag. I added an FPS timer & did the whole floor() stuff you mentioned above. Here is what I have:

#include <iostream>
#include <string>
#include <cmath>
#include <SDL.h>
#include <SDL_image.h>

using namespace std;

//Set up the variables for the screen...
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;
const int FRAMES_PER_SECOND = 50;
int ticksDone = 0;
int startTicks = 0;

//Set up Physics Variables
const double FRICTION = 0.1;
//Set up variables fore the player...
const int HERO_SPEEDINCREASE = 1;
const int HERO_MAXSPEED = 10;

double heroXVel = 0;
double heroYVel = 0;
double heroXPos = 0;
double heroYPos = 0;

//Key press bools...
bool upPressed = false;
bool downPressed = false;
bool rightPressed = false;
bool leftPressed = false;
//Surfaces...
SDL_Surface *screen;
SDL_Surface *hero;
SDL_Surface *background;

//Rectangles...
SDL_Rect heroRect;
SDL_Rect backgroundRect;

//Events...
SDL_Event event;
//Initalize Functions...
void events();
void logic();
void render();
void cleanup();
void startFPSTimer();
void stopFPSTimer();

//Main
int main (int args, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO);
SDL_WM_SetCaption("Movement Try", NULL);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_DOUBLEBUF | SDL_HWSURFACE);

background = IMG_Load("gfx/background.png");
hero = IMG_Load("gfx/hero.png");

bool running = true;
//Main Loop
while (running) {
startFPSTimer();
events();
if (event.type == SDL_QUIT) {
return 0;
}

logic();

render();

stopFPSTimer();
if(ticksDone < 1000 / FRAMES_PER_SECOND) {
SDL_Delay((1000 / FRAMES_PER_SECOND)-ticksDone);
}

}
//Exiting
//cleanup();
return 0;
}

void events() {
if (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
case SDLK_UP: upPressed = true; break;
case SDLK_DOWN: downPressed = true; break;
case SDLK_RIGHT: rightPressed = true; break;
case SDLK_LEFT: leftPressed = true; break;
default: break;
}
}

else if (event.type == SDL_KEYUP) {
switch (event.key.keysym.sym) {
case SDLK_UP: upPressed = false; break;
case SDLK_DOWN: downPressed = false; break;
case SDLK_RIGHT: rightPressed = false; break;
case SDLK_LEFT: leftPressed = false; break;
default: break;
}
}
}
}

void logic() {
// Movement
if (upPressed == true) {
heroYVel -= HERO_SPEEDINCREASE;
}
if (downPressed == true) {
heroYVel += HERO_SPEEDINCREASE;
}

if (rightPressed == true) {
heroXVel += HERO_SPEEDINCREASE;
}
if (leftPressed == true) {
heroXVel -= HERO_SPEEDINCREASE;
}



if (heroXVel > HERO_MAXSPEED) {
heroXVel = HERO_MAXSPEED;
}
else if (heroXVel < -HERO_MAXSPEED) {
heroXVel = -HERO_MAXSPEED;
}

if (heroYVel > HERO_MAXSPEED) {
heroYVel = HERO_MAXSPEED;
}
else if (heroYVel < -HERO_MAXSPEED) {
heroYVel = -HERO_MAXSPEED;
}


if (heroXVel < .9 && heroXVel > -.9) {
heroXVel = 0;
}
if (heroYVel < .9 && heroYVel > -.9) {
heroYVel = 0;
}
heroXPos += heroXVel;
heroYPos += heroYVel;

heroRect.x = floor(heroXPos+.5);
heroRect.y = floor(heroYPos+.5);
//End of Movement


//Physics...
heroXVel *= (1-FRICTION);
heroYVel *= (1-FRICTION);
}

void render() {
SDL_FillRect(screen, NULL, 0);
SDL_BlitSurface(background, NULL, screen, &backgroundRect);
SDL_BlitSurface(hero, NULL, screen, &heroRect);
SDL_Flip(screen);
}

void startFPSTimer() {
startTicks = SDL_GetTicks();
}

void stopFPSTimer() {
ticksDone = SDL_GetTicks() - startTicks;
}



Share this post


Link to post
Share on other sites
Quote:
Original post by pseudobot
Noone has an idea on why it is appearing to lag? :-/


Try this:


background = IMG_Load("gfx/background.png");
background = SDL_DisplayFormatAlpha(background);
hero = IMG_Load("gfx/hero.png");
hero = SDL_DisplayFormatAlpha(hero);

Share this post


Link to post
Share on other sites

This topic is 3142 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this