Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] al_draw_bitmap crash

Credits go to Edgar Reynaldo, Mark Oates, Matthew Leverton, and Trent Gamblin for helping out!
This thread is locked; no one can reply to it. rss feed Print
[A5] al_draw_bitmap crash
William Labbett
Member #4,486
March 2004
avatar

Hi, I'm getting a crash with al_draw_bitmap(). The ALLEGRO_BITMAP pointer isn't null. I can't figure it out. Hoping someone can help.

gdb says :-

Quote:

finished.
returned.
got it.
[New Thread 5372.0x17fc]
switching to bitmap 1
creating thread.
[New Thread 5372.0x1670]
making new blot.
calling dinkle_get_connecting_blot for b1.
calling dinkle_make_monochrome_pattern.
tiles_bitmap not NULL.
checking next bitmap.
unmapping colors.
drawing bitmap.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 5372.0x1670]
0x69c83e52 in al_copy_transform () from C:\shmup_project\allegro-5.0.1-md.dll
(gdb)

The code looks like this. The crash happens on the al_draw_bitmap line.

printf("drawing bitmap.\n");
  
  if(tiles_bitmap == NULL) printf("it's NULL.\n");
  
  al_draw_bitmap(tiles_bitmap, 0, 0, 0);
  printf("calling al_flip_display.\n");
  al_flip_display();
  system("PAUSE");

Any ideas ?

Mark Oates
Member #1,146
March 2001
avatar

The only think I can think of is that the tiles_bitmap was somehow deleted, leaving a dangling pointer.

William Labbett
Member #4,486
March 2004
avatar

could it be a thread safety issue ?

EDIT : I removed the threads and now it works fine but still the problem of jerky scrolling is back :/

Matthew Leverton
Supreme Loser
January 1999
avatar

could it be a thread safety issue ?

Yes, it probably is.

You have to remember that threads can operate in any order. Thread A could finish before Thread B does anything. Or Thread B could do a lot of things before Thread A does anything. No order between the two is guaranteed.

In your case, the primary thread should not touch the bitmap until the secondary thread is finished updating it. To do that, you'll need to wait for the thread to finish via a join, and not touch the bitmap in the meantime.

William Labbett
Member #4,486
March 2004
avatar

Right. I've seen what was wrong now and fixed the issue. Thanks for explaining that. I've done some further investigating to work out why the scrolling slows down when I use a thread.

I profiled the code and there are some functions which get called a lot more than others but these are functions that only get called while a thread is running but the slowdown occurs even when the thread isn't running so I don't know what's causing it.

Quote:

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
28.57 0.02 0.02 dinkle_set_up_tiles
28.57 0.04 0.02 next_to_two_array_code
14.29 0.05 0.01 get_union_of_arrays
14.29 0.06 0.01 reflect_tile
14.29 0.07 0.01 reverse_of_tile
0.00 0.07 0.00 530 0.00 0.00 Backdrop::Get_Draw_From()
0.00 0.07 0.00 530 0.00 0.00 Backdrop::Thread_Active()
0.00 0.07 0.00 530 0.00 0.00 Backdrop::Update_Position()
0.00 0.07 0.00 530 0.00 0.00 Backdrop::Draw()
0.00 0.07 0.00 1 0.00 0.00 GameEssentials::GetBitmaps(char const*, char const*)
0.00 0.07 0.00 1 0.00 0.00 GameEssentials::GameInit()
0.00 0.07 0.00 1 0.00 0.00 GameEssentials::GameEssentials()
0.00 0.07 0.00 1 0.00 0.00 Backdrop::Make_New_Blot()
0.00 0.07 0.00 1 0.00 0.00 Backdrop::Backdrop(char const*, int&, ALLEGRO_COLOR*)

any suggestions ?

EDIT : I guess that's not a lot to go on.

The slow down starts after the first thread gets destroyed.

Matthew Leverton
Supreme Loser
January 1999
avatar

Which thread creates the bitmap? If the secondary thread is creating the bitmap, then it might not be compatible with the display.

If the primary thread creates the bitmap, and the secondary thread locks it for write, does its stuff, and unlocks it, you shouldn't have any speed disadvantages.

William Labbett
Member #4,486
March 2004
avatar

It's a secondary thread as it happens. How do I make it compatible with the display ?

Or do I need to rethink the code ?

Thanks.

Matthew Leverton
Supreme Loser
January 1999
avatar

I'm only speaking of which thread calls al_create_bitmap(). If the primary thread creates it, and passes it to the secondary thread, you should be fine.

Otherwise, you may need to do something like this to make it compatible:

That code would go in the primary thread after the secondary thread is finished. However, if you can make the primary thread be the one that calls al_create_bitmap() on the original bitmap, it wouldn't be necessary.

William Labbett
Member #4,486
March 2004
avatar

Joy. Now I know what I'm doing, maybe I can fulfil this idea afterall. Thanks :)

EDIT :

when calling al_set_target_bitmap in a secondary thread does it affect the target bitmap in the main thread ?

Trent Gamblin
Member #261
April 2000
avatar

To your edit: no. Target bitmap like some other things in A5 are per thread.

William Labbett
Member #4,486
March 2004
avatar

cheers Trent.

That's not why nothing's getting drawn on the bitmap then.

I've got this function here :

#SelectExpand
1void make_blot(ALLEGRO_BITMAP *b, ALLEGRO_BITMAP *tiles, unsigned char **tile_numbers, int w, int h, ALLEGRO_COLOR c1, ALLEGRO_COLOR c2) 2{ 3 int x, y; 4 5 al_set_target_bitmap(b); 6 7 //al_save_bitmap("all_tiles_saved.png", tiles_bitmap); 8 9 10 for(y = 0; y < h; ++y) 11 { 12 for(x = 0; x < w; ++x) 13 { 14 15 al_draw_bitmap_region(tiles, tile_numbers[y][x] << 4, 0, 16, 16, x << 4, y << 4, 0); 16 } 17 } 18 19 20}

When I use it from the main thread it works but from a secondary thread it doesn't seem to draw anything on the target bitmap.

Trent Gamblin
Member #261
April 2000
avatar

I don't think drawing is thread safe. It has to be done from the thread that created the display.

William Labbett
Member #4,486
March 2004
avatar

What if I use an ALLEGRO_LOCKED_REGION ?

Is that why matthew suggested doing that ?

Trent Gamblin
Member #261
April 2000
avatar

I don't think that'll work either. Anything tied to the OpenGL (or d3d?) context can only be accessed from one thread. Unless you mean using memory bitmaps. You can use those from multiple threads as long as you do it in a thread safe manner (a given I suppose) and you don't draw them to video bitmaps or the screen, ie the single thread for gpu stuff still applies. You can create and draw a memory bitmap in one thread and then when you're done draw it in a different thread, even to video bitmaps or screen.

William Labbett
Member #4,486
March 2004
avatar

Okay,

I thought I could use a memory bitmap in the second thread and then use al_clone_bitmap() and change it into a video bitmap back in the primary thread.

Would that work or does al_clone_bitmap ignore the current bitmap flags ?

Edgar Reynaldo
Member #8,592
May 2007
avatar

William Labbett
Member #4,486
March 2004
avatar

Cheers. I did a little test with al_get_bitmap_flags and it answered my question.

Thanks for all the help guys. This question has definitely been answered helpfully.

I've got the threads working now. I make a memory bitmap from the primary thread, then make it in the secondary and then when it's done, clone it into a video bitmap.

The scrolling works really nicely now. Still there's a bit of speed change but it's acceptable.

I'm pleased to have learnt about all this.

Thanks.

Edgar Reynaldo
Member #8,592
May 2007
avatar

If the sizes of all your bitmaps don't change, then you should create all your memory and video bitmaps in your primary thread, and just draw to the memory bitmaps in the secondary thread. When that's done draw it to your video bitmap in the primary thread so it will be acclerated when you're drawing it to the screen.

William Labbett
Member #4,486
March 2004
avatar

then make it in the secondary and then when it's done

Sorry. When I said that, I meant lock it and set the pixels.

Thomas Fjellstrom
Member #476
June 2000
avatar

I don't think drawing is thread safe. It has to be done from the thread that created the display

I would think if you surround access to that bitmap and possibly other items with a mutex, it should work unless I'm missing something.

I'm not sure why a bitmap couldn't be used in a different thread, especially if its only used there. Then it shouldn't even need a mutex.

--
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

William Labbett
Member #4,486
March 2004
avatar

I tried it but none of my al_draw_bitmap's to it seemed to do anything so I followed Trent's advice. Could there have been another reason ?

Thomas Fjellstrom
Member #476
June 2000
avatar

Hm, I seem to recall GL really hates it when you use stuff from one thread in other threads. Least I think that was one issue.

--
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

William Labbett
Member #4,486
March 2004
avatar

FWIW I'm not using GL

Go to: