Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Drawing text slows down FPS dramatically

This thread is locked; no one can reply to it. rss feed Print
Drawing text slows down FPS dramatically
Aksel Huff
Member #16,201
February 2016

EDIT: Unless there is something wrong with my FPS calculation, it seems like a blank screen will give me around 3000 to 5000 FPS, but if I draw even one small bit of text, it drops down to 20 FPS. Drawing a line does not seem to affect FPS.

I've only just now noticed that with each call to al_draw_text() my FPS drops dramatically. I noticed it when I had flashing "Press Enter" text, whenever the text was visible, an object that followed my mouse stuttered.

I can't think of anything that I might have done to cause this problem. I tried adding several more lines to draw "Main Menu" over and over and with each draw the FPS cut in half for each draw.

I believe this is all the applicable code:

#SelectExpand
1// GAME LOOP 2while (engine->state_manager->running()) 3{ 4 if (engine->event_handler->handleEvents()) //Function included in post 5 { 6 ALLEGRO_EVENT ev = engine->event_handler->getEvent(); 7 engine->input_handler->getInput(ev); 8 engine->state_manager->handleEvents(); 9 10 if (engine->input_handler->isKeyPressed(ALLEGRO_KEY_ESCAPE) || engine->event_handler->eventIs(ALLEGRO_EVENT_DISPLAY_CLOSE)) 11 { 12 engine->state_manager->quit(); 13 } 14 else if (engine->event_handler->eventIs(ALLEGRO_EVENT_TIMER)) 15 { 16 engine->state_manager->update(); 17 } 18 } 19 20 if (engine->event_handler->eventQueueEmpty()) // Simply calls al_is_event_queue_empty() 21 { 22 uint64_t ms = t.getMilliseconds(); 23 elapsed = ms - prev_time; 24 prev_time = ms; 25 26 engine->state_manager->draw(elapsed); // Function included in post 27 engine->draw_engine->flipAndClear(al_map_rgb(0, 0, 0)); 28 } 29 engine->state_manager->cleanStates(); 30} 31 32bool EventHandler::handleEvents() 33{ 34 ALLEGRO_EVENT ev; 35 36 if (!al_get_next_event(event_queue, &ev)) return false; 37 38 if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) 39 focus = false; 40 else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN) 41 focus = true; 42 else if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) 43 { 44 al_acknowledge_resize(al_get_current_display()); 45 axe::log(_MESSAGE, "Display Resized!\n"); 46 engine->draw_engine->resized(); 47 // Windows has just been resized, let anything know about it. 48 } 49 50 this->ev = ev; 51 52 return true; 53} 54 55void MenuState::draw(uint64 elapsed) 56{ 57 //Press Enter will flash once per second 58 el += elapsed; 59 if (el >= 500) draw_text = true; 60 if (el >= 1000) 61 { 62 el -= 1000; 63 draw_text = false; 64 } 65 66 if (font1) 67 { 68 al_draw_text(font1, al_map_rgb(255, 255, 255), w / 2, 64, ALLEGRO_ALIGN_CENTRE, "Main Menu"); 69 } 70 71 if (draw_text && font2) 72 { 73 al_draw_text(font1, al_map_rgb(255, 255, 255), w / 2, h - 128, ALLEGRO_ALIGN_CENTRE, "Press Enter"); 74 } 75 76 //Draws an X starting at (0,0) moving 90 pixels to the right per second, and 50 pixels down per second 77 78 x += 90.f * elapsed / 1000.f; 79 y += 50.f * elapsed / 1000.f; 80 81 al_draw_line(x - 8, y - 8, x + 8, y + 8, al_map_rgb(255, 0, 0), 2); 82 al_draw_line(x - 8, y + 8, x + 8, y - 8, al_map_rgb(255, 0, 0), 2); 83}

Thanks for the help!

Edgar Reynaldo
Member #8,592
May 2007
avatar

Are you loading your fonts before al_create_display? They might be memory bitmaps. Show font and display creation code. All video bitmaps are attached to a display and if you haven't created a display you don't have anything to attach it to so they're memory bitmaps.

Or your problem is something else. What version of Allegro are you using? What platform are you on? What's your compiler?

Aksel Huff
Member #16,201
February 2016

Thanks for the help! I would not have figured this out if you hadn't have brought up memory/video bitmaps!

EDIT2: I added "al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);" before loading fonts and the problem disappeared! I'm guessing Allegro is defaulting to memory bitmaps for some reason? Or something I've done has changed the bitmap flags. Also I've just now noticed that lines 65 and 67 are using al_set_new_bitmap_flags rather than al_set_new_display_flags(). I haven't tested it yet, but I'm guessing that is the culprit.

I'm using Allegro 5.2.2 from NuGet in MSVC Express 2015. Windows 10.

The display is created inside "engine->draw_engine->init()", and then near the end of my game initialization I load a font to draw the FPS with

Here is essentially the program entry for my game:

#SelectExpand
1int Game::init() 2{ 3 t.start(); 4 5 srand(time(NULL)); 6 engine = new axe::Engine(); 7 const float ticks_per_second = 30.f; 8 9 /*************** SET DEFAULT SETTINGS ***************/ 10 11 int width = 1280; 12 int height = 720; 13 bool fullscreen = false; 14 bool music = true; 15 bool sfx = true; 16 bool vsync = true; 17 bool maximized = true; 18 19 engine->settings_handler->set("x_resolution", width); 20 engine->settings_handler->set("y_resolution", height); 21 engine->settings_handler->set("fullscreen", fullscreen); 22 engine->settings_handler->set("maximized", maximized); 23 engine->settings_handler->set("vsync", vsync); 24 engine->settings_handler->set("music", music); 25 engine->settings_handler->set("sfx", sfx); 26 27 engine->settings_handler->loadSettings(".settings"); 28 engine->settings_handler->printSettings(); 29 30 engine->settings_handler->get("x_resolution", width); 31 engine->settings_handler->get("y_resolution", height); 32 engine->settings_handler->get("fullscreen", fullscreen); 33 engine->settings_handler->get("maximized", maximized); 34 engine->settings_handler->get("vsync", vsync); 35 engine->settings_handler->get("music", music); 36 engine->settings_handler->get("sfx", sfx); 37 38 if (engine->init(ticks_per_second)) 39 { 40 axe::crash("Engine failed to initialize!"); 41 return 1; 42 } 43 engine->draw_engine->init(width, height, fullscreen, false); 44 45 engine->draw_engine->setWindowIcon(RES::IMG::ICO); //todo add \n to the error report for this function 46 engine->draw_engine->setWindowTitle("The 21st Floor"); 47 48 engine->sound_manager->setMusicMute(!music); // true in settings means music is on, true in sound_manager means music is off 49 engine->sound_manager->setSFXMute(!sfx); 50 51 engine->state_manager->changeState(new SplashState(engine)); 52 53 fnt = nullptr; 54 fnt = al_load_font(RES::FNT::ARIAL, 18, 0); 55 56 return 0; 57}

And here is my disaster of window initialization!

#SelectExpand
1int DrawEngine::init(int w, int h, bool fullscreen, bool match_aspect_ratio) 2{ 3 ALLEGRO_DISPLAY_MODE display_data; 4 5 this->fullscreen = fullscreen; 6 screenWidth = w; 7 screenHeight = h; 8 9 //Get all possible fullscreen resolutions and calculate aspect ratio 10 int num_display_modes = al_get_num_display_modes(); 11 al_get_display_mode(num_display_modes - 1, &display_data); 12 float aspect_ratio = float(display_data.width) / float(display_data.height); 13 14 //Fill vector with all resolutions, removing duplicates and anything not matching aspect ratio 15 printf("Supported Fullscreen Resolutions:\n"); 16 for (int i = 0; i < num_display_modes; i++) 17 { 18 al_get_display_mode(i, &display_data); 19 20 bool same_aspect; 21 22 if (match_aspect_ratio) 23 same_aspect = float(display_data.width) / float(display_data.height) == aspect_ratio; 24 else 25 same_aspect = true; 26 27 if (same_aspect) 28 { 29 bool dup = false; 30 for (std::vector<ALLEGRO_DISPLAY_MODE>::iterator it = display_modes.begin(); it != display_modes.end(); ++it) 31 { 32 if (display_data.width == (*it).width && display_data.height == (*it).height) 33 dup = true; 34 } 35 if (!dup) 36 { 37 display_modes.push_back(display_data); 38 printf(" %ix%i\n", display_data.width, display_data.height); 39 } 40 } 41 } 42 43 //Make sure the resolution supplied to this function is supported in fullscreen 44 if (fullscreen) 45 { 46 al_set_new_display_flags(ALLEGRO_FULLSCREEN); 47 48 bool found = false; 49 for (int i = display_modes.size() - 1; i >= 0; i--) 50 { 51 if (display_modes[i].width == screenWidth && display_modes[i].height == screenHeight) 52 { 53 found = true; 54 } 55 } 56 if (!found) 57 { 58 screenWidth = display_modes.back().width; 59 screenHeight = display_modes.back().height; 60 axe::log(axe::_WARNING, "Resolution Settings Invalid: Setting resolution to default: %ix%i\n", screenWidth, screenHeight); 61 } 62 } 63 else if (screenWidth == display_modes.back().width && screenHeight == display_modes.back().height) 64 { 65 al_set_new_bitmap_flags(ALLEGRO_MAXIMIZED); 66 } 67 else al_set_new_bitmap_flags(ALLEGRO_WINDOWED); 68 69 display = al_create_display(screenWidth, screenHeight); 70 71 if (!display) 72 { 73 axe::crash("Unable to create display at resolution %ix%i", screenWidth, screenHeight); 74 return 1; 75 } 76 77 if (!fullscreen) centerWindow(); 78 79 al_init_image_addon(); 80 al_init_primitives_addon(); 81 al_init_font_addon(); 82 al_init_ttf_addon(); 83 84 al_register_event_source(event_queue, al_get_display_event_source(display)); 85 86 printf("DrawEngine Initialized\n"); 87 88 return 0; 89}

I'm going to quickly write up a minimal program to see if I can recreate the issue.
EDIT: I've created a barebones program and I can call al_draw_text several hundred times per frame and still get 1000+ FPS using the exact same FPS calculation I am in my game. I must have done something wrong somewhere.

Edgar Reynaldo
Member #8,592
May 2007
avatar

It's a good idea to initialize every addon before creating a display. Do that all in a single init function once before you use your engine. You call init, and then you create a font. In init you create a display, so the font should be attached to a display.

Also I've just now noticed that lines 65 and 67 are using al_set_new_bitmap_flags rather than al_set_new_display_flags(). I haven't tested it yet, but I'm guessing that is the culprit.

Yes, that's a problem. You should be calling al_set_new_display_flags there. Calling al_set_new_bitmap_flags with display flags is an error. There's a separate set of flags.

Go to: