SDL_Flip vs SDL_UpdateRect: what's better /smoother?

Hello, the following code make appear a pull-down menu when the user
move the mouse in the upper part of the screen (screen size = 1024x768).
My pull-down menu is an image (1024x161) and it appear in the upper part
of the screen in the following way:

  • draw last row
  • draw last two rows
  • draw last three rows
  • draw all image

The problem is that using “SDL_Flip” (line #2#) the process is slow and
not very smooth.
Instead, if I use “SDL_UpdateRect” (line #1#), each time updating only
the screen from Y=0 to Y=160, the pull-down animation is very fast and
smooth.

Why SDL_Flip is so slow? I know that it update all the screen, but it’s
an hardware process, or not? Am I doing something wrong?
SDL_UpdateRect doesn’t wait vertical sync, it isn’t?

I also read that the sprite size should be “power of two”, is it true?
How much speed I gain doing so and why?

---------- Here’s the code:

// screen size 1024x768
#define MAX_X 1024
#define MAX_Y 768

SDL_Rect raster_src;
SDL_Rect raster_dst;

SDL_Surface *raster_bar;
raster_bar=IMG_Load(“IMG/bar_upper.png”); // image is 1024x161

raster_src.x=0;
raster_src.y=160;
raster_src.w=1024;
raster_src.h=1;
raster_dst.y=0;

while (raster_src.y>=0){

SDL_BlitSurface(raster_bar,&raster_src,screen,&raster_dst);

// #1#
SDL_UpdateRect(screen, 0, 0, MAX_X, 160);

// #2#
//SDL_Flip(screen); 

raster_src.y--;
raster_src.h++;

}----------

SDL_Flip will only use hardware assisted double buffering if you
actually get a hardware surface. This is not always the case,
typically, one can only get a hardware surface when running in
fullscreen mode. I believe it is not possible to get a hardware
surface on X without being root or something, not a good idea.

If your display surface is a software surface, SDL_Flip is basically
SDL_UpdateRect called on the entire screen. As such it will be as slow
as the time it takes to copy all those pixels.

To test if you are getting a hardware surface, check if the value of (
SDL_GetVideoSurface()->flags & SDL_HWSURFACE ), it will be zero if you
did not get a hardware surface.

If you don’t have a hardware surface, I don’t think drawing will wait
for vsync. I could be wrong though.

Sprite size will not need to be a power of two, SDL is (primarily) a
software blitter so it blits rectangles of any size at pretty much the
same speed.

There may be other techniques to speed up blitting, using RLE on
certain surfaces may help. Using SDL_DisplayFormat() on images may
help. Don’t do alpha blending on hardware surfaces, or any per-pixel
manipulation at all.

As always though, you will need to test the speed differences yourself
to be sure. Test them on multiple machines, what may be super quick on
one machine may not act the same under a different set of hardware.On 12/06/07, voidstar wrote:

Why SDL_Flip is so slow? I know that it update all the screen, but it’s
an hardware process, or not? Am I doing something wrong?
SDL_UpdateRect doesn’t wait vertical sync, it isn’t?

I also read that the sprite size should be “power of two”, is it true?
How much speed I gain doing so and why?

Why SDL_Flip is so slow? I know that it update all the screen, but it’s
an hardware process, or not?

You answer your own question - it updates the whole screen which is always going to
be slower than just updating a part of it. Are you using hardware surfaces? It still has to
copy all the data to video memory…

Am I doing something wrong?
SDL_UpdateRect doesn’t wait vertical sync, it isn’t?

Nope. I don’t see why you need to update the whole screen anyway…

I also read that the sprite size should be “power of two”, is it true?
How much speed I gain doing so and why?

Doesn’t need to be but not a bad idea to have power-of-two IMHO.
You will gain speed because calculations are quicker to perform on these surfaces.

Ed___________________________________________________________
Yahoo! Answers - Got a question? Someone out there knows the answer. Try it
now.
http://uk.answers.yahoo.com/

You answer your own question - it updates the whole screen which is always
going to be slower than just updating a part of it. Are you using hardware
surfaces? It still has to copy all the data to video memory…

Thanks for your answer. Yes I do this:

raster_bar=SDL_ConvertSurface(raster_bar, screen->format, SDL_HWSURFACE);

Yes, it has to copy all data, but my question is: ok it’s a bit slower, but
why the animation is not smooth? I see some little flickering. I read that
SDL_Flip does a vertycal sync before writing to video memory and this
should avoid flickering/tearing. But, again, the animation is not smooth.

Nope. I don’t see why you need to update the whole screen anyway…

No, I don’t want to update whole screen, but I was using SDL_Flip() because
it does a vertical sync (and I want it to avoid flickering/ecc).

Is there a function to wait for vertical sync? Maybe a Win32 function?
So I could call this function, and after that I call SDL_UpdateRect.

For example, when I was using SVGAlib under Linux, there was a function
called “vga_waitretrace()”.

To test if you are getting a hardware surface, check if the value of (
SDL_GetVideoSurface()->flags & SDL_HWSURFACE ), it will be zero if you
did not get a hardware surface.
If you don’t have a hardware surface, I don’t think drawing will wait
for vsync. I could be wrong though.

Oops! You’re right, I did not get a hardware surface!
I do this for the screen surface and for the pull-down image surface:

screen = SDL_SetVideoMode(MAX_X, MAX_Y, 32,
SDL_HWSURFACE|SDL_FULLSCREEN|SDL_DOUBLEBUF);

raster_bar=SDL_ConvertSurface(raster_bar, screen->format, SDL_HWSURFACE);

Is it ok? Why I can’t get a hardware surface?! Do i forgot something?

There may be other techniques to speed up blitting, using RLE on
certain surfaces may help. Using SDL_DisplayFormat() on images may
help. Don’t do alpha blending on hardware surfaces, or any per-pixel
manipulation at all.

I used “SDL_ConvertSurface”. However, I also tried to use SDL_DisplayFormat:

SDL_Surface* raster_bar_converted = SDL_DisplayFormat(raster_bar);
SDL_FreeSurface(raster_bar);
raster_bar = raster_bar_converted;

but the result is the same, no difference.

Can you help me?
Thanks!

It may not be easy/possible to get a hardware surface on your platform
at all. Linux tends to be very picky about who can write directly to
hardware.

I recommned you give these a read:
http://www.oreillynet.com/articles/author/1205

The author is a very knowledgeable subscriber to this list.On 12/06/07, voidstar wrote:

Oops! You’re right, I did not get a hardware surface!
I do this for the screen surface and for the pull-down image surface:

screen = SDL_SetVideoMode(MAX_X, MAX_Y, 32,
SDL_HWSURFACE|SDL_FULLSCREEN|SDL_DOUBLEBUF);

raster_bar=SDL_ConvertSurface(raster_bar, screen->format, SDL_HWSURFACE);

Is it ok? Why I can’t get a hardware surface?! Do i forgot something?

It may not be easy/possible to get a hardware surface on your platform
at all. Linux tends to be very picky about who can write directly to
hardware.
I recommned you give these a read:
http://www.oreillynet.com/articles/author/1205

Ok thanks I’ll read it, but I’m not under Linux, I’m using Windows XP!

I just tried this test:

( screen->flags & SDL_HWSURFACE == SDL_HWSURFACE )

and it tells me “true” => hardware surface

While your test:

( SDL_GetVideoSurface()->flags & SDL_HWSURFACE == 0 )

tells me “true” => NO hardware surface

Why?

Hmm…

Looks to me that SDL_HWSURFACE is 0x00000001, so anything & 0x000001
will either be 1 (have hardware) or 0 (don’t). I cannot understand how
you are getting different values in these 2 tests.

It may be a operator precedence issue. checks yup, it seems to be.
== is higher priority than bitwise &, so your code looks like this:

( screen->flags & SDL_HWSURFACE == SDL_HWSURFACE )
which is
( screen->flags & (!0) )
whereas
( SDL_GetVideoSurface()->flags & SDL_HWSURFACE == 0 )
is
(( SDL_GetVideoSurface()->flags & 0 )

Instead, use

if( (screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE)
or
if( (SDL_GetVideoSurface()->flags & SDL_HWSURFACE) != 0)On 12/06/07, voidstar wrote:

It may not be easy/possible to get a hardware surface on your platform
at all. Linux tends to be very picky about who can write directly to
hardware.
I recommned you give these a read:
http://www.oreillynet.com/articles/author/1205

Ok thanks I’ll read it, but I’m not under Linux, I’m using Windows XP!

I just tried this test:

( screen->flags & SDL_HWSURFACE == SDL_HWSURFACE )

and it tells me “true” => hardware surface

While your test:

( SDL_GetVideoSurface()->flags & SDL_HWSURFACE == 0 )

tells me “true” => NO hardware surface

Why?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

It may be a operator precedence issue.

Yes it was that!

The right test is now:

if ( (screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE ) {

printf("Can't get hardware surface\n");
exit(1);

}

Well… I can’t get hardware surface! Why?!

Thanks again.

Well… I can’t get hardware surface! Why?!

You need to use the DirectX driver, not the (default) windib one:

SDL_putenv(“SDL_VIDEODRIVER=directx”);

Of course, that could cause other problems, since I don’t think the
directx driver is really supported any more :frowning:

GregoryOn Tue, 12 Jun 2007, voidstar wrote:

You need to use the DirectX driver, not the (default) windib one:
SDL_putenv(“SDL_VIDEODRIVER=directx”);
Of course, that could cause other problems, since I don’t think the
directx driver is really supported any more :frowning:

I tried. The pull-down animation is still slow but it’s very smooth!
The problem is that all the screen is “crashed”: mixed pictures merged,
the cursor does not erase when I move the mouse, blinking screen, etc :open_mouth:

You mean there’s no way to get hardware surface?!
And, at least, what about a function to wait for vertical sync?

Thanks!

You need to use the DirectX driver, not the (default) windib one:
SDL_putenv(“SDL_VIDEODRIVER=directx”);
Of course, that could cause other problems, since I don’t think
the directx driver is really supported any more :frowning:

I tried. The pull-down animation is still slow but it’s very smooth!
The problem is that all the screen is “crashed”: mixed pictures
merged, the cursor does not erase when I move the mouse, blinking
screen, etc :open_mouth:

You mean there’s no way to get hardware surface?!

Well, it looks like you did get one here… The blinking screen is
very typical for double buffering (hardware page flipping) with
incorrect partial updating.

For every change, you need to update both buffers! (Not an issue
when doing full screen redraws every frame, obviously.)

And, at least, what about a function to wait for vertical sync?

Few platforms provide this, and part of the reason is that it doesn’t
really work without hardware page flipping anyway. (*) You get
tearing concentrated to a narrow band on the screen instead of
randomly distributed. Usually looks worse than not using vsync at
all…

(*) Actually, it does work, if you use some sort of timers
"locked" to the retrace to “sync” multiple times per frame;
that is,
1. Sync in the middle of the screen.
2. Repaint the upper half of the screen.
3. Sync on the retrace (and adjust the timer as needed)
4. Repaint the lower half of the screen.
5. Goto 1. (Next frame.)
I’ve tried this on Linux by hacking an OpenGL driver, and
it works rather well - but I can’t think of any portable
way of doing it on the application level.

//David Olofson - Programmer, Composer, Open Source Advocate

.------- http://olofson.net - Games, SDL examples -------.
| http://zeespace.net - 2.5D rendering engine |
| http://audiality.org - Music/audio engine |
| http://eel.olofson.net - Real time scripting |
’-- http://www.reologica.se - Rheology instrumentation --'On Tuesday 12 June 2007, voidstar wrote: