gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog gui/gtk_glue_agg.cpp gui/gtk_gl...


From: Udo Giacomozzi
Subject: [Gnash-commit] gnash ChangeLog gui/gtk_glue_agg.cpp gui/gtk_gl...
Date: Wed, 27 Jun 2007 14:22:35 +0000

CVSROOT:        /cvsroot/gnash
Module name:    gnash
Changes by:     Udo Giacomozzi <udog>   07/06/27 14:22:35

Modified files:
        .              : ChangeLog 
        gui            : gtk_glue_agg.cpp gtk_glue_agg.h 

Log message:
        implemented shared memory image blitting

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.3614&r2=1.3615
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk_glue_agg.cpp?cvsroot=gnash&r1=1.18&r2=1.19
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk_glue_agg.h?cvsroot=gnash&r1=1.8&r2=1.9

Patches:
Index: ChangeLog
===================================================================
RCS file: /cvsroot/gnash/gnash/ChangeLog,v
retrieving revision 1.3614
retrieving revision 1.3615
diff -u -b -r1.3614 -r1.3615
--- ChangeLog   27 Jun 2007 09:55:20 -0000      1.3614
+++ ChangeLog   27 Jun 2007 14:22:35 -0000      1.3615
@@ -2,6 +2,7 @@
 
        * gui/fb.cpp, gui/fltk_glue_agg.cpp, gui/gtk.cpp, gui/gui.cpp: set
          correct _validbounds  
+       * gui/gtk_glue_agg.{cpp,h}: implemented shared memory image blitting
 
 2007-06-26 Udo Giacomozzi <address@hidden>
 

Index: gui/gtk_glue_agg.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gtk_glue_agg.cpp,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- gui/gtk_glue_agg.cpp        26 Jun 2007 17:40:09 -0000      1.18
+++ gui/gtk_glue_agg.cpp        27 Jun 2007 14:22:35 -0000      1.19
@@ -18,21 +18,33 @@
 //
 //
 
-/* $Id: gtk_glue_agg.cpp,v 1.18 2007/06/26 17:40:09 udog Exp $ */
+/* $Id: gtk_glue_agg.cpp,v 1.19 2007/06/27 14:22:35 udog Exp $ */
 
 
-/*
+/// \page gtk_shm_support GTK shared memory extension support
+/// 
+/// The GTK-AGG combination supports the use of the X11 MIT-SHM extension.
+/// This extension allows passing image data to the X server in it's native
+/// format (defined by the graphics mode). This prevents CPU intensive pixel
+/// format conversions for the X server.
+///
+/// Not all X servers support this extension and it's available for local
+/// (not networked) X connections anyway. So the GTK GUI will first *try*
+/// to use the extension and on failure provide automatic fallback to standard
+/// pixmaps.
+///
+/// You won't notice this fallback unless you check the log messages (aside
+/// from potential performance difference.)
+///
+/// The macro ENABLE_MIT_SHM must be defined in gtk_glue_agg.h to enable
+/// support for the MIT-SHM extension.
+///
+/// For more information about the extension, have a look at these URLs:
+/// http://en.wikipedia.org/wiki/MIT-SHM
+/// http://www.xfree86.org/current/mit-shm.html  
 
-TODO: Support MIT-SHM to push image data more quickly on screen, avoiding
-overhead by X Server IPC.
 
-References:
-  http://en.wikipedia.org/wiki/MIT-SHM
-  http://www.xfree86.org/current/mit-shm.html
-
-Also worth checking:
-  http://en.wikipedia.org/wiki/X_video_extension
-*/
+// Also worth checking: http://en.wikipedia.org/wiki/X_video_extension
 
 
 #include <cstdio>
@@ -71,7 +83,11 @@
 
 GtkAggGlue::~GtkAggGlue()
 {
+  if (_offscreenbuf) {
   free(_offscreenbuf);
+    _offscreenbuf=NULL;
+  }
+  
   destroy_shm_image();
 }
 
@@ -128,25 +144,78 @@
 GtkAggGlue::create_shm_image(unsigned int width, unsigned int height)
 {
 
-  //Visual xvisual = ((GdkVisualPrivate*) visual)->xvisual; 
+  // destroy any already existing structures
+  destroy_shm_image();
+
+#ifdef ENABLE_MIT_SHM
+  GdkVisual* visual = gdk_drawable_get_visual(_drawing_area->window);
+  Visual* xvisual = GDK_VISUAL_XVISUAL(visual); 
+  
+  // prepare segment info (populated by XShmCreateImage)
+  _shm_info = (XShmSegmentInfo*) malloc(sizeof(XShmSegmentInfo));  
+  assert(_shm_info != NULL);
+  
+  // create shared memory XImage
+  _shm_image = XShmCreateImage(gdk_display, xvisual, visual->depth, 
+    ZPixmap, NULL, _shm_info, width, height);
 
+  if (!_shm_image) {
+    log_msg("Failed creating the shared memory XImage!");
   destroy_shm_image();
+    return;
+  }
+  
+  // create shared memory segment
+  _shm_info->shmid = shmget(IPC_PRIVATE, 
+    _shm_image->bytes_per_line * _shm_image->height, IPC_CREAT|0777);
+    
+  if (_shm_info->shmid == -1) {
+    log_msg("Failed requesting shared memory segment (%s). Perhaps the "
+      "required memory size is bigger than the limit set by the kernel.",
+      strerror(errno));
+    destroy_shm_image();
+    return;
+  }
   
-  /*if (!_shm_info) {
-    _shm_info = malloc(sizeof XShmSegmentInfo);
-  }*/ 
+  // attach the shared memory segment to our process
+  _shm_info->shmaddr = _shm_image->data = (char*) shmat(_shm_info->shmid, 0, 
0);
+  
+  if (_shm_info->shmaddr == (char*) -1) {
+    log_msg("Failed attaching to shared memory segment: %s", strerror(errno));
+    destroy_shm_image();
+    return;
+  }
+  
+  // Give the server full access to our memory segment. We just follow
+  // the documentation which recommends this, but we could also give him
+  // just read-only access since we don't need XShmGetImage...
+  _shm_info->readOnly = False;
+  
+  // Finally, tell the server to attach to our shared memory segment  
+  if (!XShmAttach(gdk_display, _shm_info)) {
+    log_msg("Server failed attaching to the shared memory segment");
+    destroy_shm_image();
+    return;
+  }
+  
+  //log_msg("create_shm_image() OK"); // <-- remove this
+#endif
   
-  //_shm_image = XShmCreateImage();
 }
 
 void 
 GtkAggGlue::destroy_shm_image()
 {
 #ifdef ENABLE_MIT_SHM
-  if (!_shm_image) return; // not allocated
-  
+  if (_shm_image) {  
   XDestroyImage(_shm_image);
   _shm_image=NULL;
+  }
+  
+  if (_shm_info) {
+    free(_shm_info);
+    _shm_info=NULL;
+  }
   
 #endif
 }
@@ -163,18 +232,40 @@
 #ifdef ENABLE_MIT_SHM
   GdkVisual *visual = gdk_drawable_get_visual(_drawing_area->window);
   
+  // Create a dummy SHM image to detect it's pixel format (we can't use the 
+  // info from "visual"). 
+  // Is there a better way??
+  
+  create_shm_image(256,256);
+  
+  if (!_shm_image) return NULL;
+  
+  unsigned int red_shift, red_prec;
+  unsigned int green_shift, green_prec;
+  unsigned int blue_shift, blue_prec;
+
+  decode_mask(_shm_image->red_mask,   &red_shift,   &red_prec);
+  decode_mask(_shm_image->green_mask, &green_shift, &green_prec);
+  decode_mask(_shm_image->blue_mask,  &blue_shift,  &blue_prec);
+  
+  
+  log_msg("X server pixel format is (R%d:%d, G%d:%d, B%d:%d, %d bpp)",
+    red_shift, red_prec,
+    green_shift, green_prec,
+    blue_shift, blue_prec,
+    _shm_image->bits_per_pixel);
+  
+  
   char *pixelformat = agg_detect_pixel_format(
-    visual->red_shift, visual->red_prec,
-    visual->green_shift, visual->green_prec,
-    visual->blue_shift, visual->blue_prec,
-    visual->depth); 
+    red_shift, red_prec,
+    green_shift, green_prec,
+    blue_shift, blue_prec,
+    _shm_image->bits_per_pixel);
+    
+  destroy_shm_image();
 
   if (!pixelformat) {
-    log_msg("Pixel format of X server not recognized (%d:%d, %d:%d, %d:%d, %d 
bpp)",
-      visual->red_shift, visual->red_prec,
-      visual->green_shift, visual->green_prec,
-      visual->blue_shift, visual->blue_prec,
-      visual->depth);
+    log_msg("Pixel format of X server not recognized!");
     return NULL; 
   }
   
@@ -182,11 +273,15 @@
   
   render_handler* res = create_render_handler_agg(pixelformat);
   
-  if (!res) 
+  if (!res) {
     log_msg("Failed creating a renderer instance for this pixel format. "
       "Most probably Gnash has not compiled in (configured) support "
       "for this pixel format - using standard pixmaps instead");      
   
+    // disable use of shared memory pixmaps
+    _have_shm = false;
+  }      
+  
   
   return res;
     
@@ -200,8 +295,10 @@
 {
 
   // try with MIT-SHM
+  if (_have_shm) {
   _agg_renderer = create_shm_handler();
   if (_agg_renderer) return _agg_renderer;
+  }
 
 #ifdef PIXELFORMAT_RGB565
 #warning A pixel format of RGB565; you must have a (hacked) GTK which supports 
\
@@ -222,11 +319,41 @@
 
        #define CHUNK_SIZE (100*100*(_bpp/8))
        
-       create_shm_image(width, height);
-
        if (width == _width && height == _height)
           return;
           
+  _width = width;
+       _height = height;
+          
+          
+       // try shared image first
+       if (_have_shm)
+         create_shm_image(width, height);
+         
+#ifdef ENABLE_MIT_SHM
+       if (_shm_image) {
+       
+         // ==> use shared memory image (faster)
+         
+         log_msg("GTK-AGG: Using shared memory image");
+    
+    if (_offscreenbuf) {  
+      free(_offscreenbuf);
+      _offscreenbuf = NULL;
+    }
+         
+       static_cast<render_handler_agg_base *>(_agg_renderer)->init_buffer(
+         (unsigned char*) _shm_info->shmaddr,
+               _shm_image->bytes_per_line * _shm_image->height,
+               _width,
+               _height
+       );
+       
+  } else {
+#endif         
+  
+    // ==> use standard pixmaps (slower, but should work in any case)
+
        int new_bufsize = width*height*(_bpp/8);
        
        // TODO: At the moment we only increase the buffer and never decrease 
it. Should be
@@ -249,9 +376,6 @@
                memset(_offscreenbuf, 0, new_bufsize);
        }
 
-  _width = width;
-       _height = height;
-
        // Only the AGG renderer has the function init_buffer, which is *not* 
part of
        // the renderer api. It allows us to change the renderers movie size 
(and buffer
        // address) during run-time.
@@ -262,11 +386,50 @@
                _height
        );
        
+       
+#ifdef ENABLE_MIT_SHM
+  }
+#endif  
+       
 }
 
 void
 GtkAggGlue::render()
 {
+
+#ifdef ENABLE_MIT_SHM
+  if (_shm_image) {
+  
+    XShmPutImage(
+      gdk_display, 
+      GDK_WINDOW_XWINDOW(_drawing_area->window), 
+      GDK_GC_XGC(_drawing_area->style->fg_gc[GTK_STATE_NORMAL]),  // ???
+      _shm_image,
+      0, 0,
+      0, 0,
+      _width, _height,
+      False); 
+      
+      // <Udo>:
+      // The shared memory buffer is copied in background(!) since the X 
+      // calls are executed asynchroneously. This is dangerous because it
+      // may happen that the renderer updates the buffer while the X server
+      // still copies the data to the VRAM (flicker can occurr).
+      // Normally this is avoided using the XShmCompletionEvent which is sent
+      // to the client once the buffer has been copied. The last argument to
+      // XShmPutImage must be set to True for this. 
+      // We'd need to wait for this event before calling the renderer again.
+      // I know nothing about X event handling and so I just call XSync here
+      // to wait until all commands have been executed. This has the 
+      // disadvantage that we can't leave the X server some time till the core 
+      // is ready to *render* the next frame. I don't think it would make a 
+      // significant performance difference unless data to video ram is very 
+      // slow (could be the case for old / embedded computers, though).       
+      XSync(gdk_display, False);
+
+  } else {
+#endif  
+
        // Update the entire screen
        gdk_draw_rgb_image (
                _drawing_area->window,
@@ -280,12 +443,34 @@
                (int)(_width*_bpp/8)
        );
        
+#ifdef ENABLE_MIT_SHM
+  }
+#endif  
+       
 }
 
 void
 GtkAggGlue::render(int minx, int miny, int maxx, int maxy)
 {
 
+#ifdef ENABLE_MIT_SHM
+  if (_shm_image) {
+  
+    XShmPutImage(
+      gdk_display, 
+      GDK_WINDOW_XWINDOW(_drawing_area->window), 
+      GDK_GC_XGC(_drawing_area->style->fg_gc[GTK_STATE_NORMAL]),  // ???
+      _shm_image,
+      minx, miny,
+      minx, miny,
+               maxx-minx+1, maxy-miny+1,
+      False);
+      
+    XSync(gdk_display, False); // see GtkAggGlue::render(void)
+  
+  } else {
+#endif       
+
        // Update only the invalidated rectangle
        gdk_draw_rgb_image (
                _drawing_area->window,
@@ -298,6 +483,10 @@
                _offscreenbuf + miny*(_width*(_bpp/8)) + minx*(_bpp/8),
                (int)((_width)*_bpp/8)
        );
+       
+#ifdef ENABLE_MIT_SHM
+  }
+#endif  
 }
 
 void
@@ -308,6 +497,24 @@
 }
 
 
+void 
+GtkAggGlue::decode_mask(unsigned long mask, unsigned int *shift, unsigned int 
*size)
+{
+  *shift = 0;
+  *size = 0;
+  
+  if (mask==0) return; // invalid mask
+  
+  while (!(mask & 1)) {
+    (*shift)++;
+    mask = mask >> 1;
+  }
+  
+  while (mask & 1) {
+    (*size)++;
+    mask = mask >> 1;
+  }
+}
 
 } // namespace gnash
 

Index: gui/gtk_glue_agg.h
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gtk_glue_agg.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- gui/gtk_glue_agg.h  26 Jun 2007 17:40:09 -0000      1.8
+++ gui/gtk_glue_agg.h  27 Jun 2007 14:22:35 -0000      1.9
@@ -20,7 +20,7 @@
 
 // Define this macro to enable experimental support for MIT-SHM
 // see http://www.xfree86.org/current/mit-shm.html
-//#define ENABLE_MIT_SHM 1
+#define ENABLE_MIT_SHM 1
 
 #include "gtk_glue.h"
 
@@ -67,7 +67,8 @@
     ///
     /// This can still fail even if check_mit_shm() returned true in case
     /// we have not the appropriate pixel format compiled in or any other
-    /// error happened.  
+    /// error happened. create_shm_image() replaces (destroys) an already
+    /// allocated SHM image.
     void create_shm_image(unsigned int width, unsigned int height);
     
     /// Destroys a previously created SHM image (deals with NULL pointer)
@@ -77,6 +78,10 @@
     /// format. Returns NULL on failure.
     render_handler *create_shm_handler();    
     
+    // converts a bitmask to a shift/size information (used for pixel format
+    // detection)
+    void decode_mask(unsigned long mask, unsigned int *shift, unsigned int 
*size);
+    
 };
 
 } // namespace gnash




reply via email to

[Prev in Thread] Current Thread [Next in Thread]