Hi Dmitry, I applied your patch and recorded frame rates quite the same as yours. Surely it's not as fast as a browser application that simply moves a static picture. Keep in mind that QLGT immediately starts to update the screen while moving the map. Most applications wait until you finish the move and update the map later. Thus with every screen update the map is rendered from scratch.
But anyway, I am nosy how QLGT would perform if I do not use QImage at all. Maybe it's worth dropping the thread safeness and use a special thread save draw() for the cases it's needed. As I am a bit busy the next days this might take a bit. Oliver -------- Original-Nachricht -------- > Datum: Thu, 13 Oct 2011 10:58:49 +0400 > Von: Dmitry Guryanov <[email protected]> > An: Oliver Eichler <[email protected]> > CC: [email protected], [email protected] > Betreff: Re: [Qlandkartegt-users] [PATCH] use QPixmap instead of QImage for > drawing OSM map > On Wed, Oct 12, 2011 at 10:36 PM, Oliver Eichler > <[email protected]>wrote: > > > Am 12.10.2011 12:35, schrieb Dmitry Guryanov: > > > > On Wed, Oct 12, 2011 at 1:16 PM, Oliver > Eichler<[email protected]>** > >> wrote: > >> > >> Hi Dmitry, > >>> > >>> I know, but QPixmap is not threadsafe. As there are already some > thread > >>> functions that use the draw handlers, too, and future development > might > >>> tend > >>> to do map rendering in a thread, the current implementation should > avoid > >>> the > >>> usage of QPixmap in the objects that inherit IMap. > >>> > >>> > >>> I know 3 another ways to increase rendering speed: > >> > >> 1. Don't draw to the QImage in COsmTilesHash::getImage. Create some > class, > >> which store qimage and qpoint (where qimage must be draw) and put > object > >> of > >> this class to list, then in CMapOSM::draw iterate through this list and > >> draw > >> each tile to screen directly - I've checked this method, and it reduces > >> render time about 2 times. > >> > > > > If I recall right Marc's idea (the guy who implemented all OSM/TMS > support) > > was to update the screen with each tile received, to give feedback to > the > > user. If I understand your idea correctly the screen would just update > after > > all tiles are loaded. > > > > > No, COsmTilesHash::slotRequestFinished will add object for new tile to > the > list and do emit newImageReady, but this method will break idea with > internal buffer, and it will not help a lot to make map scrolling smooth > :( > > > > > > > >> 2. Try to guess pixel format of screen and create QImages with that > pixel > >> format - this change significantly improves performance. > >> > > > > As long as this does not affect the IMap::buffer QImage it's a good > idea. > > This buffer, common to all map objects, has to be able to handle the > alpha > > channel, as Garmin or raster maps use transparency. Even in CMapOSM > > transparency is need when drawing a vector map as overlay. > > > > If alfa channel is needed, this method will not wok :( QImages with such > pixel format are being drawn to screen slowly. > > > > On my Linux boxes and my win7 netbook the OSM drawing performance has > never > > been a problem. But if it's such a performance ditch on your system I > think > > your idea is fair enough. > > > > > I've compared qlandkarte with web applications, like > http://www.openstreetmap.org/ and maps.google.com - web apps works > excellent, i don't see any delays at all, but in qlandkarte update rate is > small :( Please, try to run qlandkarte with patch in attachment and check > output, on my system - fedora 15, Core(TM)2 Duo CPU E6750, nvidia > adapter, > screen size 1600x1200 and with maximized window it shows about 11 FPS :( > With pixmaps it shows 40-400 fps (maybe some problem with qt events and > synchronization exists, paintEvent works 2.5 ms, so it can be always > 400fps). > > > > > >> 3. Create separate hash for storing tiles in QPixmaps and convert > QImages > >> to > >> QPixmaps in GUI thread. > >> > > > > Well the method CMapOSM::draw(QPainter& p) can be called by the GUI > thread > > or from any other point. If that does make sense in the case of CMapOSM > can > > be discussed, as the method will just trigger tile download and draw the > > current IMap::buffer. CMapOSM will update itself automatically until all > > visible tiles are loaded. This is no real concept for a background > thread, > > that expects a complete map after the call. > > > > Thus it would be an option to bypass the IMap::buffer use QPixmap > > completely for CMapOSM and COsmTilesHash. But CMapOSM::draw(QPainter& p) > > should make sure just be called in the main thread. Not sure if that can > be > > checked by the Qt API to make it portable. > > > > It's possible but my intuition tells me that I will regret one day ;) > > > > > Maybe create one separate method, which will be called only from GUI > thread > and second - method, which must be thread safe. In simplest case first > will > just call second, but when some optimization is possible - we can add fast > and thread-unsafe code for drawing to screen ? > > > > Oliver > > > > > > > > > >>> -------- Original-Nachricht -------- > >>> > >>>> Datum: Wed, 12 Oct 2011 11:11:27 +0400 > >>>> Von: Dmitry > Guryanov<dmitry.guryanov@**gmail.com<[email protected]> > >>>> > > >>>> An: > qlandkartegt-users@lists.**sourceforge.net<[email protected]> > >>>> CC: [email protected] > >>>> Betreff: [Qlandkartegt-users] [PATCH] use QPixmap instead of QImage > for > >>>> > >>> drawing OSM map > >>> > >>> QImage is optimized for IO, as states QT documentation, > >>>> and operation like drawing one QImage to another or > >>>> drawing QImage to screen are very slow, especially when > >>>> pixel format of QImage not same as screen (on my system > >>>> pixel format of screen is rgb32, but qlandkarte use > >>>> QImage::Format_ARGB32_**Premultiplied). > >>>> > >>>> Using QPixmap speeds up paintEvent handler, before this > >>>> patch time of CCanvas::paintEvent was ~85ms, after - ~2.5ms. > >>>> Update rate is still not high, about 40FPS, because > >>>> of qt events, but map moves more smoothly. > >>>> --- > >>>> src/CMapOSM.cpp | 8 ++++---- > >>>> src/CMapOSM.h | 5 +++-- > >>>> src/COsmTilesHash.cpp | 16 ++++++++++------ > >>>> src/COsmTilesHash.h | 8 ++++---- > >>>> 4 files changed, 21 insertions(+), 16 deletions(-) > >>>> > >>>> diff --git a/src/CMapOSM.cpp b/src/CMapOSM.cpp > >>>> index 5c25462..c9cb2d7 100644 > >>>> --- a/src/CMapOSM.cpp > >>>> +++ b/src/CMapOSM.cpp > >>>> @@ -216,7 +216,7 @@ void CMapOSM::setNewTileUrl(int cbIndex) > >>>> } > >>>> > >>>> osmTiles = new COsmTilesHash(tileList.at(**index).path); > >>>> - > >>>> > >>>> connect(osmTiles,SIGNAL(**newImageReady(QImage,bool)),** > >>> this,SLOT(newImageReady(**QImage,bool))); > >>> > >>>> + > >>>> > >>>> connect(osmTiles,SIGNAL(**newImageReady(QPixmap,bool)),** > >>> this,SLOT(newImageReady(**QPixmap,bool))); > >>> > >>>> > >>>> needsRedraw = true; > >>>> emit sigChanged(); > >>>> @@ -370,7 +370,7 @@ void CMapOSM::draw(QPainter& p) > >>>> draw(); > >>>> } > >>>> > >>>> - p.drawImage(0,0,buffer); > >>>> + p.drawPixmap(0, 0, image); > >>>> > >>>> // render overlay > >>>> if(!ovlMap.isNull()&& lastTileLoaded&& !doFastDraw) > >>>> > >>>> @@ -437,9 +437,9 @@ void CMapOSM::draw() > >>>> } > >>>> > >>>> > >>>> -void CMapOSM::newImageReady(QImage image, bool done) > >>>> +void CMapOSM::newImageReady(QPixmap image, bool done) > >>>> { > >>>> - buffer = image; > >>>> + this->image = image; > >>>> lastTileLoaded = done; > >>>> needsRedraw = false; > >>>> emit sigChanged(); > >>>> diff --git a/src/CMapOSM.h b/src/CMapOSM.h > >>>> index 6b7e2f8..2a44081 100644 > >>>> --- a/src/CMapOSM.h > >>>> +++ b/src/CMapOSM.h > >>>> @@ -21,6 +21,7 @@ > >>>> #define CMAPOSM_H > >>>> > >>>> #include<IMap.h> > >>>> +#include<QPixmap> > >>>> #include "CMapOSMType.h" > >>>> > >>>> class COsmTilesHash; > >>>> @@ -49,14 +50,14 @@ class CMapOSM : public IMap > >>>> bool rebuildServerList(); > >>>> > >>>> public slots: > >>>> - void newImageReady(QImage image, bool lastTileLoaded); > >>>> + void newImageReady(QPixmap image, bool lastTileLoaded); > >>>> void setNewTileUrl(int cbIndex = -1); > >>>> private: > >>>> QComboBox *cb; > >>>> QWidget *parent; > >>>> int currentTileListIndex; > >>>> QList<CMapOSMType> tileList; > >>>> - QImage image; > >>>> + QPixmap image; > >>>> bool lastTileLoaded; > >>>> void draw(); > >>>> COsmTilesHash *osmTiles; > >>>> diff --git a/src/COsmTilesHash.cpp b/src/COsmTilesHash.cpp > >>>> index 3455cc0..7471f36 100644 > >>>> --- a/src/COsmTilesHash.cpp > >>>> +++ b/src/COsmTilesHash.cpp > >>>> @@ -183,7 +183,7 @@ void COsmTilesHash::**startNewDrawing( double > lon, > >>>> double lat, int osm_zoom, const > >>>> > >>>> //qDebug()<< xCount<< yCount<< window; > >>>> > >>>> - image = QImage(window.size(),QImage::** > >>>> Format_ARGB32_Premultiplied); > >>>> + image = QPixmap(window.size()); > >>>> image.fill(Qt::white); > >>>> for(int x=0; x<xCount; x++) > >>>> { > >>>> @@ -212,7 +212,7 @@ void COsmTilesHash::getImage(int osm_zoom, int > >>>> osm_x, > >>>> int osm_y, QPoint point) > >>>> if (tiles.contains(osmUrlPart)) > >>>> { > >>>> QPainter p(&image); > >>>> - p.drawImage(point,tiles.value(**osmUrlPart)); > >>>> + p.drawPixmap(point,tiles.**value(osmUrlPart)); > >>>> #ifdef COSMTILESHASHDEBUG > >>>> p.drawRect(QRect(point,QSize(**255,255))); > >>>> p.drawText(point + QPoint(10,10), "cached " + osmUrlPart); > >>>> @@ -229,9 +229,11 @@ void COsmTilesHash::getImage(int osm_zoom, int > >>>> > >>> osm_x, > >>> > >>>> int osm_y, QPoint point) > >>>> > >>>> if(img1.format() != QImage::Format_Invalid) > >>>> { > >>>> + QPixmap pix1(img1.size()); > >>>> + pix1.convertFromImage(img1); > >>>> QPainter p(&image); > >>>> - p.drawImage(point,img1); > >>>> - tiles.insert(osmUrlPart,img1); > >>>> + p.drawPixmap(point,pix1); > >>>> + tiles.insert(osmUrlPart,pix1); > >>>> int days = > >>>> > >>>> QFileInfo(osmFilePath).**lastModified().daysTo(** > >>> QDateTime::currentDateTime()); > >>> > >>>> if ( days< 8) > >>>> { > >>>> @@ -309,10 +311,12 @@ void COsmTilesHash::**slotRequestFinished(int > id, > >>>> > >>> bool > >>> > >>>> error) > >>>> img1.save (&f); > >>>> } > >>>> > >>>> - tiles.insert(osmUrlPart,img1); > >>>> + QPixmap pix1(img1.size()); > >>>> + pix1.convertFromImage(img1); > >>>> + tiles.insert(osmUrlPart,pix1); > >>>> // if (osmUrlPart.startsWith(**QString("/%1/").arg(osm_zoom))**) > { > >>>> QPainter p(&image); > >>>> - p.drawImage(startPointHash.**value(id),img1); > >>>> + p.drawPixmap(startPointHash.**value(id),pix1); > >>>> #ifdef COSMTILESHASHDEBUG > >>>> p.drawRect(QRect(**startPointHash.value(id),**QSize(255,255))); > >>>> p.drawText(startPointHash.**value(id) + QPoint(10,10), > >>>> QString::number(id) + osmUrlPartHash.value(id)); > >>>> diff --git a/src/COsmTilesHash.h b/src/COsmTilesHash.h > >>>> index f5f6e8f..5ee7d68 100644 > >>>> --- a/src/COsmTilesHash.h > >>>> +++ b/src/COsmTilesHash.h > >>>> @@ -20,7 +20,7 @@ > >>>> #include<QString> > >>>> #include<QRect> > >>>> #include<QPainter> > >>>> -#include<QImage> > >>>> +#include<QPixmap> > >>>> #include<QHash> > >>>> > >>>> class QHttp; > >>>> @@ -34,7 +34,7 @@ class COsmTilesHash: public QObject > >>>> void startNewDrawing( double lon, double lat, int osm_zoom, > >>>> > >>> const > >>> > >>>> QRect& window); > >>>> static const QString&getCacheFolder(void) { return > cacheFolder; > >>>> > >>>> }; > >>>> signals: > >>>> - void newImageReady(QImage image, bool lastTileLoaded); > >>>> + void newImageReady(QPixmap image, bool lastTileLoaded); > >>>> private: > >>>> QString tileServer; > >>>> QString tileUrlPart; > >>>> @@ -48,12 +48,12 @@ class COsmTilesHash: public QObject > >>>> double tile2long(int x, int zoom); > >>>> double tile2lat(int y, int zoom); > >>>> void getImage(int osm_zoom, int osm_x, int osm_y, QPoint > >>>> startPoint); > >>>> - QImage image; > >>>> + QPixmap image; > >>>> QHttp *tilesConnection; > >>>> // CMapOSM *cmapOSM; > >>>> QString osmTileBaseUrl; > >>>> bool requestInProgress; > >>>> - QHash<QString,QImage> tiles; > >>>> + QHash<QString,QPixmap> tiles; > >>>> int getid; > >>>> static QString cacheFolder; > >>>> private slots: > >>>> -- > >>>> 1.7.6.4 > >>>> > >>>> > >>>> > >>>> ------------------------------**------------------------------** > >>> ------------------ > >>> > >>>> All the data continuously generated in your IT infrastructure > contains a > >>>> definitive record of customers, application performance, security > >>>> threats, fraudulent activity and more. Splunk takes this data and > makes > >>>> sense of it. Business sense. IT sense. Common sense. > >>>> > http://p.sf.net/sfu/splunk-**d2d-oct<http://p.sf.net/sfu/splunk-d2d-oct> > >>>> ______________________________**_________________ > >>>> Qlandkartegt-users mailing list > >>>> > Qlandkartegt-users@lists.**sourceforge.net<[email protected]> > >>>> > https://lists.sourceforge.net/**lists/listinfo/qlandkartegt-**users<https://lists.sourceforge.net/lists/listinfo/qlandkartegt-users> > >>>> > >>> > >>> > >> > > ------------------------------------------------------------------------------ All the data continuously generated in your IT infrastructure contains a definitive record of customers, application performance, security threats, fraudulent activity and more. Splunk takes this data and makes sense of it. Business sense. IT sense. Common sense. http://p.sf.net/sfu/splunk-d2d-oct _______________________________________________ Qlandkartegt-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/qlandkartegt-users
