You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-construct/libs/qt-x11-free/files/0005-qpixmap_mitshm.patch

570 lines
18 KiB

qt-bugs@ issue : 11790 (part of)
applied: no
author: Lubos Lunak <l.lunak@kde.org>
NOTE: Needs #define QT_MITSHM in the matching qplatformdefs.h file. This
patch does so only for linux-g++ and linux-g++-distcc platforms.
MITSHM extension support for QPixmap<->QImage conversions.
Hello,
the review and apply the attached patches that improve performance of
QImage->QPixmap conversions. They should be applied in order
'mitshm','more_local' and 'fast', but they're independent from each other
(well, besides merging problems).
Mitshm patch adds MITSHM extension support for both
QPixmap::convertFromImage() and QPixmap::convertToImage(). I've noticed there
was some MITSHM support already, turned off by default, but it was used only
for QPixmap::xForm() , and it used shared pixmaps (and I'd bet nobody uses
it). My patch adds shared ximages support for faster pixmap<->image
conversions. Since I don't understand the xForm() code much, and I didn't
want to do anything with it, I added three #define's:
- QT_MITSHM generally enabling MITSHM support, which should be set in
qplatformsdefs.h (or wherever you setup platform specific stuff), it can be
enabled at least on Linux
- QT_MITSHM_CONVERSIONS - this is for my new code
- QT_MITSHM_XFORM - this is for the xForm() code
There's one more #define, QT_MITSHM_RMID_IGNORES_REFCOUNT. Glibc
documentation of shmctl( ... IPC_RMID ) quite clearly says that the memory
segment is freed only after the refcount increased by shmat() and decreased
by shmdt() is 0. However, at least according to
http://bugs.kde.org/show_bug.cgi?id=27517 , this doesn't happen on other
platforms for some strange reason. Such platforms should have this #define if
you ever consider supporting MITSHM on them.
The lower limit for using MITSHM for the image is about 8KiB
(width*height*depth > 100*100*32 ). Also, BestOptim in such case doesn't keep
the ximage, as the shared ximage is always freed before the function returns
(I don't know if it's worth copying it).
The second patch ('more_local'), in short, does nothing. Besides improving
performance by about 10% by making variables more "local", making few of them
const, and also making some of them unsigned (this help gcc for some reason).
The last one, 'fast', moves some if's out of the loops, and handles some most
common case specially (15bpp, 16bpp and 32bpp ximage depths). 32bpp case, if
the endianess matches, is simply uses memcpy(), for the 15/16bpp depth,
variables are replaced directly by matching values, statements are a bit
reordered and merged when suitable, and again, in case endianess matches,
pixels are written simply as Q_INT16. Most probably it would also help to
process two pixels at once and write them as Q_INT32, but I didn't want to
complicate the code too much (later >;) ).
The last snippet of 'fast' handles case when xi->bytes_per_line is not equal
to width for 8bpp ximage. I'm not actually sure if that can ever happen, but
since I've already written it *shrug*.
The 'more_local' and 'fast' patches change only convertFromImage(), as I
don't think convertToImage() is that performance critical (but it's as
unoptimized as convertFromImage() was).
Maybe some numbers. The difference is of course mainly visible with larger
pixmaps. The two optimizations alone reduce the time to 50% for 32bpp, to 70%
for 16bpp. The MITSHM support, when other patches are already applied too,
for 32bpp images saves about 33%. Together, the total time is reduced to
about 40% for 32bpp. Imlib probably still beats that, but at least this
obsoletes KPixmapIO.
--- work/qt-x11-free-3.3.8/src/kernel/qpixmap_x11.cpp
+++ work/qt-x11-free-3.3.8/src/kernel/qpixmap_x11.cpp
@@ -37,7 +37,19 @@
// NOT REVISED
+#include "qplatformdefs.h"
+
+#if defined(Q_OS_WIN32) && defined(QT_MITSHM)
+#undef QT_MITSHM
+#endif
+
+#ifdef QT_MITSHM
+
+// Use the MIT Shared Memory extension for pixmap<->image conversions
+#define QT_MITSHM_CONVERSIONS
+
// Uncomment the next line to enable the MIT Shared Memory extension
+// for QPixmap::xForm()
//
// WARNING: This has some problems:
//
@@ -45,14 +57,13 @@
// 2. Qt does not handle the ShmCompletion message, so you will
// get strange effects if you xForm() repeatedly.
//
-// #define QT_MITSHM
+// #define QT_MITSHM_XFORM
-#if defined(Q_OS_WIN32) && defined(QT_MITSHM)
-#undef QT_MITSHM
+#else
+#undef QT_MITSHM_CONVERSIONS
+#undef QT_MITSHM_XFORM
#endif
-#include "qplatformdefs.h"
-
#include "qbitmap.h"
#include "qpaintdevicemetrics.h"
#include "qimage.h"
@@ -91,7 +102,7 @@ inline static void qSafeXDestroyImage( X
MIT Shared Memory Extension support: makes xForm noticeably (~20%) faster.
*****************************************************************************/
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
static bool xshminit = FALSE;
static XShmSegmentInfo xshminfo;
@@ -173,8 +184,100 @@ static bool qt_create_mitshm_buffer( con
// return FALSE;
// }
-#endif // QT_MITSHM
+#endif // QT_MITSHM_XFORM
+
+#ifdef QT_MITSHM_CONVERSIONS
+
+static bool qt_mitshm_error = false;
+static int qt_mitshm_errorhandler( Display*, XErrorEvent* )
+{
+ qt_mitshm_error = true;
+ return 0;
+}
+
+static XImage* qt_XShmCreateImage( Display* dpy, Visual* visual, unsigned int depth,
+ int format, int /*offset*/, char* /*data*/, unsigned int width, unsigned int height,
+ int /*bitmap_pad*/, int /*bytes_per_line*/, XShmSegmentInfo* shminfo )
+{
+ if( width * height * depth < 100*100*32 )
+ return NULL;
+ static int shm_inited = -1;
+ if( shm_inited == -1 ) {
+ if( XShmQueryExtension( dpy ))
+ shm_inited = 1;
+ else
+ shm_inited = 0;
+ }
+ if( shm_inited == 0 )
+ return NULL;
+ XImage* xi = XShmCreateImage( dpy, visual, depth, format, NULL, shminfo, width,
+ height );
+ if( xi == NULL )
+ return NULL;
+ shminfo->shmid = shmget( IPC_PRIVATE, xi->bytes_per_line * xi->height,
+ IPC_CREAT|0600);
+ if( shminfo->shmid < 0 ) {
+ XDestroyImage( xi );
+ return NULL;
+ }
+ shminfo->readOnly = False;
+ shminfo->shmaddr = (char*)shmat( shminfo->shmid, 0, 0 );
+ if( shminfo->shmaddr == (char*)-1 ) {
+ XDestroyImage( xi );
+ shmctl( shminfo->shmid, IPC_RMID, 0 );
+ return NULL;
+ }
+ xi->data = shminfo->shmaddr;
+#ifndef QT_MITSHM_RMID_IGNORES_REFCOUNT
+ // mark as deleted to automatically free the memory in case
+ // of a crash (but this doesn't work e.g. on Solaris)
+ shmctl( shminfo->shmid, IPC_RMID, 0 );
+#endif
+ if( shm_inited == 1 ) { // first time
+ XErrorHandler old_h = XSetErrorHandler( qt_mitshm_errorhandler );
+ XShmAttach( dpy, shminfo );
+ shm_inited = 2;
+ XSync( dpy, False );
+ XSetErrorHandler( old_h );
+ if( qt_mitshm_error ) { // oops ... perhaps we are remote?
+ shm_inited = 0;
+ XDestroyImage( xi );
+ shmdt( shminfo->shmaddr );
+#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
+ shmctl( shminfo->shmid, IPC_RMID, 0 );
+#endif
+ return NULL;
+ }
+ } else
+ XShmAttach( dpy, shminfo );
+ return xi;
+}
+
+static void qt_XShmDestroyImage( XImage* xi, XShmSegmentInfo* shminfo )
+{
+ XShmDetach( QPaintDevice::x11AppDisplay(), shminfo );
+ XDestroyImage( xi );
+ shmdt( shminfo->shmaddr );
+#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
+ shmctl( shminfo->shmid, IPC_RMID, 0 );
+#endif
+}
+
+static XImage* qt_XShmGetImage( const QPixmap* pix, int format,
+ XShmSegmentInfo* shminfo )
+{
+ XImage* xi = qt_XShmCreateImage( pix->x11Display(), (Visual*)pix->x11Visual(),
+ pix->depth(), format, 0, 0, pix->width(), pix->height(), 32, 0, shminfo );
+ if( xi == NULL )
+ return NULL;
+ if( XShmGetImage( pix->x11Display(), pix->handle(), xi, 0, 0, AllPlanes ) == False ) {
+ qt_XShmDestroyImage( xi, shminfo );
+ return NULL;
+ }
+ return xi;
+}
+#endif // QT_MITSHM_CONVERSIONS
/*****************************************************************************
Internal functions
@@ -627,9 +730,20 @@ QImage QPixmap::convertToImage() const
d = 32; // > 8 ==> 32
XImage *xi = (XImage *)data->ximage; // any cached ximage?
- if ( !xi ) // fetch data from X server
+#ifdef QT_MITSHM_CONVERSIONS
+ bool mitshm_ximage = false;
+ XShmSegmentInfo shminfo;
+#endif
+ if ( !xi ) { // fetch data from X server
+#ifdef QT_MITSHM_CONVERSIONS
+ xi = qt_XShmGetImage( this, mono ? XYPixmap : ZPixmap, &shminfo );
+ if( xi ) {
+ mitshm_ximage = true;
+ } else
+#endif
xi = XGetImage( x11Display(), hd, 0, 0, w, h, AllPlanes,
mono ? XYPixmap : ZPixmap );
+ }
Q_CHECK_PTR( xi );
if (!xi)
return image; // null image
@@ -640,15 +754,31 @@ QImage QPixmap::convertToImage() const
QImage::LittleEndian : QImage::BigEndian;
}
image.create( w, h, d, 0, bitOrder );
- if ( image.isNull() ) // could not create image
+ if ( image.isNull() ) { // could not create image
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage )
+ qt_XShmDestroyImage( xi, &shminfo );
+ else
+#endif
+ qSafeXDestroyImage( xi );
return image;
+ }
const QPixmap* msk = mask();
const QPixmap *alf = data->alphapm;
QImage alpha;
if (alf) {
- XImage *axi = XGetImage(x11Display(), alf->hd, 0, 0, w, h, AllPlanes, ZPixmap);
+ XImage* axi;
+#ifdef QT_MITSHM_CONVERSIONS
+ bool mitshm_aximage = false;
+ XShmSegmentInfo ashminfo;
+ axi = qt_XShmGetImage( alf, ZPixmap, &ashminfo );
+ if( axi ) {
+ mitshm_aximage = true;
+ } else
+#endif
+ axi = XGetImage(x11Display(), alf->hd, 0, 0, w, h, AllPlanes, ZPixmap);
if (axi) {
image.setAlphaBuffer( TRUE );
@@ -662,6 +792,11 @@ QImage QPixmap::convertToImage() const
src += axi->bytes_per_line;
}
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_aximage )
+ qt_XShmDestroyImage( axi, &ashminfo );
+ else
+#endif
qSafeXDestroyImage( axi );
}
} else if (msk) {
@@ -804,6 +939,12 @@ QImage QPixmap::convertToImage() const
xi->bits_per_pixel );
#endif
image.reset();
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage )
+ qt_XShmDestroyImage( xi, &shminfo );
+ else
+#endif
+ qSafeXDestroyImage( xi );
return image;
}
@@ -909,10 +1050,22 @@ QImage QPixmap::convertToImage() const
delete [] carr;
}
if ( data->optim != BestOptim ) { // throw away image data
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage )
+ qt_XShmDestroyImage( xi, &shminfo );
+ else
+#endif
qSafeXDestroyImage( xi );
((QPixmap*)this)->data->ximage = 0;
- } else // keep ximage data
+ } else { // keep ximage data
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage ) { // copy the XImage?
+ qt_XShmDestroyImage( xi, &shminfo );
+ xi = 0;
+ }
+#endif
((QPixmap*)this)->data->ximage = xi;
+ }
return image;
}
@@ -1085,6 +1238,11 @@ bool QPixmap::convertFromImage( const QI
bool trucol = (visual->c_class == TrueColor || visual->c_class == DirectColor);
int nbytes = image.numBytes();
uchar *newbits= 0;
+ int newbits_size = 0;
+#ifdef QT_MITSHM_CONVERSIONS
+ bool mitshm_ximage = false;
+ XShmSegmentInfo shminfo;
+#endif
if ( trucol ) { // truecolor display
QRgb pix[256]; // pixel translation table
@@ -1113,10 +1271,18 @@ bool QPixmap::convertFromImage( const QI
}
}
+#ifdef QT_MITSHM_CONVERSIONS
+ xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
+ if( xi != NULL ) {
+ mitshm_ximage = true;
+ newbits = (uchar*)xi->data;
+ }
+ else
+#endif
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
- Q_CHECK_PTR( xi );
if (!xi)
return false;
+ if( newbits == NULL )
newbits = (uchar *)malloc( xi->bytes_per_line*h );
Q_CHECK_PTR( newbits );
if ( !newbits ) // no memory
@@ -1323,6 +1489,7 @@ bool QPixmap::convertFromImage( const QI
}
newbits = (uchar *)malloc( nbytes ); // copy image into newbits
+ newbits_size = nbytes;
Q_CHECK_PTR( newbits );
if ( !newbits ) // no memory
return FALSE;
@@ -1440,11 +1607,18 @@ bool QPixmap::convertFromImage( const QI
}
if ( !xi ) { // X image not created
+#ifdef QT_MITSHM_CONVERSIONS
+ xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
+ if( xi != NULL )
+ mitshm_ximage = true;
+ else
+#endif
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
if ( xi->bits_per_pixel == 16 ) { // convert 8 bpp ==> 16 bpp
ushort *p2;
int p2inc = xi->bytes_per_line/sizeof(ushort);
ushort *newerbits = (ushort *)malloc( xi->bytes_per_line * h );
+ newbits_size = xi->bytes_per_line * h;
Q_CHECK_PTR( newerbits );
if ( !newerbits ) // no memory
return FALSE;
@@ -1462,6 +1636,14 @@ bool QPixmap::convertFromImage( const QI
"(bpp=%d)", xi->bits_per_pixel );
#endif
}
+#ifdef QT_MITSHM_CONVERSIONS
+ if( newbits_size > 0 && mitshm_ximage ) { // need to copy to shared memory
+ memcpy( xi->data, newbits, newbits_size );
+ free( newbits );
+ newbits = (uchar*)xi->data;
+ }
+ else
+#endif
xi->data = (char *)newbits;
}
@@ -1495,19 +1677,24 @@ bool QPixmap::convertFromImage( const QI
}
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage )
+ XShmPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), FALSE ),
+ xi, 0, 0, 0, 0, w, h, False );
+ else
+#endif
XPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), FALSE ),
xi, 0, 0, 0, 0, w, h );
- if ( data->optim != BestOptim ) { // throw away image
- qSafeXDestroyImage( xi );
- data->ximage = 0;
- } else { // keep ximage that we created
- data->ximage = xi;
- }
data->w = w;
data->h = h;
data->d = dd;
+ XImage* axi = NULL;
+#ifdef QT_MITSHM_CONVERSIONS
+ bool mitshm_aximage = false;
+ XShmSegmentInfo ashminfo;
+#endif
if ( image.hasAlphaBuffer() ) {
QBitmap m;
m = image.createAlphaMask( conversion_flags );
@@ -1543,13 +1730,22 @@ bool QPixmap::convertFromImage( const QI
data->alphapm->rendhd =
(HANDLE) XftDrawCreateAlpha( x11Display(), data->alphapm->hd, 8 );
- XImage *axi = XCreateImage(x11Display(), (Visual *) x11Visual(),
+#ifdef QT_MITSHM_CONVERSIONS
+ axi = qt_XShmCreateImage( x11Display(), (Visual*)x11Visual(),
+ 8, ZPixmap, 0, 0, w, h, 8, 0, &ashminfo );
+ if( axi != NULL )
+ mitshm_aximage = true;
+ else
+#endif
+ axi = XCreateImage(x11Display(), (Visual *) x11Visual(),
8, ZPixmap, 0, 0, w, h, 8, 0);
if (axi) {
+ if( axi->data==NULL ) {
// the data is deleted by qSafeXDestroyImage
axi->data = (char *) malloc(h * axi->bytes_per_line);
Q_CHECK_PTR( axi->data );
+ }
char *aptr = axi->data;
if (image.depth() == 32) {
@@ -1567,14 +1763,48 @@ bool QPixmap::convertFromImage( const QI
}
GC gc = XCreateGC(x11Display(), data->alphapm->hd, 0, 0);
+ #ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_aximage )
+ XShmPutImage( dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h, False );
+ else
+#endif
XPutImage(dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h);
XFreeGC(x11Display(), gc);
- qSafeXDestroyImage(axi);
}
}
#endif // QT_NO_XFTFREETYPE
}
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage || mitshm_aximage )
+ XSync( x11Display(), False ); // wait until processed
+#endif
+
+ if ( data->optim != BestOptim ) { // throw away image
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage )
+ qt_XShmDestroyImage( xi, &shminfo );
+ else
+#endif
+ qSafeXDestroyImage( xi );
+ data->ximage = 0;
+ } else { // keep ximage that we created
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_ximage ) { // copy the XImage?
+ qt_XShmDestroyImage( xi, &shminfo );
+ xi = 0;
+ }
+#endif
+ data->ximage = xi;
+ }
+ if( axi ) {
+#ifdef QT_MITSHM_CONVERSIONS
+ if( mitshm_aximage )
+ qt_XShmDestroyImage( axi, &ashminfo );
+ else
+#endif
+ qSafeXDestroyImage(axi);
+ }
return TRUE;
}
@@ -1737,7 +1967,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
return pm;
}
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
static bool try_once = TRUE;
if (try_once) {
try_once = FALSE;
@@ -1770,7 +2000,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
dbpl = ((w*bpp+31)/32)*4;
dbytes = dbpl*h;
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
if ( use_mitshm ) {
dptr = (uchar *)xshmimg->data;
uchar fillbyte = bpp == 8 ? white.pixel() : 0xff;
@@ -1786,7 +2016,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
memset( dptr, Qt::white.pixel( x11Screen() ), dbytes );
else
memset( dptr, 0xff, dbytes );
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
}
#endif
@@ -1817,7 +2047,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
} else {
xbpl = (w*bpp)/8;
p_inc = dbpl - xbpl;
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
if ( use_mitshm )
p_inc = xshmimg->bytes_per_line - xbpl;
#endif
@@ -1854,7 +2084,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
QPixmap pm( w, h );
pm.data->uninit = FALSE;
pm.x11SetScreen( x11Screen() );
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
if ( use_mitshm ) {
XCopyArea( dpy, xshmpm, pm.handle(), gc, 0, 0, w, h, 0, 0 );
} else {
@@ -1863,7 +2093,7 @@ QPixmap QPixmap::xForm( const QWMatrix &
ZPixmap, 0, (char *)dptr, w, h, 32, 0 );
XPutImage( dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h);
qSafeXDestroyImage( xi );
-#if defined(QT_MITSHM)
+#if defined(QT_MITSHM_XFORM)
}
#endif
--- work/qt-x11-free-3.3.8/mkspecs/linux-g++/qplatformdefs.h
+++ work/qt-x11-free-3.3.8/mkspecs/linux-g++/qplatformdefs.h
@@ -102,5 +102,6 @@
#define QT_VSNPRINTF ::vsnprintf
#endif
+#define QT_MITSHM
#endif // QPLATFORMDEFS_H