Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Terrible Frame Rate With Tile Map System

This thread is locked; no one can reply to it. rss feed Print
Terrible Frame Rate With Tile Map System
Eric Johnson
Member #14,841
January 2013
avatar

Hi there. I've just recently begun playing around with tile-based game development. Everything was going smoothly up until I updated the size of my map from 11x10 to 24x15 (each tile is 15x16 pixels by the way). Now the frame rate is terrible—it's not even playable like this. :-/

Map File

#SelectExpand
1#include <iostream> 2#include <fstream> 3#include "map.h" 4 5using namespace std; 6 7Map::Map(const char* filename) { 8 9 Map::loadCounterX, loadCounterY = 0; 10 11 std::ifstream openfile(filename); 12 13 openfile >> Map::mapSizeX >> Map::mapSizeY; 14 15 // Make sure the map was opened properly 16 if (openfile.is_open()) { 17 18 while (!openfile.eof()) { 19 20 openfile >> Map::map[Map::loadCounterX][Map::loadCounterY]; 21 22 Map::loadCounterX++; 23 24 if (Map::loadCounterX >= Map::mapSizeX) { 25 26 Map::loadCounterX = 0; 27 Map::loadCounterY++; 28 } 29 } 30 } 31 else { 32 33 // Couldn't open file 34 std::cout << "Error loading map!" << endl; 35 } 36} 37 38void Map::draw(ALLEGRO_BITMAP *bitmap, int cameraX, int cameraY) { 39 40 for (int a = 0; a < Map::mapSizeX; a++) { 41 42 for (int b = 0; b < Map::mapSizeY; b++) { 43 44 switch (Map::map[a][b]) { 45 46 case 0: 47 48 al_draw_bitmap_region(bitmap, 33, 0, 15, 16, a * 15 - cameraX, b * 16 - cameraY, 0); 49 break; 50 51 case 1: 52 53 al_draw_bitmap_region(bitmap, 16, 0, 15, 16, 15 * a - cameraX, 16 * b - cameraY, 0); 54 break; 55 56 case 10: 57 58 al_draw_bitmap_region(bitmap, 0, 0, 15, 16, a * 15 - cameraX, b * 16 - cameraY, 0); 59 break; 60 } 61 } 62 } 63}

Render Section of Game Loop

#SelectExpand
1if (draw && al_is_event_queue_empty(event_queue)) { 2 3 // Draw 4 5 draw = false; 6 7 Camera.follow(Player.x, Player.y); 8 9 Map1.draw(player, Camera.x, Camera.y); // SUPER LAGGY! 10 11 Player.draw(player, Camera.x, Camera.y); 12 13 al_flip_display(); 14 al_clear_to_color(al_map_rgb(252, 197, 130)); 15 }

Map File

#SelectExpand
124 15 21 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 41 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 121 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 131 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 141 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 151 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 161 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Any ideas on how to have it run smoothly? Maybe a better map code? Thank you in advance. :)

Edgar Reynaldo
Member #8,592
May 2007
avatar

al_hold_bitmap_drawing(true);

/* Draw from the same bitmap, your atlas, your tiles */

al_hold_bitmap_drawing(false);

This lets the cpu store up drawing operations to send to the gpu all at once, instead of doing one, waiting for the gpu, and doing another, waiting, so on....

And, you should only draw SCREEN_WIDTH/TILE_WIDTH + 1 tiles wide, and SCREEN_HEIGHT/TILE_HEIGHT + 1 tiles tall.

Eric Johnson
Member #14,841
January 2013
avatar

Edit
Got it working! Thank you! :D

Like so? void Map::draw(ALLEGRO_BITMAP *bitmap, int cameraX, int cameraY) { for (int a = 0; a < Map::mapSizeX; a++) { for (int b = 0; b < Map::mapSizeY; b++) { switch (Map::map[a][b]) { case 0: al_hold_bitmap_drawing(true); al_draw_bitmap_region(bitmap, 33, 0, 15, 16, a * 15 - cameraX, b * 16 - cameraY, 0); al_hold_bitmap_drawing(false); break; } } } }

Edgar Reynaldo
Member #8,592
May 2007
avatar

Jeff Bernard
Member #6,698
December 2005
avatar

Does this thread imply that it'll be faster to combine smaller bitmaps into an atlas so that deferred drawing can be used? Or is the gain because they are already in an atlas?

--
I thought I was wrong once, but I was mistaken.

Thomas Fjellstrom
Member #476
June 2000
avatar

You will see a gain from atlasing your bitmaps and using the deferred drawing.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Kris Asick
Member #1,424
July 2001

