Crazy "random" slowdown
aniquilator

Hello folks.
So this problem is driving me crazy... I tried everything before coming here and bother you guys. But I really dont found whats up.

The explanation:
I'm programmin a game framework... for a long time, and I used to use allegro4 and sdl backends.. Now I'm programmin an allegro5 backend, because? Allegro5 Rules.

So, i "finished" my integration of the graphic module, but I'm finding some crazy problems in some situations..

For example this:Explanation after the code

#SelectExpand
1const int width = 1280; 2const int height = 720; 3 4int main() 5{ 6 try 7 { 8 Graphic::Addon::System::set(); 9 Input::Addon::System::set(); 10 Graphic::Display display("TESTE GORGON Framework rev 207+", width, height); 11 Input::Keyboard keyboard; 12 13 std::vector<Graphic::Image> images; 14 //images.push_back( Graphic::Image("hakumen_normal_map.pcx") ); 15 Graphic::Image a("hakumen.pcx"); 16 //images.push_back( Graphic::Image("hakumen_normal_map.pcx") ); 17 18 19 Core::Point position(150,150); 20 21 float zoom = 1; 22 23 display.setAsTarget(); 24 while(1) 25 { 26 27 keyboard.update(); 28 if( keyboard.getKey( Input::Key::ESCAPE ).isPressed() ) 29 { 30 break; 31 } 32 else if( keyboard.getKey( Input::Key::LEFT_ALT ).isPressed() && keyboard.getKey( Input::Key::ENTER ).isPressed() ) 33 { 34 display.toogleFullScreen(); 35 } 36 37 if ( keyboard.getKey( Input::Key::RIGHT ).isPressed() ) { position.addX(5.5); } 38 else if ( keyboard.getKey( Input::Key::LEFT ).isPressed() ) { position.subX(5.5); } 39 if ( keyboard.getKey( Input::Key::DOWN ).isPressed() ) { position.addY(5.5); } 40 else if ( keyboard.getKey( Input::Key::UP ).isPressed() ) { position.subY(5.5); } 41 42 if ( keyboard.getKey( Input::Key::W ).isPressed() ) { zoom-= 0.1; } 43 else if ( keyboard.getKey( Input::Key::S ).isPressed() ) { zoom+= 0.1; } 44 if(zoom < 0 ) zoom = 0; 45 display.clear(Graphic::Color(1.0f ,0.0f ,0.5f, 1.0 ) ); //limpa a tela 46 47 a.draw(position, a.getWidth()*zoom, a.getHeight()*zoom, Graphic::Mirroring::Normal ); 48 49 al_flip_display(); 50 51 } 52 } 53 catch(Core::Exception& exception) 54 { 55 exception.writeInLog(); 56 std::cout << "exception" << std::endl; 57 } 58 Graphic::System::halt(); 59 return 0; 60}

I load a image and displays it in the screen... aplying some scale..
Note the line comented:

//images.push_back( Graphic::Image("hakumen_normal_map.pcx") );
Graphic::Image a("hakumen.pcx");
//images.push_back( Graphic::Image("hakumen_normal_map.pcx") );

If a uncoment the first line, all my program becomes soooo slow.
but if I uncomment the third line, it runs normally.
Is the same code! O.o

I know that its difficult to know whats happing wihout knowing the Image code and all. But all it does is load a allegro image and puts it inside.

I have used the Allegro Debug version and got the allegro.log, and surprise..

I dont know why, but when it becomes slow to hell I got lots of:

opengl   D         ogl_bitmap.c:649  ogl_lock_region                  [   8,60037] Locking backbuffer
opengl   D         ogl_bitmap.c:846  ogl_unlock_region                [   8,75334] Unlocking backbuffer

I think it calls this every step of the game.
And when it runs normal, i dont get this...
Here are the logs:

NORMAL
SLOW

Please help, I'm getting crazy here, today I passed more than 3 hours running the debug mode, and finding nothing ... :-[
If I understand the reason of the ogl_lock and ogl_unlock always,i can figure whats wrong..

Edgar Reynaldo

You should post your Graphic::Image class constructor.

Mark Oates

For my own curiosity and slightly unrelated to your question, could you talk briefly about your framework, what it aims to do and how it's generally constructed?

aniquilator

So.. I think I found whats causing this whole mess...
In the Image constructor, I load the image.. But I wanted that all my modules to be the most independent possible, so I have my own loading routines. in the allegro image routine i use something like this..

#SelectExpand
1void Image::load(const std::string& pFileName,const ImageLoader& pImageLoader) 2 { 3 setImageBase(System::get().getImage(), true); 4 create(350,350); 5 setAsTarget(); 6 lock(); 7 for(int i =0; i<getHeight(); ++i) 8 { 9 for(int j =0; j<getWidth(); ++j) 10 { 11 System::get().drawPixel( Core::Point(j, i), Color(1.0, 1.0, 0.0, 1.0) ); 12 } 13 } 14 unlock(); 15 16 //pImageLoader.load(*this, pFileName); 17 }

In this code, I'm forcing the load to paint each pixel of the image manually with green...
I set the image as target, after lock it, do putpixel operations...
unlock.

Now what I have discovered... If I create a image small, the program runs fine, if the image is big, than, welcome slowdown.
So what I think is: if there are many put pixel operations the program goes slow...

What do you think?

Now, Mark Oates:
This framework I started more than 4 years ago when I was in the university, the main goal was to build a game framework, easy of use, fast, and so on. What happened, I was without time, and I couldn't do all that I wanted. That Time,I was making it in C. Then time changed I started to make a new one in C++, much better for a game I was making called Rabbitz, I have posted about this game here a long time ago. And I have posted here about a megaman engine I was building, that engine uses the first version of my framework, in C.

So, after that I made my framework all in c++. The main goals: multiplataform, working in a system based in backends: You choose the lib that will render, like, allegro, sdl, allegro5. Why? I wanted to have the most plataforms possible.
The framework has some modules, like:
Audio
Core
Graphic
Input
Physics
Script

and some other modules that I will remove when I have ported them all.

This framework works with lua, as a script language, and chipmunk as a physics lib.
Graphic works with allegro4, allegro5(almost), SDL;
Audio audiere, and I'm porting a openAL backend because, audiere isn't compatible with MacOs.

Besides, I have a Editor, with sprites, animations and sound packages.

After the framework middle age, I started to program a game engine totally based in scripts. And this engine is almost done, you program all your game with lua, and use the framework files, for sprites, audio, animations in your game.
The goal is: you have your game as a lua script, and a executable file, with the engine, if you want to port your game you only have to compile the engine in the new plataform or download it if other one had done it before you for example.

Um.. I think thats it. XD

Elias

So what I think is: if there are many put pixel operations the program goes slow...

Yes, both al_draw_pixel and al_put_pixel are very slow. Avoid them unless in special cases, like maybe use al_draw_pixel for certain particle effects. al_put_pixel is used on locked surfaces - usually just locking in a known format like RGBA then directly modifying the buffer is faster. But al_put_pixel can be easier to understand if speed doesn't matter and in some special cases you might lock to an unknown format in which case you need al_put_pixel.

aniquilator

Elis thats no the case..
I just use al_draw_pixel, when I'm loading my images, and I lock the image first..
it seems that when I use a lot of al_put_pixel, later on, on my main loop, every think becomes slow...

Like I said, this kind of operations is occuring very much:

opengl   D         ogl_bitmap.c:649  ogl_lock_region                  [   8,60037] Locking backbuffer
opengl   D         ogl_bitmap.c:846  ogl_unlock_region                [   8,75334] Unlocking backbuffer

And I dont know why. :(

Elias

Well, al_draw_pixel() will take as long as al_draw_bitmap() - which is quite slow, considering it only draws a single pixel.

What for are you calling al_put_pixel? It doesn't really make sense except for directly modifying memory/locked bitmaps. If you want to draw a single pixel (e.g. for particle effects), use al_draw_pixel.

aniquilator

I just use al_put_pixel in my loading functions.
WHy┬▓ because I have a separated module for loading files, I dont know if this will keep this way, but this is not the problem.
The problem is the "slowdown".

It happens, in my main loop, after put pixels and all.
In my main loop I just clear the buff , draw a image, and then flip the buffer.

But in some cases this ogl_lock, unlock, is happening too much... :(
I think it is that is causing the slowdowns...
Take a look at the log... you will see it.

someone972

What is the code for the draw() and clear() functions?

Elias

You should never use locking during the game... it will kill performance. (There's exceptions, like if you stream a video to a texture and have no other way to transfer the data.)

aniquilator

Elias I'm not locking/unlocking during the game...
I said that in the log i saw that the allegro is locking/unlocking without my comand.. I dont know why it is locking and unlocking every frame.
About the draw and clear functions they are pretty basic, just a wrapper in this example:

#SelectExpand
1void ImageBase::clear(const Color& pColor) const 2{ 3 ALLEGRO_BITMAP* aux = al_get_target_bitmap(); 4 al_set_target_bitmap(mData); 5 al_clear_to_color( gorgonColort2AllegroColor(pColor) );//just normal conversion, not big 6 al_set_target_bitmap(aux); 7} 8void ImageBase::draw 9( 10 const Core::Point& pPosition, 11 const int& pWidth, 12 const int& pHeight, 13 const Mirroring& pMirroring 14) const //drawScaled 15{ 16 al_draw_scaled_bitmap 17 ( 18 mData, 19 0, 0, 20 mWidth, mHeight, 21 pPosition.getX(), pPosition.getY(), 22 pWidth, pHeight, 23 gorgonMirroring2AllegroMirroring(pMirroring)//small conversion 24 ); 25}

I was that the problem just happens for drawing operations. If I clear the image instead, it runs normal, but when I draw(every kind of draw),it becomes crazy.

Elias

Why do you clear the bitmap you are drawing? I assume you draw everything to an intermediate buffer and then only draw that. Some (old) cards don't like that. I assume if you never change the target bitmap the slowdown disappears.

aniquilator

I don't clear the bitmap I'm drawing, I just clear the display.

    display.clear(Graphic::Color(1.0f ,0.0f ,0.5f, 1.0 ) );  //limpa a tela
    a.draw(position, a.getWidth()*zoom, a.getHeight()*zoom, Graphic::Mirroring::Normal );
    al_flip_display();

Btw, i made more test today, and I figure out, looking into the allegro locks that when the slowdown happens there is 2 locks into the bitmap, but only one unlock... But I explicity call lock, then unlock, one time each. And I putted a printf there, and i comproved that My calls are correct, one for each, but why the allegro are calling 2 locks? look at these lines in the log:
The Fast:

opengl   D         ogl_bitmap.c:1076 _al_ogl_create_bitmap            [   0,75770] Creating OpenGL bitmap
opengl   D         ogl_bitmap.c:1098 _al_ogl_create_bitmap            [   0,75775] Using dimensions: 350 350
opengl   D         ogl_bitmap.c:1107 _al_ogl_create_bitmap            [   0,75779] Chose format ABGR_8888 for OpenGL bitmap
dtor     D               dtor.c:184  _al_register_destructor          [   0,77158] added dtor for object 0x944cd18, func 0xedc0db
opengl   D        ogl_display.c:194  setup_fbo                        [   0,77169] Created FBO: 1
opengl   D         ogl_bitmap.c:679  ogl_lock_region                  [   0,77181] Locking non-backbuffer READWRITE
display  D        xfullscreen.c:974  _al_xglx_handle_mmon_event       [   0,82355] got event 28
opengl   D         ogl_bitmap.c:892  ogl_unlock_region                [   0,96023] Unlocking non-backbuffer READWRITE

The Slow:

opengl   D         ogl_bitmap.c:1076 _al_ogl_create_bitmap            [   0,79280] Creating OpenGL bitmap
opengl   D         ogl_bitmap.c:1098 _al_ogl_create_bitmap            [   0,79287] Using dimensions: 350 350
opengl   D         ogl_bitmap.c:1107 _al_ogl_create_bitmap            [   0,79291] Chose format ABGR_8888 for OpenGL bitmap
dtor     D               dtor.c:184  _al_register_destructor          [   0,80180] added dtor for object 0x95339e8, func 0x8790db
opengl   D         ogl_bitmap.c:679  ogl_lock_region                  [   0,80190] Locking non-backbuffer READWRITE
opengl   D         ogl_bitmap.c:671  ogl_lock_region                  [   0,84405] Locking non-backbuffer WRITEONLY
opengl   D         ogl_bitmap.c:888  ogl_unlock_region                [   0,84568] Unlocking non-backbuffer WRITEONLY
dtor     D               dtor.c:214  _al_unregister_destructor        [   0,85012] removed dtor for object 0x9546ca8

OOOO This is driving me crazy.:(

Elias

al_set_target_bitmap(mData);
al_clear_to_color( gorgonColort2AllegroColor(pColor) );//just normal conversion, not big
al_set_target_bitmap(aux);

So "aux" and "mData" are the same?

Btw, i made more test today, and I figure out, looking into the allegro locks that when the slowdown happens there is 2 locks into the bitmap, but only one unlock... But I explicity call lock, then unlock, one time each.

That would explain the slowness. What is the difference between your two logs? Or are you saying the same program, when you run it multiple times, will behave differently?

Are you calling any graphics functions other than al_put_pixel or al_draw_pixel while a bitmap is locked?

aniquilator

Aux is the previous target.
I save the previous target, set the new one(just for cleaning), clear, and set back the older.

To generate my logs, i have done this:
just one cicle of the main loop, and a return 0 after it.
So, The slow one, I simulate the situation describe in the first message, I uncommented the first images.push_back( Graphic::Image("hakumen_normal_map.pcx") );

to siulate the fast and normal behavior, I uncommented the second.
Thats all.
and after, vimdiff in both logs.

Edit:
The slowdown happens when I try to draw every image I create after the first...

Edit2:
I found the problem.
In the Image destructor I was doing this:

ImageBase::~ImageBase()
{
  if(mData != NULL)
  {
    if( al_get_target_bitmap() == mData )
    {
      al_set_target_bitmap(NULL);
    }
    al_destroy_bitmap(mData);
  }
}

When I commented the al_set_target_bitmap()
Everything is back to normal...
WHY?????

Elias

What for is that if? Why would you ever destroy the current target bitmap?

Are you maybe trying to destroy a bitmap you don't own (like the backbuffer)?

aniquilator

I putted that in the destructor just to erase the target if i would destroy the image. Just ti erase the trash pointer. But the funny fact is that,
if a call al_set_target_bitmap(NULL) everywhere in my code, it will get this slow down. no matter where, if I put this, my program becomes slow...
Edit
It just becomes slow if I call al_set_target_bitmap(NULL)before creating my images, if I call after nothing happens. O.o

Thomas Fjellstrom

It just becomes slow if I call al_set_target_bitmap(NULL)before creating my images, if I call after nothing happens. O.o

Probably because at that point, allegro doesn't know what display to attach your bitmaps to, so it creates memory bitmaps. Which as you've noticed, is slow.

van_houtte

For my own curiosity and slightly unrelated to your question, could you talk briefly about your framework, what it aims to do and how it's generally constructed?

KGM v2.0

aniquilator

So to test this behavior, I have made a small program so simulate it..

#SelectExpand
1int main() 2{ 3 al_init(); 4 al_init_image_addon(); 5 al_install_keyboard(); 6 7 8 ALLEGRO_DISPLAY *display = al_create_display(1280,780); 9 al_set_target_bitmap(NULL); 10 ALLEGRO_BITMAP* img = al_create_bitmap(820,840); 11 al_set_target_bitmap(img); 12 for(int i = 0; i < 820; ++i) 13 { 14 for(int j = 0; j < 840; ++j) 15 al_put_pixel(i,j,al_map_rgb(i,i,j)); 16 } 17 al_set_target_backbuffer(display); 18 float i=0; 19 while (1) 20 { 21 22 ALLEGRO_KEYBOARD_STATE kstate; 23 al_get_keyboard_state(&kstate); 24 25 if (al_key_down(&kstate, ALLEGRO_KEY_ESCAPE)){break;} 26 27 al_clear_to_color(al_map_rgb_f(i,i,i)); 28 al_draw_bitmap(img,20,20,0); 29 al_flip_display(); 30 i+= 0.01; 31 if(i>1) i = 0; 32 } 33}

And if I comment the "al_set_target_bitmap(NULL);" it all work normal, it it remains there, slowdown.
Now I see it, when I create some bitmap with no target_bitmap = memory bitmaps and slowww. Thanks to explain this to me Thomas. :D

btw KGM 2.0 O.o ? I dont get. kkk

van_houtte
Elias

Well, as Tomasu said, never call al_set_target_bitmap(NULL) or you get memory bitmaps.

Thread #607485. Printed from Allegro.cc