Re: [AD] Progress report

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


Peter Hull wrote:
Also I will need Milan's display/bitmap management thing to avoid
crashes (if it's not ready, I can hack it by retaining the GL context
until the app terminates)

Here. Try this patch. All you have to do is to add the code to osx destroy_display() function similar to what this patch adds to GLX. Add that before destroying the context. It will convert all display bitmaps to display independent (memory) bitmaps if the last display is being destroyed.

Another thing, I noticed that glxCreateContext cannot return NULL because of invalid shared_list argument. That error is on the server-side so I take it that it must succeed. I don't even know how to check for server-side errors. Because of this all GLX bitmaps are compatible so I didn't do any compability IDs... You'll have to do that yourself. Just make all the displays sharing resources have the same ID and check that in is_compatible_bitmap().



Notes about the patch:
* manages a vector of bitmaps for every ALLEGRO_DISPLAY. This is driver independent.

* it adds a internal function to convert a display bitmap to memory bitmap: _al_convert_to_memory_bitmap().

* because _al_convert_to_memory_bitmap() removes the item from the display bitmap vector, a temporary vector is needed while looping trough the vector and calling this function.

* a realloc in _al_convert_to_memory_bitmap() is commented out and it will cause small memory leaks (I'm not sure if that is technically a memory leak since destroying a bitmap will free the memory). The problem with this realloc() is that I don't know If I can assume that the pointer passed to it wont change.


--
Milan Mimica
http://sparklet.sf.net
Index: src/xglx/xdisplay.c
===================================================================
--- src/xglx/xdisplay.c	(revision 10191)
+++ src/xglx/xdisplay.c	(working copy)
@@ -244,20 +244,36 @@
 
 static void xdpy_destroy_display(ALLEGRO_DISPLAY *d)
 {
-   unsigned int i;
    ALLEGRO_SYSTEM_XGLX *s = (void *)al_system_driver();
    ALLEGRO_DISPLAY_XGLX *glx = (void *)d;
 
+   /* If we're the last display, convert all bitmpas to display independent
+    * (memory) bitmaps. */
+   if (s->system.displays._size == 1) {
+      size_t i;
+      _AL_VECTOR bitmaps;
+
+      /* We need a local copy of the bitmap vector because
+      * _al_convert_to_memory_bitmap() destroys the bitmap removing the item
+      * from the vector while we loop trough it. */
+      _al_vector_init(&bitmaps, sizeof(ALLEGRO_BITMAP*));
+      for (i = 0; i < d->bitmaps._size; i++) {
+         ALLEGRO_BITMAP **bmp = _al_vector_alloc_back(&bitmaps);
+         *bmp = *((ALLEGRO_BITMAP **)_al_vector_ref(&d->bitmaps, i));
+      }
+
+      for (i = 0; i < bitmaps._size; i++) {
+         ALLEGRO_BITMAP **bmp = _al_vector_ref(&bitmaps, i);
+         _al_convert_to_memory_bitmap(*bmp);
+      }
+
+      _al_vector_free(&bitmaps);
+   }
+
    _al_ogl_unmanage_extensions((ALLEGRO_DISPLAY_OGL*)glx);
 
    _al_mutex_lock(&s->lock);
-   for (i = 0; i < _al_vector_size(&s->system.displays); i++) {
-      ALLEGRO_DISPLAY_XGLX **dptr = _al_vector_ref(&s->system.displays, i);
-      if (glx == *dptr) {
-         _al_vector_delete_at(&s->system.displays, i);
-         break;
-      }
-   }
+   _al_vector_find_and_delete(&s->system.displays, &d);
    XDestroyWindow(s->xdisplay, glx->window);
 
    if (d->flags & ALLEGRO_FULLSCREEN)
@@ -436,6 +452,7 @@
 static bool xdpy_is_compatible_bitmap(ALLEGRO_DISPLAY *display,
    ALLEGRO_BITMAP *bitmap)
 {
+   /* All GLX bitmaps are compatible. */
    return true;
 }
 
@@ -500,7 +517,6 @@
 }
 
 
-
 /* Obtain a reference to this driver. */
 ALLEGRO_DISPLAY_INTERFACE *_al_display_xglx_driver(void)
 {
Index: src/win/wgl_disp.c
===================================================================
--- src/win/wgl_disp.c	(revision 10191)
+++ src/win/wgl_disp.c	(working copy)
@@ -980,7 +980,27 @@
 {
    ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_system_driver();
    ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)disp;
+   size_t i;
+   _AL_VECTOR bitmaps;
 
+   /* We need a local copy of the bitmap vector because
+    * _al_convert_to_memory_bitmap() destroys the bitmap from the driver side
+    * removing the item from the vector while we loop trough it. */
+   _al_vector_init(&bitmaps, sizeof(ALLEGRO_BITMAP*));
+   for (i = 0; i < wgl_disp->bitmaps._size; i++) {
+      ALLEGRO_BITMAP **bmp = _al_vector_alloc_back(&bitmaps);
+      *bmp = *((ALLEGRO_BITMAP **)_al_vector_ref(&wgl_disp->bitmaps, i));
+   }
+
+   /* We need to convert all our bitmaps to display independent (memory)
+    * bitmaps because WGL driver doesn't support sharing of resources. */
+   for (i = 0; i < bitmaps._size; i++) {
+      ALLEGRO_BITMAP **bmp = _al_vector_ref(&bitmaps, i);
+      _al_convert_to_memory_bitmap(*bmp);
+   }
+
+   _al_vector_free(&bitmaps);
+
    destroy_display_internals(wgl_disp);
    _al_vector_find_and_delete(&system->system.displays, &disp);
    gfx_driver = 0;
@@ -1232,7 +1252,11 @@
 
 static bool wgl_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
 {
-   return true;
+   /* Note: WGL driver doesn't support sharing of resources between contexts,
+    * thus all bitmaps are tied to the display which was current at the time
+    * al_create_bitmap was called.
+    */
+   return display == bitmap->display;
 }
 
 
Index: src/display_new.c
===================================================================
--- src/display_new.c	(revision 10191)
+++ src/display_new.c	(working copy)
@@ -62,8 +62,12 @@
    ALLEGRO_SYSTEM *system = al_system_driver();
    ALLEGRO_DISPLAY_INTERFACE *driver = system->vt->get_display_driver();
    ALLEGRO_DISPLAY *display = driver->create_display(w, h);
+
    if (!display)
       return NULL;
+
+   _al_vector_init(&display->bitmaps, sizeof(ALLEGRO_BITMAP*));
+
    {
    ALLEGRO_COLOR black = al_map_rgba(0, 0, 0, 0);
    al_set_current_display(display);
@@ -84,6 +88,7 @@
 void al_destroy_display(ALLEGRO_DISPLAY *display)
 {
    display->vt->destroy_display(display);
+   _al_vector_free(&display->bitmaps);
 }
 
 
Index: src/bitmap_new.c
===================================================================
--- src/bitmap_new.c	(revision 10191)
+++ src/bitmap_new.c	(working copy)
@@ -28,8 +28,7 @@
 
 
 
-/* Creates a memory bitmap. A memory bitmap can only be drawn to other memory
- * bitmaps, not to a display.
+/* Creates a memory bitmap.
  */
 static ALLEGRO_BITMAP *_al_create_memory_bitmap(int w, int h)
 {
@@ -116,7 +115,8 @@
 ALLEGRO_BITMAP *al_create_bitmap(int w, int h)
 {
    ALLEGRO_BITMAP *bitmap;
-   
+   ALLEGRO_BITMAP **back;
+
    if ((al_get_new_bitmap_flags() & ALLEGRO_MEMORY_BITMAP) ||
          (_al_current_display->vt->create_bitmap == NULL)) {
       return _al_create_memory_bitmap(w, h);
@@ -158,6 +158,11 @@
       return NULL;
    }
 
+   /* We keep a list of bitmaps depending on the current display so that we can
+    * convert them to memory bimaps when the display is destroyed. */
+   back = _al_vector_alloc_back(&_al_current_display->bitmaps);
+   *back = bitmap;
+
    return bitmap;
 }
 
@@ -176,6 +181,8 @@
 
    if (bitmap->parent) {
       /* It's a sub-bitmap */
+      if (bitmap->display)
+         _al_vector_find_and_delete(&bitmap->display->bitmaps, &bitmap);
       _AL_FREE(bitmap);
       return;
    }
@@ -193,6 +200,8 @@
    if (bitmap->vt)
       bitmap->vt->destroy_bitmap(bitmap);
 
+   _al_vector_find_and_delete(&bitmap->display->bitmaps, &bitmap);
+
    if (bitmap->memory)
       _AL_FREE(bitmap->memory);
 
@@ -726,6 +735,14 @@
    bitmap->yofs = y;
    bitmap->memory = NULL;
 
+   if (bitmap->display) {
+      /* We keep a list of bitmaps depending on the current display so that we can
+      * convert them to memory bimaps when the display is destroyed. */
+      ALLEGRO_BITMAP **back;
+      back = _al_vector_alloc_back(&bitmap->display->bitmaps);
+      *back = bitmap;
+   }
+
    return bitmap;
 }
 
@@ -776,4 +793,75 @@
    return bitmap->locked;
 }
 
+
+/* Converts a display bitmap to a memory bitmap preserving its contents.
+ * Driver specific resources occupied by the display bitmap are freed.
+ * A converted sub bitmap is invalid until its parent is converted.
+ */
+void _al_convert_to_memory_bitmap(ALLEGRO_BITMAP *bitmap)
+{
+   ALLEGRO_BITMAP *tmp;
+
+   /* Do nothing if it is a memory bitmap already. */
+   if (bitmap->flags & ALLEGRO_MEMORY_BITMAP)
+      return;
+
+   if (bitmap->parent) {
+      _al_vector_find_and_delete(&bitmap->display->bitmaps, &bitmap);
+
+      /* Trim the driver-specific data for sub bitmaps. */
+      //REVIEW: will the pointer stay the same after this? Not a real memory
+      //leak anyway.
+      //_AL_REALLOC(bitmap, sizeof(ALLEGRO_BITMAP));
+
+      bitmap->display = NULL;
+      bitmap->flags &= ALLEGRO_MEMORY_BITMAP;
+      return;
+   }
+
+   /* Allocate a temporary bitmap which will hold the data
+    * during the conversion process. */
+   _al_push_new_bitmap_parameters();
+   al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
+   al_set_new_bitmap_format(bitmap->format);
+   tmp = al_create_bitmap(bitmap->w, bitmap->h);
+   _al_pop_new_bitmap_parameters();
+
+   _al_push_target_bitmap();
+
+   /* Preserve bitmap contents. */
+   al_set_target_bitmap(tmp);
+   al_draw_bitmap(bitmap, 0, 0, 0);
+   tmp->cb = bitmap->cb;
+   tmp->cr = bitmap->cr;
+   tmp->cl = bitmap->cl;
+   tmp->ct = bitmap->ct;
+
+   _al_pop_target_bitmap();
+
+   /* Destroy the display bitmap to free driver-specific resources. */
+   if (bitmap->vt)
+      bitmap->vt->destroy_bitmap(bitmap);
+
+   _al_vector_find_and_delete(&bitmap->display->bitmaps, &bitmap);
+
+   /* Put the contents back to the bitmap. */
+   bitmap->format = tmp->format;
+   bitmap->flags = tmp->flags;
+   bitmap->pitch = tmp->pitch;
+   bitmap->display = NULL;
+   bitmap->locked = false;
+   bitmap->w = tmp->w;
+   bitmap->h = tmp->h;
+   bitmap->cl = tmp->cl;
+   bitmap->ct = tmp->ct;
+   bitmap->cr = tmp->cr;
+   bitmap->cb = tmp->cb;
+   bitmap->parent = NULL;
+   bitmap->xofs = bitmap->yofs = 0;
+   bitmap->memory = tmp->memory;
+
+   _AL_FREE(tmp);
+}
+
 /* vim: set ts=8 sts=3 sw=3 et: */
Index: include/allegro5/internal/aintern_bitmap.h
===================================================================
--- include/allegro5/internal/aintern_bitmap.h	(revision 10191)
+++ include/allegro5/internal/aintern_bitmap.h	(working copy)
@@ -109,6 +109,7 @@
 void _al_convert_to_compat_bitmap(
 	ALLEGRO_BITMAP *src,
         BITMAP *dst);
+void _al_convert_to_memory_bitmap(ALLEGRO_BITMAP *bitmap);
 int _al_get_pixel_value(int src_format, ALLEGRO_COLOR *src_color);
 int _al_get_compat_bitmap_format(BITMAP *bmp);
 bool _al_format_has_alpha(int format);
Index: include/allegro5/internal/aintern_display.h
===================================================================
--- include/allegro5/internal/aintern_display.h	(revision 10191)
+++ include/allegro5/internal/aintern_display.h	(working copy)
@@ -61,6 +61,8 @@
    int refresh_rate;
    int flags;
    int w, h;
+
+   _AL_VECTOR bitmaps; /* A list of bitmaps created for this display. */
 };
 
 #define _al_current_display al_get_current_display()
Index: examples/exnew_multiwin.c
===================================================================
--- examples/exnew_multiwin.c	(revision 10191)
+++ examples/exnew_multiwin.c	(working copy)
@@ -85,6 +85,8 @@
 
          al_flip_display();
       }
+
+      al_rest(0.01);
    }
 
    al_destroy_bitmap(pictures[0]);


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