The size of the tiles will have less of an impact on your framerate compared to how many you're drawing. If your tiles are only 16x16 and you're drawing these at 1920x1080 resolution, that's around 8000 tiles you need to draw per frame. I have a GeForce 9800 GT video card and I can only hit about 10,000 draw calls per frame with Allegro 5 and still maintain 60 FPS.

If you double your tile resolution to 32x32, you will cut down the number of draw ops per frame by 75%.

There is another much more complicated (but extremely efficient) option though. I'm also using a tile size of 16x16 in the game I'm working on, but I've developed a mapping system similar to how old game consoles work, in that you keep a primary background to draw tiles to and ONLY draw in new tiles that have become visible. This way if no new tiles become visible, you don't have to draw any for the frame, just draw the entire background to the screen in a single draw op! :D

The catch is that this background must be sized to a power of 2 so that you can wrap across the edges of it using Allegro's primitive drawing system. Further still, the primitive drawing system has its own quirks, specifically with its low-level functions, so you have to be sure to group all related primitive drawing into a single function call to keep the framerate from dying.

Mine specifically also has the added complication of having a depth-effect going on. You can see an example of it here: http://www.pixelships.com/vzone/dj06.html

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Thomas Fjellstrom
Member #476
June 2000
avatar

Is that really even necessary? The FBO stuff may be a lot slower than you're hoping for on some hardware. Slow enough that its faster to just re-draw everything to the screen instead.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Kris Asick
Member #1,424
July 2001

I'm not directlly accessing frame buffer objects to do what I do so I don't think that's going to make a huge difference. Especially considering the following:

I have a mid-range video card: A GeForce 9800 GT. I can handle about 10,000 draw calls in an A5 program per frame (with deferred drawing) without dipping below 60 FPS. At 1920x1080 resolution, it takes roughly 8000 draw calls to fill the screen with a 16x16 tilemap, leaving only 2000 free for sprites, text, etc.

In my game though, I also have a depth effect going. To achieve this effect by simply drawing everything again would require ANOTHER 24,000 draw calls. Now we're way past the 10,000 limit I can reach, much less a user with a low-end graphics card/chipset.

The engine I've developed only draws in new rows and columns to the background when necessary. A row of 16x16 tiles takes about 150 draw calls. A column takes about 80 draw calls. (I'm factoring in that the depth effect requires the buffer to be about 20% larger than the screen size.)

The entire redraw, including the depth effect, of the background to the screen takes a single al_draw_prim() call with 24 verticies passed in, drawing 8 triangles.

Draw Calls Required per Frame at 60 FPS When:
Moving Diagonally at a high speed: 2 cols + 2 rows + BG = 461
Moving Vertically at high speed: 3 rows + BG = 451
Not Moving at all: BG = 1

Substantially less than the 10,000 I can hit and well within the limits of many systems. ;)

I've tested this engine on several systems now and have reached framerates on the poor ones that even some commercial 2D titles using tilemaps can't hit! ;D

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Thomas Fjellstrom
Member #476
June 2000
avatar

I'm not directlly accessing frame buffer objects to do what I do so I don't think that's going to make a huge difference. Especially considering the following:

Allegro implements drawing to bitmaps with FBOs (when it can).

That said 10,000 calls seems really low. But maybe not. Consumer hardware and their drivers aren't tweaked to handle a bunch of separate calls. You want workstation cards for that (apparently lots of old school CAD packages use OpenGL immediate mode calls, ie: glBegin/glVertex/glEnd etc).

Just note that some hardware really doesn't like FBOs much at all. I'm not sure if its still the case, but after the big intel-gfx linux driver rewrite, my card started supporting FBOs, except it was HORRENDOUSLY slow. It seemed as if the driver was doing it in software, and it may have been.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Kris Asick
Member #1,424
July 2001

Allegro implements drawing to bitmaps with FBOs (when it can).

OK. That's good to know and it might explain a few things I've noted in terms of framerate between my game and some other games on very low-end hardware. Specifically, a system with an integrated Intel POS chipset. My game runs at a lower framerate than other games on said system that don't require heavy amounts of graphic updating. Anything action-based though gets extremely bad framerates to begin with, so the fact that my game managed 26 FPS (with its glow shader off) at all is still impressive considering the hardware. (Glow shader on High Quality mode got about 10 FPS.)

Still, I need the small tile size and the depth effect to give my game its personality. No going back on it now, especially just to accomodate graphics hardware that doesn't quite cut it in the first place. ;)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Go to: