[Top][All Lists]
[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
- [Gnash-commit] gnash ChangeLog gui/gtk_glue_agg.cpp gui/gtk_gl...,
Udo Giacomozzi <=