Sign in to follow this  
kiketom

Agggh!!! Slow FPS drawing map [Solved]

Recommended Posts

Hi!! I have a FPS problem blitting my map structure to screen. I define the screen buffer:
/* in main.cpp */
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 24, SDL_HWSURFACE | SDL_DOUBLEBUF);


/* And this is the Blitting proccess */
/* in Layer.cpp */

int cols;
int rows;
	
	for (int ii = 0; ii <= this->vectorTiles.size() - 1; ii++)
	{
	    cols = (ii % this->GetColsLayer());
            rows = (ii / this->GetRowsLayer());

	    PlotX = (cols*TILE_WIDTH/2)-(rows*(TILE_WIDTH/2));
	    PlotY = ((rows*(TILE_HEIGHT/2))+(cols*(TILE_HEIGHT/2)));
			
			SDL_Rect rect_dest;
			rect_dest.w = 0;
			rect_dest.h = 0;
			rect_dest.x = PlotX;
			rect_dest.y = PlotY;

			if ((PlotX  >= rect->x)&&(PlotX <= rect->x+rect->w)&&(PlotY + TILE_HEIGHT >=rect->y)&&(PlotY<=rect->y+rect->h))
			{
				
				indexImage = this->vectorTiles[(rows * this->GetColsLayer()) + cols]->GetImageNumber();
				
				SDL_Surface *imageTile = this->TileSet->GetTile(indexImage);
				SDL_BlitSurface(imageTile, NULL, screen, &rect_dest);
				SDL_FreeSurface(imageTile);
			}

}



This is the result!! [wow] 12 FPS with only 3 frames!! Where is the problem????? [depressed] Thx [Edited by - kiketom on March 16, 2006 9:13:19 AM]

Share this post


Link to post
Share on other sites
I dont know much about SDL, but.


//If this line loads surface
SDL_Surface *imageTile = this->TileSet->GetTile(indexImage);

//and this line deletes the surface
SDL_FreeSurface(imageTile);

then that is your problem.

you should never load and delete images within your main drawing loop,

instead load your images at game start (or level start) and use them until the game is over (or level changes)

loading and freeing images for each tile is extreamly wasteful

Share this post


Link to post
Share on other sites
I'm not loading the image from File every time.
I'm getting part of the image from the imageTile loaded.





SDL_Surface* tileSet::GetTile(int Index)
{
Uint32 rmask, gmask, bmask, amask;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif

SDL_Surface *surface = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY, this->getWidthImageTiles(), this->getWidthImageTiles(), 32, rmask, gmask, bmask, amask);

SDL_Rect rect_origen;
rect_origen.w = this->getWidthImageTiles();
rect_origen.h = this->getHeightImageTiles();
rect_origen.y = (Index / this->getImageCols()) * rect_origen.h;
rect_origen.x = (Index % this->getImageRows()) * rect_origen.w;

SDL_BlitSurface(this->m_image_tiles, &rect_origen, surface, NULL);

return surface;
}


Share this post


Link to post
Share on other sites
You are still creating new memory and deleting the memory every frame due to SDL_CreateRGBSurface...

Maybe you can cache the surfaces in the beginning and then just return the cached surfaces...

Share this post


Link to post
Share on other sites
Quote:
Original post by kiketom
I'm not loading the image from File every time.
I'm getting part of the image from the imageTile loaded.



*** Source Snippet Removed ***


Lo que estas haciendo es crear una imagen nueva cada vez que dibujas un tile, y despues volverla a borrar. Usas esa imagen para copiar en ella el grafico del tile, y despues volver a copiar de ahi a la pantalla.

Por que no dibujas el tile directamente desde la imagen que tiene todos los tiles (el tileset, vamos) a la pantalla?

De esta manera te ahorras el crear y destruir cientos de superficies cada fotograma, que es lo que te esta bajando la velocidad.

Simplemente:

SDL_BlitSurface(TileSet->GetImageTiles(), &rect_origen, screen, &rect_dest);

Como los datos de la superficie m_image_tiles y el rectangulo de origen se calculan en TileSet, un mejor disenyo seria incluir esto en el propio TileSet, algo como un metodo drawTile (screen, &rect_dest, indiceTile)

Espero que te ayude, un saludo.

PD: I write this in spanish as your profile says you're from spain. If you aren't, just say so and I'll translate ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by kiketom
Now the FPS are 17.
[oh]

still this is very slow ........


Un par de ideas rapidas:

- Prueba a ejecutarlo a pantalla completa, a ver si el resultado es distinto

- Crea las superficies del tileset con el mismo formato de pixel que la superficie screen, esto evitara que el sistema tenga que hacer conversiones en cada blit


De todos modos, es posible que el problema no este en el codigo este, sino en alguna otra cosa que tu programa haga y que pueda estar causando el cuello de botella.

-----

A couple of fast ideas:

- Try running it in fullscreen, and see if you get different rates

- Create the tileset surfaces using the same pixel format than the screen surface, this should stop the system from performing conversions in every blit


Anyways, it's possible the problem is not in this code, but in some other thing your program is doing and creating that bottleneck.

Share this post


Link to post
Share on other sites
This is the implementation of my TileSet contructor

tileSet::tileSet(char file[], int Rows, int Columns)
{
Uint32 color;

this->m_image_tiles = IMG_Load(file);

if (!this->m_image_tiles)
{
printf ("IMG_Load: %s\n", IMG_GetError ());
}

color = SDL_MapRGB(this->m_image_tiles->format, 255, 0, 255);
SDL_SetColorKey(this->m_image_tiles, SDL_SRCCOLORKEY, color);

this->m_Rows = Rows;
this->m_Cols = Columns;
}



How can i make it with the same pixel format that the screen if i create the surface with IMG_Load???

Thanks, ;)

-------------------------------------------------------

Asi tengo implementado la creacion del TileSet:


tileSet::tileSet(char file[], int Rows, int Columns)
{
Uint32 color;

this->m_image_tiles = IMG_Load(file);

if (!this->m_image_tiles)
{
printf ("IMG_Load: %s\n", IMG_GetError ());
}

color = SDL_MapRGB(this->m_image_tiles->format, 255, 0, 255);
SDL_SetColorKey(this->m_image_tiles, SDL_SRCCOLORKEY, color);

this->m_Rows = Rows;
this->m_Cols = Columns;
}



¿Como puedo hacer para que sea del mismo formato que el screen si creo la surface con IMG_Load?

Gracias ;)

Share this post


Link to post
Share on other sites
Reducing the bitsperpixel in the screen to 16 instead of 24 i have won 8 more frames per second.

Now the map (20x20) with 3 layer have 70 FPS in windowed mode.
[totally]
Thanks ALL!!!

[Edited by - kiketom on March 16, 2006 8:10:52 AM]

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