Discussion:
SDL2 tilemap - too slow
André Wagner
2013-09-03 16:49:52 UTC
Permalink
I'm using SDL2 to write a game that displays a tilemap at every frame,
but the performance is too slow. I wrote a little program to isolate
the problem. Consider that "temp.bmp" is a 16x16 image.

#include <stdio.h>

#include "SDL2/SDL.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_image.h"

int main()
{
SDL_Window* win;
SDL_Renderer* ren;
int x, y;

SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(800, 600, 0, &win, &ren);
SDL_Surface* sf = IMG_Load("temp.bmp");
SDL_Texture* tx = SDL_CreateTextureFromSurface(ren, sf);

for(;;) {
Uint32 t = SDL_GetTicks();
for(x=0; x<800; x+=16) {
for(y=0; y<600; y+=16) {
SDL_Rect src = { 0, 0, 16, 16 };
SDL_Rect dst = { x, y, 16, 16 };
SDL_RenderCopy(ren, tx, &src, &dst);
}
}
SDL_RenderPresent(ren);
printf("%ld ms\n", SDL_GetTicks() - t);
}
}

Running the program, I see that it takes about 16ms to render a frame.
This is exactly 60 FPS (1000/60), which leaves no room for game logic.
Also, I'm running it in a pretty fast computer.

I'm pretty sure I'm using the wrong strategy, but I'm not sure what be
the right one. Maybe creating a big texture and updating it less often
would be the way to go, but I couldn't find any documentation on how
to copy one texture over another.

Hacking a little into it, I found out that:
- acceleration is active;
- vsync is disabled;
- most of the time (90%) is spent in SDL_RenderPreset.

So, how can I improve the tilemap performance?

Thank you in advance,

André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
Alex Barry
2013-09-03 16:56:46 UTC
Permalink
The one thing I'd recommend is only redrawing when necessary. This means
making a image (according to your loop) 800x600, and drawing once on this
buffer, then perform a render copy/present using this buffer. Only update
the buffer when you need to redraw (like character movement, etc.) and only
update the tiles that have been changed (player moving from one tile to
another, means those two tiles get updated). So you should almost never be
doing a full redraw unless the player is scrolling the tiles (if that even
happens in your application).

Hope that helps,
-Alex
Post by André Wagner
I'm using SDL2 to write a game that displays a tilemap at every frame,
but the performance is too slow. I wrote a little program to isolate
the problem. Consider that "temp.bmp" is a 16x16 image.
#include <stdio.h>
#include "SDL2/SDL.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_image.h"
int main()
{
SDL_Window* win;
SDL_Renderer* ren;
int x, y;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(800, 600, 0, &win, &ren);
SDL_Surface* sf = IMG_Load("temp.bmp");
SDL_Texture* tx = SDL_CreateTextureFromSurface(ren, sf);
for(;;) {
Uint32 t = SDL_GetTicks();
for(x=0; x<800; x+=16) {
for(y=0; y<600; y+=16) {
SDL_Rect src = { 0, 0, 16, 16 };
SDL_Rect dst = { x, y, 16, 16 };
SDL_RenderCopy(ren, tx, &src, &dst);
}
}
SDL_RenderPresent(ren);
printf("%ld ms\n", SDL_GetTicks() - t);
}
}
Running the program, I see that it takes about 16ms to render a frame.
This is exactly 60 FPS (1000/60), which leaves no room for game logic.
Also, I'm running it in a pretty fast computer.
I'm pretty sure I'm using the wrong strategy, but I'm not sure what be
the right one. Maybe creating a big texture and updating it less often
would be the way to go, but I couldn't find any documentation on how
to copy one texture over another.
- acceleration is active;
- vsync is disabled;
- most of the time (90%) is spent in SDL_RenderPreset.
So, how can I improve the tilemap performance?
Thank you in advance,
André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
André Wagner
2013-09-03 17:01:50 UTC
Permalink
The one thing I'd recommend is only redrawing when necessary. This means making a image (according to your loop) 800x600, and drawing once on this buffer, then perform a render copy/present using this buffer.
What do you mean by "image"? A SDL_Surface or a SDL_Texture? Looks
like a SDL_Texture would be the way to go, but I couldn't find any
documentation on how to copy one SDL_Texture in another...

André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
Alex Barry
2013-09-03 17:12:47 UTC
Permalink
I'd recommend making an SDL_surface, and convert it to a texture - then on
any updates to the surface, you can just toss it in a new texture (or there
may be a way to update a texture with a region from a surface?). If you
create it as a texture, then you could make sure it has streaming enabled
so you can read and write to it. I don't know what sort of performance
either option gives you, but I'm sure someone here might have some
information off hand, or browse through the wiki - maybe someone has made
an article comparing those options and their pros/cons? If not, you could
do the comparison yourself and then write up an article. That would be
very useful wiki information, if not directly for SDL, I'm sure gamedev or
some similar website would appreciate the contribution.
Post by Alex Barry
The one thing I'd recommend is only redrawing when necessary. This means
making a image (according to your loop) 800x600, and drawing once on this
buffer, then perform a render copy/present using this buffer.
What do you mean by "image"? A SDL_Surface or a SDL_Texture? Looks
like a SDL_Texture would be the way to go, but I couldn't find any
documentation on how to copy one SDL_Texture in another...
André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Gabriel Jacobo
2013-09-03 17:15:35 UTC
Permalink
Post by André Wagner
The one thing I'd recommend is only redrawing when necessary. This
means making a image (according to your loop) 800x600, and drawing once on
this buffer, then perform a render copy/present using this buffer.
Post by André Wagner
What do you mean by "image"? A SDL_Surface or a SDL_Texture? Looks
like a SDL_Texture would be the way to go, but I couldn't find any
documentation on how to copy one SDL_Texture in another...
André
Take a look at the Render Target functionality, it's designed so you can
render textures on other textures.
Jonathan Dearborn
2013-09-03 20:25:09 UTC
Permalink
I would suggest that you move your timing printf so that it does not count
SDL_RenderPresent(). Chances are that you'll notice most of the time being
spent in that function. The reason? Vsync. Even though you say it is
disabled, the framerate you mention seems like quite the coincidence.

Jonny D
Post by André Wagner
The one thing I'd recommend is only redrawing when necessary. This
means making a image (according to your loop) 800x600, and drawing once on
this buffer, then perform a render copy/present using this buffer.
Post by André Wagner
What do you mean by "image"? A SDL_Surface or a SDL_Texture? Looks
like a SDL_Texture would be the way to go, but I couldn't find any
documentation on how to copy one SDL_Texture in another...
André
Take a look at the Render Target functionality, it's designed so you can
render textures on other textures.
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
RodrigoCard
2013-09-03 23:53:31 UTC
Permalink
Well, I am pretty sure vsync is enabled even if you say it isnt. exact 60 fps is not a coincidence.

try putting some high processing stuff before the render call, you will see it will still run at 60fps

------------------------
Rodrigo Cardoso Rocha
@RodrigoRodrigoR - twitter.com/RodrigoRodrigoR
Chibata Creations - chibatacreations.com
Pallav Nawani
2013-09-04 06:23:38 UTC
Permalink
This is probably because SDL_RenderPresent() is waiting for the vertical
retrace, hence the drawing is locked to 60FPS.
Consider creating setting video mode and creating a renderer yourself
(instead of just using SDL_CreateWindowAndRenderer()) , and setting it
to not wait for vertical retrace.
Post by André Wagner
I'm using SDL2 to write a game that displays a tilemap at every frame,
but the performance is too slow. I wrote a little program to isolate
the problem. Consider that "temp.bmp" is a 16x16 image.
#include <stdio.h>
#include "SDL2/SDL.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_image.h"
int main()
{
SDL_Window* win;
SDL_Renderer* ren;
int x, y;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(800, 600, 0, &win, &ren);
SDL_Surface* sf = IMG_Load("temp.bmp");
SDL_Texture* tx = SDL_CreateTextureFromSurface(ren, sf);
for(;;) {
Uint32 t = SDL_GetTicks();
for(x=0; x<800; x+=16) {
for(y=0; y<600; y+=16) {
SDL_Rect src = { 0, 0, 16, 16 };
SDL_Rect dst = { x, y, 16, 16 };
SDL_RenderCopy(ren, tx, &src, &dst);
}
}
SDL_RenderPresent(ren);
printf("%ld ms\n", SDL_GetTicks() - t);
}
}
Running the program, I see that it takes about 16ms to render a frame.
This is exactly 60 FPS (1000/60), which leaves no room for game logic.
Also, I'm running it in a pretty fast computer.
I'm pretty sure I'm using the wrong strategy, but I'm not sure what be
the right one. Maybe creating a big texture and updating it less often
would be the way to go, but I couldn't find any documentation on how
to copy one texture over another.
- acceleration is active;
- vsync is disabled;
- most of the time (90%) is spent in SDL_RenderPreset.
So, how can I improve the tilemap performance?
Thank you in advance,
André
--
*Pallav Nawani*
*Game Designer/CEO*
http://www.ironcode.com
Twitter: http://twitter.com/Ironcode_Gaming
Facebook: http://www.facebook.com/Ironcode.Gaming
Sam Lantinga
2013-09-04 07:58:05 UTC
Permalink
What platform are you running on? It may be that the video driver has
vsync turned on by default even if the application doesn't request it.
Post by André Wagner
I'm using SDL2 to write a game that displays a tilemap at every frame,
but the performance is too slow. I wrote a little program to isolate
the problem. Consider that "temp.bmp" is a 16x16 image.
#include <stdio.h>
#include "SDL2/SDL.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_image.h"
int main()
{
SDL_Window* win;
SDL_Renderer* ren;
int x, y;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(800, 600, 0, &win, &ren);
SDL_Surface* sf = IMG_Load("temp.bmp");
SDL_Texture* tx = SDL_CreateTextureFromSurface(ren, sf);
for(;;) {
Uint32 t = SDL_GetTicks();
for(x=0; x<800; x+=16) {
for(y=0; y<600; y+=16) {
SDL_Rect src = { 0, 0, 16, 16 };
SDL_Rect dst = { x, y, 16, 16 };
SDL_RenderCopy(ren, tx, &src, &dst);
}
}
SDL_RenderPresent(ren);
printf("%ld ms\n", SDL_GetTicks() - t);
}
}
Running the program, I see that it takes about 16ms to render a frame.
This is exactly 60 FPS (1000/60), which leaves no room for game logic.
Also, I'm running it in a pretty fast computer.
I'm pretty sure I'm using the wrong strategy, but I'm not sure what be
the right one. Maybe creating a big texture and updating it less often
would be the way to go, but I couldn't find any documentation on how
to copy one texture over another.
- acceleration is active;
- vsync is disabled;
- most of the time (90%) is spent in SDL_RenderPreset.
So, how can I improve the tilemap performance?
Thank you in advance,
André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
André Wagner
2013-09-04 10:44:42 UTC
Permalink
Yes. Thank you all for your replies, I now also believe that it is the
VSYNC. Two tests proved this: I removed the tilemap copying, and added
a 5ms delay in the loop, and in both times the timing remained the
same.

My surprise was that SDL_RENDERER_PRESENTVSYNC = 0. I'm running in
Arch Linux inside a VirtualBox.

Regards,

André
What platform are you running on? It may be that the video driver has vsync
turned on by default even if the application doesn't request it.
Post by André Wagner
I'm using SDL2 to write a game that displays a tilemap at every frame,
but the performance is too slow. I wrote a little program to isolate
the problem. Consider that "temp.bmp" is a 16x16 image.
#include <stdio.h>
#include "SDL2/SDL.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_image.h"
int main()
{
SDL_Window* win;
SDL_Renderer* ren;
int x, y;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(800, 600, 0, &win, &ren);
SDL_Surface* sf = IMG_Load("temp.bmp");
SDL_Texture* tx = SDL_CreateTextureFromSurface(ren, sf);
for(;;) {
Uint32 t = SDL_GetTicks();
for(x=0; x<800; x+=16) {
for(y=0; y<600; y+=16) {
SDL_Rect src = { 0, 0, 16, 16 };
SDL_Rect dst = { x, y, 16, 16 };
SDL_RenderCopy(ren, tx, &src, &dst);
}
}
SDL_RenderPresent(ren);
printf("%ld ms\n", SDL_GetTicks() - t);
}
}
Running the program, I see that it takes about 16ms to render a frame.
This is exactly 60 FPS (1000/60), which leaves no room for game logic.
Also, I'm running it in a pretty fast computer.
I'm pretty sure I'm using the wrong strategy, but I'm not sure what be
the right one. Maybe creating a big texture and updating it less often
would be the way to go, but I couldn't find any documentation on how
to copy one texture over another.
- acceleration is active;
- vsync is disabled;
- most of the time (90%) is spent in SDL_RenderPreset.
So, how can I improve the tilemap performance?
Thank you in advance,
André
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
_______________________________________________
SDL mailing list
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
--
Ars longa, vita brevis, occasio praeceps, experientia fallax, iudicium
difficile.
Loading...