RE: [AD] acquire_bitmap weirdness

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On Sun, 2006-01-01 at 20:51 -0800, Robert Ohannessian wrote:

> 
> That's a bad idea. Most apps do things like:
> 
> 
> acquire_bitmap(my_video_backbuffer);
> 
> for (i = my_sprites.begin(); i != my_sprites.end(); i++) {
> 
>     blit(i->bitmap, my_video_bitmap, ...);
> 
> }
> 
> release_bitmap(my_video_backbuffer);
> 

I would consider this broken code.. you are not supposed to use
acquire_bitmap here, under no platform. It can be sped up by simply not
using acquire_bitmap.

But what if code looks like this:

acquire_bitmap(my_video_backbuffer);
blit(i->bitmap, my_video_bitmap, ...);
for (i = 0; i < 640 * 480; i++) {
    pupixel(my_video_bitmap...)
}
release_bitmap(my_video_backbuffer);

Right now, this will be very slow, and if you move the blit one line up,
suddenly gets fast.. I find it just unaceptable from an API semantics
point of view.

> If blit() unlocks the bitmap (as it tends to do under Windows) and you
> reloc it right after, then you'll spend all the time in your loop just
> locking and unlocking the bitmap. Locks are really really slow.
> They're measured in tens of millisecond. You really don't want to do
> more than 1-2 lock/frame.

Yes. So that's the one big drawback of my proposed solution, existing
code which uses acquire_bitmap in the way of your example above will get
very slow.

Well, attached is a rework of my old acquire_bitmap patch, merely
extended with stating some of the facts about the DX driver, for now.
That should probably get applied in any case. And personally, I'm still
(slightly) in favor of changing the semantics to not have functions
(like your blit above) auto-unlock.

-- 
Elias Pschernig
Index: docs/src/allegro._tx
===================================================================
--- docs/src/allegro._tx	(revision 5629)
+++ docs/src/allegro._tx	(working copy)
@@ -4972,23 +4972,93 @@
 @xref release_bitmap, acquire_screen, release_screen
 @eref ex3buf, exaccel, expat, exquat, exscroll, exswitch, exupdate
 @shortdesc Locks the bitmap before drawing onto it.
-   Locks the specified video memory bitmap prior to drawing onto it. This 
-   does not apply to memory bitmaps, and only affects some platforms 
-   (Windows needs it, DOS does not). These calls are not strictly required, 
-   because the drawing routines will automatically acquire the bitmap before 
-   accessing it, but locking a DirectDraw surface is very slow, so you will 
-   get much better performance if you acquire the screen just once at the 
-   start of your main redraw function, and only release it when the drawing 
-   is completely finished. Multiple acquire calls may be nested, and the 
-   bitmap will only be truly released when the lock count returns to zero. 
-   Be warned that DirectX programs activate a mutex lock whenever a surface 
-   is locked, which prevents them from getting any input messages, so you 
-   must be sure to release all your bitmaps before using any timer, 
-   keyboard, or other non-graphics routines!
-   
-   Note that if you are using hardware accelerated VRAM-&gtVRAM blits, you should
-   not call acquire_bitmap().
+   Acquires the specified video memory bitmap prior to drawing onto it. You 
+   never need to call the function explicitly as it is low level, and will only 
+   give you a speed up if you know what you are doing. Using it wrongly may 
+   cause slowdown, or even lock up your program.
 
+   Note: You do never need to use acquire_bitmap on a memory bitmap, i.e. a
+   normal bitmap created with create_bitmap. It will simply do nothing in that
+   case.
+
+   It still can be useful, because e.g. under the current DirectDraw driver of
+   Allegro, some drawing functions (like putpixel) need to lock a video bitmap
+   before drawing to it. But doing this is very slow, so you will get much
+   better performance if you acquire the screen just once at the start of your
+   main redraw function, then call multiple drawing operations which need the
+   bitmap locked, and only release it when done.
+
+   Multiple acquire calls may be nested, but you must make sure to match up the
+   acquire_bitmap and release_bitmap calls. Be warned that DirectX programs
+   activate a mutex lock whenever a surface is locked, which prevents them from
+   getting any input messages, so you must be sure to release all your bitmaps
+   before using any timer, keyboard, or other non-graphics routines!
+
+   Note that if you are using hardware accelerated VRAM-&gtVRAM functions, you
+   should not call acquire_bitmap(). Such functions need an unlocked target
+   bitmap under DirectX, so there is now just the opposite case from before - if
+   the bitmap is already locked with acquire_bitmap, each single drawing
+   operation has to unlock it.
+
+   Note: For backwards compatibility, the unlocking behavior of such functions
+   is permanent. That is, if you call acquire_bitmap first, then call e.g. en
+   accelerated blit, the DirectX bitmap will be unlocked automatically.
+
+   Here is an example where it may be useful to use acquire_bitmap:
+
+   <codeblock>
+   acquire_bitmap(page);
+   for (i = 0; i < 10000; i++)
+      putpixel(page, x[i], y[i], color[i]);
+   release_bitmap(page);
+   <endblock>
+
+   In the above case, without the acquire/release pair Allegro might lock and
+   unlock the video bitmap after every call to putpixel. But now, it will only
+   do it once.
+
+   An example of *how it is used wrong*:
+
+   <codeblock>
+   acquire_bitmap(page);
+   for (i = 0; i < 10000; i++)
+       draw_sprite(page, sprite[i], x[i], y[i]);
+   release_bitmap(page);
+   <endblock>
+
+   Accelerated sprites normally can only be drawn to a not acquired video
+   bitmap, so instead of speeding up the above, acquire_bitmap slows it down to
+   a crawl if the sprites are video bitmaps themselves - since Allegro now needs
+   to un-acquire the page for every sprite.
+
+   Another example:
+
+   <codeblock>
+   acquire_bitmap(page);
+   for (i = 0; i < 10; i++)
+       circlefill(page, x[i], y[i], x[i + 1], y[i + 1], color[i]);
+   release_bitmap(page);
+   <endblock>
+
+   The circlefill function acquires the destination on its own before plotting
+   all the single pixels, so it may be pointless to acquire it manually, since
+   the acquiring may take less time than drawing the circle. And even if not,
+   with only 10 circles, you probably don't save a lot. Also, circlefill may use
+   accelerated filling, in which case the video bitmap should not be acquired at
+   all, like in the previous example.
+
+   There is no clear cross-platform way in this Allegro version to know which
+   drawing operations are accelerated or not. For example a normal rectfill most
+   probably is, but an XOR rectfill, or one with blending activated, most
+   probably is not. Rule of dumb: Never us acquire_bitmap.
+
+   And be warned again: This function can be very dangerous to use, since the
+   whole program may get locked while the bitmap is locked. So the lock should
+   only be held for a short time, and you should not call anything but drawing
+   operations onto the locked video bitmap while a lock is in place. Especially
+   don't call things like show_mouse (or scare_mouse which calls that) or
+   readkey, since that will most likely deadlock your entire program.
+
 @@void @release_bitmap(BITMAP *bmp);
 @xref acquire_bitmap, acquire_screen, release_screen
 @eref ex3buf, exaccel, expat, exquat, exscroll, exswitch, exupdate


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/