Sign in to follow this  
Aoyama

SDL_FULLSCREEN slower than SDL_SWSURFACE ?

Recommended Posts

Aoyama    132
Hi, I've made a little test where you have to move the mouse to click targets on the screen. With SDL_SWSURFACE, it works fine, but when I am using SDL_FULLSCREEN instead, the mouse doesn't react in real-time at all, it's very slow... Do you know why and how I can avoid that ?

Share this post


Link to post
Share on other sites
let_bound    488
Quote:
Original post by Aoyama
Hi,

I've made a little test where you have to move the mouse to click targets on the screen. With SDL_SWSURFACE, it works fine, but when I am using SDL_FULLSCREEN instead, the mouse doesn't react in real-time at all, it's very slow...

Do you know why and how I can avoid that ?


SDL_SWSURFACE and SDL_FULLSCREEN aren't mutually exclusive, so I don't quite understand your question.

If I were to guess, I'd say that you're using a hardware surface in fullscreen, and that you're making use of alpha blending. Using alpha blending with hardware surfaces is guaranteed to kill your framerate because the pixels have to be read back from the VRAM. If this is what you're doing, then the solution is to use software surfaces even in fullscreen (if you want alpha blending) or to avoid alpha blending (at least on hardware surfaces).

Another common cause of poor performances is forgetting to convert your surfaces to the current bit depth. You'll want to read the documentation of SDL_DisplayFormat and SDL_DisplayFormatAlpha if you haven't already.


Hope this helps.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
or he could use opengl to do alpha blending in hardware instead.

Share this post


Link to post
Share on other sites
Aoyama    132
Ok, thanks, I thought that I had to use SDL_SWSURFACE or SDL_FULLSCREEN but it was as mistake... Actually I don't use any alpha blending or any surface other that the screen surface, I just use SDL_FillRect (yes it's very ugly but it's just a test)...

In fact I think that the problem is about SDL_DOUBLEBUF : when I don't use it, the program is not slow in fullscreen, but when I use SDL_FULLSCREEN|SDL_HWSURFACE|SDL_DOUBLEBUF, it's very slow. I just tried with another of my game, and it's also slow if I use fullscreen and double buffering too... Is there anything particular to do to use fullscreen and double buffering ?

Share this post


Link to post
Share on other sites
let_bound    488
Quote:
In fact I think that the problem is about SDL_DOUBLEBUF : when I don't use it, the program is not slow in fullscreen, but when I use SDL_FULLSCREEN|SDL_HWSURFACE|SDL_DOUBLEBUF, it's very slow. I just tried with another of my game, and it's also slow if I use fullscreen and double buffering too... Is there anything particular to do to use fullscreen and double buffering ?


I'd recommand that you try SDL_FULLSCREEN|SDL_SWSURFACE|SDL_DOUBLEBUF and see if that helps.

You could also avoid SDL_DOUBLEBUF altogether. If you aren't doing any kind of scrolling, it's probably a good idea to do that and to redraw only what changed on screen (the so-called dirty rectangles). If you are doing scrolling though, you'll probably get some kind of tearing.


Hope this helps.

Share this post


Link to post
Share on other sites
Aoyama    132
I had tried SWSURFACE also but it is not better :-
Without using the double buffering... You mean I have to hide the rectangle which has to disappear by a rectangle with background color and so on ? It could work now but if I improve graphics with a picture as background, it will be more difficult... So I would like to find a solution with double buffering if that's possible...

I give you the way I initialize SDL, there is maybe an error here :


SDL_Surface *Screen;

...

int WinMain (int argc, char **argv)
{

if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
fprintf (stderr, "Erreur d'initialisation de SDL: %s\n",
SDL_GetError ());
return 0;
}

Screen = SDL_SetVideoMode (SCR_W, SCR_H, 32, SDL_FULLSCREEN|SDL_SWSURFACE|SDL_DOUBLEBUF);

if (Screen == NULL)
{
fprintf(stderr, "Impossible de charger le mode vidéo : %snq", SDL_GetError());
exit(EXIT_FAILURE);
}

...

Share this post


Link to post
Share on other sites
let_bound    488
Quote:
Without using the double buffering... You mean I have to hide the rectangle which has to disappear by a rectangle with background color and so on ? It could work now but if I improve graphics with a picture as background, it will be more difficult... So I would like to find a solution with double buffering if that's possible...


Instead of doing SDL_FillRect(screen, &bounding_rect, black), you'd do SDL_BlitSurface(the_picture, &bound_rect, screen, &bounding_rect). This is oversimplified as it assumes that the picture is the same size as the display, but it should give you an idea. Using dirty rects can get quite messy though.

Anyway, I see nothing wrong with your code except that you're forcing a 32-bit display, but it shouldn't cause any kind of trouble in fullscreen (assuming Windows). Have you tried passing 0 to use the current depth? What happens if you add SDL_ANYFORMAT to the flags passed to SDL_SetVideoMode?

If none of the above works for you, maybe could you post the complete source code of a minimal example exhibiting that behaviour, precising the version of SDL, the platform, compiler and video backend (GDI, DirectDraw, ...) you're using?


Hope this helps.

Share this post


Link to post
Share on other sites
Aoyama    132
Thank you very much for all your answers !

I tried 0 and to add SDL_ANYFORMAT but it doesn't fix the problem :(

So, I'm using MinGW, SDL 1.2.9 under Windows. For the video backend, I don't know how to know it ?

Here is a minimal code :


#include <stdio.h>
#include <stdlib.h>

#include "SDL.h"

#define SCR_W 1024
#define SCR_H 768

SDL_Surface *Screen;

int s_x=0, s_y=0;
int exec=1;

/*
*****************************************************
*/

void a_rectFill(SDL_Surface *screensurf, int x, int y, int w, int h, Uint32 color)
{
SDL_Rect r;

r.x=x;
r.y=y;
r.w=w;
r.h=h;

SDL_FillRect(screensurf, &r, color);
}

/*
*****************************************************
*/

int WinMain (int argc, char **argv)
{

if (SDL_Init (SDL_INIT_VIDEO) < 0)
{
fprintf (stderr, "Erreur d'initialisation de SDL: %s\n",
SDL_GetError ());
return 1;
}

Screen = SDL_SetVideoMode (SCR_W, SCR_H, 32, SDL_FULLSCREEN|SDL_HWSURFACE|SDL_DOUBLEBUF);

if (Screen == NULL)
{
fprintf(stderr, "Impossible de charger le mode vidéo : %snq", SDL_GetError());
exit(EXIT_FAILURE);
}

SDL_ShowCursor(0);



while (exec)
{

SDL_Event event;

if (SDL_PollEvent(&event))
{
if (event.type==SDL_QUIT)
{
exec=0;
}

if (event.type==SDL_MOUSEMOTION)
{
s_x = event.button.x;
s_y = event.button.y;
}
}

if (event.type==SDL_KEYDOWN)
{
if (event.key.keysym.sym==SDLK_ESCAPE)
{
exec=0;
}
}


// bg
SDL_FillRect (Screen, NULL, 0x000033);

// draws a cross around the mouse position
a_rectFill(Screen, s_x-12, s_y, 24, 1, 0xFF0000);
a_rectFill(Screen, s_x, s_y-12, 1, 24, 0xFF0000);


SDL_Flip(Screen);

}



}


If you want the exe, I can upload it.

Share this post


Link to post
Share on other sites
let_bound    488
Quote:
Original post by Aoyama
Thank you very much for all your answers !

I tried 0 and to add SDL_ANYFORMAT but it doesn't fix the problem :(

So, I'm using MinGW, SDL 1.2.9 under Windows. For the video backend, I don't know how to know it ?


SDL_VideoDriverName() will tell you that. I think that the default video backend on Windows is DirectDraw, but it could very well be GDI.

I tested it on my Debian system [1] and it worked fine. I'm surprised you managed to build it at all on Windows though, because AFAIK SDL requires the entry point to have a precise signature (int main(int, char **)). Also, don't forget to call SDL_Quit() at the end of your program. My system was left without a visible mouse cursor and at a 640x480 resolution when I quit your program. [smile]

I'm installing MinGW on my Windows system to see how your code behaves here. I think the problem is that 1) you're using a huge resolution (1024x768 is quite a lot if you are redrawing the whole screen) and 2) you aren't doing much besides filling a rect and drawing a cross in that tight loop. I wouldn't be surprised if adding a simple SDL_Delay(0); right after SDL_Flip(Screen); did the trick.


EDIT:
I'm stupid. The problem probably comes from the way you're polling for events. if (SDL_PollEvent(&event)) means that you're only processing one event per iteration of the loop, so you eventually end up processing events that occured way in the past. Replacing it with while (SDL_PollEvent(&event)) should fix your problem.


Hope this helps.

[1] AMD64 X2 with kernel 2.6.17 SMP, x11 backend, gcc 4.1.2

[Edited by - let_bound on August 19, 2006 12:17:41 PM]

Share this post


Link to post
Share on other sites
Aoyama    132
Quote:
I'm stupid. The problem probably comes from the way you're polling for events. if (SDL_PollEvent(&event)) means that you're only processing one event per iteration of the loop, so you eventually end up processing events that occured way in the past. Replacing it with while (SDL_PollEvent(&event)) should fix your problem.


You're right, it works fine ! Thank you, really, you have spend so much time, sorry ! And I should have guessed it because when I was moving the mouse a lot, the mouse followed the way I asked for after I had stopped...

And sorry for your cursor too, I hope he has reappeared ;)

But I don't understand why this behaviour is different in a window...

Share this post


Link to post
Share on other sites
let_bound    488
Quote:
Original post by Aoyama
You're right, it works fine ! Thank you, really, you have spend so much time, sorry ! And I should have guessed it because when I was moving the mouse a lot, the mouse followed the way I asked for after I had stopped...


No biggie. I needed a break from Fallout 2. [grin]


Quote:
And sorry for your cursor too, I hope he has reappeared ;)


It has. Thanks for caring. ;)


Quote:
But I don't understand why this behaviour is different in a window...


That's a good question. I'm quite sure the behaviour isn't different, but merely faster to manifest. My guess is that the scheduler gives a higher priority to the fullscreen application, resulting in more events per iteration, lagging you faster. Don't quote me on this though.


Hope this helps.

Share this post


Link to post
Share on other sites

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