gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r10275: Use GdkImage instead of fidd


From: Bastiaan Jacques
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10275: Use GdkImage instead of fiddling with MIT-SHM and Xlib directly.
Date: Thu, 13 Nov 2008 21:57:26 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10275
committer: Bastiaan Jacques <address@hidden>
branch nick: trunk
timestamp: Thu 2008-11-13 21:57:26 +0100
message:
  Use GdkImage instead of fiddling with MIT-SHM and Xlib directly.
modified:
  gui/gtk_glue_agg.cpp
  gui/gtk_glue_agg.h
    ------------------------------------------------------------
    revno: 10273.1.1
    committer: Bastiaan Jacques <address@hidden>
    branch nick: mitshm
    timestamp: Thu 2008-11-13 21:55:48 +0100
    message:
      Use GdkImage instead of fiddling with MIT-SHM and Xlib directly.
    modified:
      gui/gtk_glue_agg.cpp
      gui/gtk_glue_agg.h
=== modified file 'gui/gtk_glue_agg.cpp'
--- a/gui/gtk_glue_agg.cpp      2008-11-07 10:57:27 +0000
+++ b/gui/gtk_glue_agg.cpp      2008-11-13 20:55:48 +0000
@@ -19,29 +19,10 @@
 
 /// \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  
-
-
-// Also worth checking: http://en.wikipedia.org/wiki/X_video_extension
-
+/// We use GdkImage to manage the rendering buffer for us. It supports
+/// automatic detection and usage of MIT-ShM, so we don't have to worry about
+/// it beyond synchronising the screen before rendering.
+ 
 #include <cerrno>
 #include <exception>
 #include <gtk/gtk.h>
@@ -53,187 +34,26 @@
 #include "render_handler_agg.h"
 #include "gtk_glue_agg.h"
 
-#ifdef ENABLE_MIT_SHM
-#include <X11/Xlib.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <X11/extensions/XShm.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkprivate.h>
-#endif
-
-
 namespace gnash
 {
 
-GtkAggGlue::GtkAggGlue() :
-    _offscreenbuf(NULL),
-    _offscreenbuf_size(0),
-    _agg_renderer(NULL),
-    _width(0),
-    _height(0),
-    _bpp(0),
-    _have_shm(false)
-#ifdef ENABLE_MIT_SHM
-  ,_shm_image(NULL)
-  ,_shm_info(NULL)
-#endif    
+GtkAggGlue::GtkAggGlue()
+:   _offscreenbuf(NULL),
+    _agg_renderer(NULL)
 {
 }
 
 GtkAggGlue::~GtkAggGlue()
 {
-    destroy_shm_image();
+    if (_offscreenbuf) {
+        gdk_image_destroy(_offscreenbuf);
+    }
 }
 
 bool
 GtkAggGlue::init(int /*argc*/, char **/*argv*/[])
 {
-    gdk_rgb_init();
-    
-#ifdef ENABLE_MIT_SHM
-    _have_shm = check_mit_shm(gdk_display);
-#else
-    _have_shm = false;
-#endif
-    
-    if (!detect_pixelformat()) {
-        // Perhaps this should be logged independently of verbosity. In this
-        // case use std::cerr.
-        log_error("FATAL: Could not detect the pixel format used by your X 
server.");
-        log_error("Please report this problem to the Gnash developer team.");
-        return false;
-    }
-    
-    log_debug("Your X server expects %s pixmap data for standard mode.", 
_pixelformat);
-    
-    return true;
-}
-
-bool 
-#ifdef ENABLE_MIT_SHM
-GtkAggGlue::check_mit_shm(Display *display) 
-#else
-GtkAggGlue::check_mit_shm(void* /*display*/) 
-#endif
-{
-#ifdef ENABLE_MIT_SHM
-    int major, minor, dummy;
-    Bool pixmaps;
-  
-    log_debug("Checking support for MIT-SHM...");
-  
-    if (!XQueryExtension(display, "MIT-SHM", &dummy, &dummy, &dummy)) {
-        log_debug("WARNING: No MIT-SHM extension available, using standard 
XLib "
-        "calls (slower)");
-        return false;
-    }
-  
-    if (XShmQueryVersion(display, &major, &minor, &pixmaps )!=True) {
-        log_debug("WARNING: MIT-SHM not ready (network link?), using standard 
XLib "
-          "calls (slower)");
-        return false;
-    }
-    
-    log_debug("NOTICE: MIT-SHM available (version %d.%d)!", major, minor);
-    
-    return true;
-    
-#else
-    return false; // !ifdef ENABLE_MIT_SHM
-#endif
-  
-}
-
-void 
-GtkAggGlue::create_shm_image(
-#ifdef ENABLE_MIT_SHM
-    unsigned int width, unsigned int height
-#else
-    unsigned int, unsigned int
-#endif
-    )
-{
-
-    // 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_debug("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_debug("Failed requesting shared memory segment (%s). Perhaps the "
-          "required memory size is bigger than the limit set by the kernel.",
-           std::strerror(errno));
-        destroy_shm_image();
-        return;
-    }
-  
-      // 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_debug("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_debug("Server failed attaching to the shared memory segment");
-        destroy_shm_image();
-        return;
-    }
-    // allows below to work. bug fix by cliff (bug #24692)
-    XSync(gdk_display, False);
-
-    // mark segment for automatic destruction after last process detaches
-    shmctl(_shm_info->shmid, IPC_RMID, 0);
-  
-    //log_debug("create_shm_image() OK"); // <-- remove this
-#endif // ENABLE_MIT_SHM
-   
-}
-
-void 
-GtkAggGlue::destroy_shm_image()
-{
-#ifdef ENABLE_MIT_SHM
-    if (_shm_image) {  
-        XDestroyImage(_shm_image);
-        _shm_image=NULL;
-    }
-  
-    if (_shm_info) {
-        free(_shm_info);
-        _shm_info=NULL;
-    }
-
-#endif
+    return true;
 }
 
 void
@@ -246,124 +66,26 @@
     gtk_widget_set_double_buffered(_drawing_area, FALSE);
 }
 
-bool 
-GtkAggGlue::detect_pixelformat() 
-{
-
-  // By definition, GTK/GDK *always* expects RGB24 data for 
-  // gdk_draw_rgb_image(). However, we want to support the OLPC which uses a 
-  // hacked GTK that works with RGB565 data.
-  
-#ifdef PIXELFORMAT_RGB24   // normal case 
-  
-    _bpp = 24;
-    _pixelformat = "RGB24";
-    return true;
-
-#else
-
-#ifdef PIXELFORMAT_RGB565  // OLPC
-
-#warning A pixel format of RGB565; you must have a (hacked) GTK which supports 
\
-         this format (e.g., GTK on the OLPC).
-                  
-    _bpp = 16;
-    _pixelformat = "RGB565";
-    return true;
-  
-#else
-
-#warning GTK GUI requires --with-pixelformat=RGB24 for AGG renderer
- 
-    log_error("Missing a supported pixel format for GTK GUI. You probably want 
to "
-              "configure --with-pixelformat=RGB24");
-    return false;   
-
-#endif  //ifdef PIXELFORMAT_RGB565   
- 
-#endif  //ifdef PIXELFORMAT_RGB24
-  
-  
-}
-
 render_handler*
-GtkAggGlue::create_shm_handler()
+GtkAggGlue::createRenderHandler()
 {
-#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;
-
-    decodeMask(_shm_image->red_mask, red_shift, red_prec);
-    decodeMask(_shm_image->green_mask, green_shift, green_prec);
-    decodeMask(_shm_image->blue_mask, blue_shift, blue_prec);
-
-  
-    log_debug("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);
-  
-  
+    GdkVisual* wvisual = gdk_drawable_get_visual(_drawing_area->window);
+
+    GdkImage* tmpimage = gdk_image_new (GDK_IMAGE_FASTEST, wvisual, 1, 1);
+
+    const GdkVisual* visual = tmpimage->visual;
+
+    // FIXME: we use bpp instead of depth, because depth doesn't appear to
+    // include the padding byte(s) the GdkImage actually has.
     const char *pixelformat = agg_detect_pixel_format(
-            red_shift, red_prec,
-            green_shift, green_prec,
-            blue_shift, blue_prec,
-            _shm_image->bits_per_pixel);
-
-    destroy_shm_image();
-
-    if (!pixelformat) {
-        log_debug("Pixel format of X server not recognized!");
-
-        // disable use of shared memory pixmaps
-        _have_shm = false;
-
-        return NULL; 
-    }
-
-    log_debug("X server is using %s pixel format", pixelformat);
-
-    render_handler* res = create_render_handler_agg(pixelformat);
-  
-    if (!res) {
-        log_debug("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;
-    
-#else
-    return NULL;
-#endif
-}
-
-render_handler*
-GtkAggGlue::createRenderHandler()
-{
-    // try with MIT-SHM
-    if (_have_shm) {
-        _agg_renderer = create_shm_handler();
-        if (_agg_renderer) return _agg_renderer;
-    }
-
-    _agg_renderer = create_render_handler_agg(_pixelformat.c_str());
+        visual->red_shift, visual->red_prec,
+        visual->green_shift, visual->green_prec,
+        visual->blue_shift, visual->blue_prec,
+        tmpimage->bpp * 8);
+
+    gdk_image_destroy(tmpimage);
+
+    _agg_renderer = create_render_handler_agg(pixelformat);
     return _agg_renderer;
 }
 
@@ -373,195 +95,60 @@
     assert(width > 0);
     assert(height > 0);
     assert(_agg_renderer != NULL);
-
-    static const size_t chunkSize = 100 * 100 * (_bpp / 8);
-    
-    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_debug("GTK-AGG: Using shared memory image");
-          
-        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,
-                _shm_image->bytes_per_line
-        );
-    
-    }
-    else {
-#endif      
-  
-        // ==> use standard pixmaps (slower, but should work in any case)
-        size_t newBufferSize = width * height * ((_bpp + 7) / 8);
-          
-        // Reallocate the buffer when it shrinks or grows.
-        if (newBufferSize != _offscreenbuf_size) {
-
-            newBufferSize = (newBufferSize / chunkSize + 1) * chunkSize;
-
-            try {
-                  _offscreenbuf.reset(new unsigned char[newBufferSize]);
-                  log_debug("GTK-AGG %i bytes offscreen buffer allocated", 
newBufferSize);
-            }
-            catch (std::bad_alloc &e)
-            {
-                log_error("Could not allocate %i bytes for offscreen buffer: 
%s",
-                      newBufferSize, e.what());
-                      
-                  // TODO: what to do here? An assertion in 
render_handler_agg.cpp
-                  // fails if we just return.
-                  return;
-            }
-      
-            _offscreenbuf_size = newBufferSize;
-
-        }
-      
-        // 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.
-        static_cast<render_handler_agg_base *>(_agg_renderer)->init_buffer(
-            _offscreenbuf.get(),
-            _offscreenbuf_size,
-            _width,
-            _height,
-            _width*((_bpp+7)/8)
-        );
-      
-      
-#ifdef ENABLE_MIT_SHM
-    }
-#endif  
-    
+    
+    if (_offscreenbuf && _offscreenbuf->width == width &&
+        _offscreenbuf->height == height) {
+        return; 
+    }
+
+    if (_offscreenbuf) {
+        gdk_image_destroy(_offscreenbuf);
+    }
+
+    GdkVisual* visual = gdk_drawable_get_visual(_drawing_area->window);
+
+    _offscreenbuf = gdk_image_new (GDK_IMAGE_FASTEST, visual, width,
+                                   height);
+
+       static_cast<render_handler_agg_base *>(_agg_renderer)->init_buffer(
+        (unsigned char*) _offscreenbuf->mem,
+        _offscreenbuf->bpl * _offscreenbuf->height,
+        _offscreenbuf->width,
+        _offscreenbuf->height,
+        _offscreenbuf->bpl); 
 }
 
 void 
 GtkAggGlue::beforeRendering()
 {
-#ifdef ENABLE_MIT_SHM
-    if (_shm_image) {
-        // 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).
-        // Instead of using the XShmCompletionEvent for this we just call XSync
-        // right before writing to the shared memory again. This will make sure
-        // that the X server finishes to copy the data to VRAM before we
-        // change it again.
-        XSync(gdk_display, False);
+    if (_offscreenbuf && _offscreenbuf->type == GDK_IMAGE_SHARED) {
+         gdk_flush();
     }
-#endif  
 }
 
 void
 GtkAggGlue::render()
 {
-    if (!_drawing_area) {
-        return;
-    }
-
-
-#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); 
-      
-      // NOTE: Data will be copied in background, see beforeRendering()
-      
-    }
-    else {
-#endif  
-
-        // Update the entire screen
-        gdk_draw_rgb_image (
-            _drawing_area->window,
-            _drawing_area->style->fg_gc[GTK_STATE_NORMAL],
-            0,
-            0,
-            _width,
-            _height,
-            GDK_RGB_DITHER_NONE,
-            _offscreenbuf.get(),
-            _width*((_bpp+7)/8)
-        );      
-
-#ifdef ENABLE_MIT_SHM
-    }
-#endif  
-    
+    render(0, 0, _offscreenbuf->width, _offscreenbuf->height);
 }
 
 void
 GtkAggGlue::render(int minx, int miny, int maxx, int maxy)
 {
-    if (!_drawing_area) {
-        return;
-    }
-
-    size_t copy_width = std::min(_width * (_bpp/8), maxx - minx);
-    size_t copy_height = std::min(_height, maxy - miny);
-    size_t stride = _width*((_bpp+7)/8);
-
-#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,
-        copy_width, copy_height,
-        False);
-      
-    // NOTE: Data will be copied in background, see beforeRendering()
- 
-    }
-    else {
-#endif
-//    log_debug("minx: %d, miny: %d, copy width: %d, copy height: %d, stride: 
%d",
-//                            minx, miny, copy_width, copy_height, stride);
-//    log_debug("offscreenbuf size: %d", _offscreenbuf_size);
-//    log_debug("From: %d", miny * stride + minx * (_bpp/8));
-
-        // Update only the invalidated rectangle
-        gdk_draw_rgb_image (
-            _drawing_area->window,
-            _drawing_area->style->fg_gc[GTK_STATE_NORMAL],
-            minx,
-            miny,
-            copy_width,
-            copy_height,
-            GDK_RGB_DITHER_NORMAL,
-            _offscreenbuf.get() + miny * stride + minx * (_bpp/8),
-            stride
-        );
-
-#ifdef ENABLE_MIT_SHM
-    }
-#endif  
+     if (!_offscreenbuf) {
+         return;
+     }
+
+     const int& x = minx;
+     const int& y = miny;
+     size_t width = std::min(_offscreenbuf->width, maxx - minx);
+     size_t height = std::min(_offscreenbuf->height, maxy - miny);
+
+     GdkGC* gc = gdk_gc_new(_drawing_area->window);
+    
+     gdk_draw_image(_drawing_area->window, gc, _offscreenbuf, x, y, x, y, 
width,
+                    height);
+     gdk_gc_unref(gc);
 }
 
 void
@@ -572,26 +159,5 @@
     }
 }
 
-#ifdef ENABLE_MIT_SHM
-void 
-GtkAggGlue::decodeMask(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;
-    }
-}
-#endif
-
 } // namespace gnash
 

=== modified file 'gui/gtk_glue_agg.h'
--- a/gui/gtk_glue_agg.h        2008-10-10 15:19:16 +0000
+++ b/gui/gtk_glue_agg.h        2008-11-13 20:55:48 +0000
@@ -26,15 +26,6 @@
 #include <gdk/gdk.h>
 #include <boost/scoped_array.hpp>
 
-// Experimental support for MIT-SHM
-// see http://www.xfree86.org/current/mit-shm.html
-// currently has some problems, see https://savannah.gnu.org/bugs/?20301
-#ifdef ENABLE_MIT_SHM
-#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#endif
-
-
 namespace gnash
 {
 
@@ -54,56 +45,8 @@
     void configure(GtkWidget *const widget, GdkEventConfigure *const event);
     
   private:
-  
-    // A buffer to hold the actual image data. A boost::scoped_array
-    // is destroyed on reset and when it goes out of scope (including on
-    // stack unwinding after an exception), so there is no need to delete
-    // it.
-    boost::scoped_array<unsigned char> _offscreenbuf;
-    
-    // The size of the offscreen image buffer.
-    size_t _offscreenbuf_size;
-    
+    GdkImage* _offscreenbuf;
     render_handler *_agg_renderer;
-    int _width, _height, _bpp;
-    std::string _pixelformat;
-    bool _have_shm;
-#ifdef ENABLE_MIT_SHM
-    XImage *_shm_image;
-    XShmSegmentInfo *_shm_info;
-    
-    /// Checks if the MIT-SHM extension is available (supported by the server)
-    bool check_mit_shm(Display *display);
-#else
-    bool check_mit_shm(void *display);
-#endif    
-    
-    /// Tries to create a SHM image. 
-    ///
-    /// 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. 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)
-    void destroy_shm_image();
-    
-    /// Tries to create a AGG render handler based on the X server pixel
-    /// format. Returns NULL on failure.
-    render_handler *create_shm_handler();    
-        
-    /// Tries to detect the pixel format used by the X server (usually RGB24).
-    /// It does not have to match the hardware pixel format, just the one
-    /// expected for pixmaps. This function is /not/ used for MIT-SHM!
-    bool detect_pixelformat();
-
-#ifdef ENABLE_MIT_SHM
-    /// converts a bitmask to a shift/size information (used for pixel format
-    /// detection)
-    static void decodeMask(unsigned long mask, unsigned int& shift, unsigned 
int& size);
-#endif
-
 };
 
 } // namespace gnash


reply via email to

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