February 14, 2011

onurozcelik onurozcelik
Lab Rat
19 posts

QGraphicsScene/QGraphicsView performance

 

Hi

I am using QGraphicsScene/QGraphicsView pair in my project
I have performance issue with this pair.
I added my custom graphics items to scene and displayed the contents with view. After that my custom graphics items paint method continuously called by scene(just like infinite loop). This makes 25% of CPU usage(approximately 400 items on scene). What may cause this behaviour?

Here is one my item implementation:

  1. class LevelCrossingItem : public QGraphicsWidget
  2. {
  3. public:
  4.     LevelCrossingItem(QString _id,qreal _x,qreal _y);
  5.     ~LevelCrossingItem();
  6.     QRectF boundingRect() const;
  7.     QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint  = QSizeF()) const;
  8.     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = 0 */);
  9.     void readStateBits();
  10.     bool isClosed();
  11.     bool isGateArmBroken();
  12.     bool isOpenedDuringRouteTanzimCompleted();
  13.     bool hasDataConsistencyWarning();
  14.     int type() const {return Type;}
  15. private slots:
  16.     void setVisible(bool);
  17. private:
  18.     enum {Type = FIELDLEVELCROSSING};
  19.     QString m_id;
  20.     QString m_source;
  21.     short m_closedState;
  22.     short m_brokenGateArmState;
  23.     short m_openedDuringRouteTanzimCompletedState;
  24.     short m_dataConsistencyWarningState;
  25.     QBitArray stateBitArray;
  26.     qreal x,y;
  27.     QSvgRenderer *renderer;
  28. };    

  1. #include "levelcrossing.h"
  2.  
  3. LevelCrossingItem::LevelCrossingItem(QString _id,qreal _x,qreal _y):m_id(_id),x(_x),y(_y),stateBitArray(4)
  4. {
  5.     m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
  6.     renderer = new QSvgRenderer;
  7.     setStateArray(stateBitArray);
  8.     setZValue(-0.5);
  9. }
  10.  
  11. LevelCrossingItem::~LevelCrossingItem()
  12. {
  13.     delete renderer;
  14. }
  15.  
  16. void LevelCrossingItem::setVisible(bool visible)
  17. {
  18.     QGraphicsItem::setVisible(visible);
  19. }
  20.  
  21. QRectF LevelCrossingItem::boundingRect() const
  22. {
  23.     return QRectF(QPointF(x,y),sizeHint(Qt::PreferredSize));
  24. }
  25.  
  26. QSizeF LevelCrossingItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
  27. {
  28.     return QSizeF(50,270);
  29. }
  30.  
  31. void LevelCrossingItem::readStateBits()
  32. {
  33.     m_closedState = property("Closed").toInt();
  34.     m_brokenGateArmState = property("Broken").toInt();
  35.     m_openedDuringRouteTanzimCompletedState = property("OpenedOnRouteWarning").toInt();
  36.     m_dataConsistencyWarningState = property("DataConsistencyWarning").toInt();
  37.  
  38.     stateBitArray.setBit(0,qvariant_cast<bool>(m_closedState));
  39.     stateBitArray.setBit(1,qvariant_cast<bool>(m_brokenGateArmState));
  40.     stateBitArray.setBit(2,qvariant_cast<bool>(m_openedDuringRouteTanzimCompletedState));
  41.     stateBitArray.setBit(3,qvariant_cast<bool>(m_dataConsistencyWarningState));
  42.  
  43.     setStateArray(stateBitArray);
  44. }
  45.  
  46. void LevelCrossingItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
  47. {
  48.     Q_UNUSED(option);
  49.     Q_UNUSED(widget);
  50.  
  51.     readStateBits();
  52.  
  53.     m_closedState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("closed")
  54.         : m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
  55.     m_brokenGateArmState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("broken")
  56.         : m_source = m_source;
  57.  
  58.     if(m_openedDuringRouteTanzimCompletedState == Positive)
  59.     {
  60.         setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),true);
  61.         if(stateChanged())
  62.             emit itemAlarmOccured(m_id,LevelCrossingIsOpenDuringTanzimCompleted);
  63.     }
  64.     else
  65.          setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),false);
  66.  
  67.     if(m_dataConsistencyWarningState == Positive)
  68.     {  
  69.         setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),true);
  70.         if(stateChanged())
  71.             emit itemAlarmOccured(m_id,LevelCrossingDataConsistency);
  72.     }
  73.     else
  74.         setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),false);
  75.  
  76.     renderer->load(m_source);
  77.     renderer->render(painter,boundingRect());
  78. }
  79.  
  80. bool LevelCrossingItem::isClosed()
  81. {
  82.     return m_closedState == Positive;
  83. }
  84.  
  85. bool LevelCrossingItem::isGateArmBroken()
  86. {
  87.     return m_brokenGateArmState == Positive;
  88. }
  89.  
  90. bool LevelCrossingItem::isOpenedDuringRouteTanzimCompleted()
  91. {
  92.     return m_openedDuringRouteTanzimCompletedState == Positive;
  93. }
  94.  
  95. bool LevelCrossingItem::hasDataConsistencyWarning()
  96. {
  97.     return m_dataConsistencyWarningState == Positive;
  98. }

I read x and y coordinates from xml file. For this item x and y coordinates are 239,344 respectively

14 replies

February 14, 2011

MarekR22 MarekR22
Lab Rat
14 posts

First ask proper question (some solid data not just “I have a problem”).
Secondly your “custom graphics items” must be faulty.

February 14, 2011

Jorj Jorj
Lab Rat
97 posts

can you post some code for the items?

February 14, 2011

Jorj Jorj
Lab Rat
97 posts

you are emitting signals during your paint method, if these are connected to the (im assuming) game logic, and trigger a redraw, you will get an infinite ish loop, possibly you should restructure you game logic to be separate form the paint methods.

that is my first thought anyway…

February 15, 2011

zgulser zgulser
Lab Rat
12 posts

Hi,

First of all, your paint methods will always be called when the view interacts with mouse unless you ignore the mouse events.

Secondly, paint ,as it stands, should only perform painting but as far as I see you do many things beyond painting. Maybe that’s why your items are slow. Plus remember that they will much faster in release mode(in case if you are working in debug mode).

Finally, what’s the renderer?

February 15, 2011

onurozcelik onurozcelik
Lab Rat
19 posts
zgulser wrote:
Finally, what’s the renderer?

QSvgRenderer instance pointer.

February 15, 2011

onurozcelik onurozcelik
Lab Rat
19 posts
Jorj wrote:
you are emitting signals during your paint method, if these are connected to the (im assuming) game logic, and trigger a redraw, you will get an infinite ish loop

I commented emit stuff but CPU usage did not change.

February 15, 2011

zgulser zgulser
Lab Rat
12 posts

Ok.

I think you should do all other controlling stuff outside the paint method( I bet you know signal-slot issue) and just perform renderer->render(painter,boundingRect()); in it.

February 15, 2011

MarekR22 MarekR22
Lab Rat
14 posts

As I can see now you mess up everything with everything.

  • paint method should do only painting nothing else (performance reasons)
  • sizeHint is hardcoded I doubt you reale need this
  • boundingRect is wrong for sure.
  • you messing around with properties when it is not needed (this is needed if code supposed to manipulate objects with unknown api/structure).

Maybe explain what this should show!

[EDIT: fixed list – use “*” instead of “-” as “bullets”, Volker]

February 15, 2011

onurozcelik onurozcelik
Lab Rat
19 posts

MarekR22

How should I implement boundingRect()?
Sample code please.

February 15, 2011

zgulser zgulser
Lab Rat
12 posts

Although it won’t solve your problem totally, it should be something like;

  1. void Item::setBoundingRect(const QRect& pBoundingRect)
  2. {
  3.       mBoundingRect = pBoundingRect;
  4. }
  5.  
  6. const QRect& Item::getBoundingRect()
  7. {
  8.       return mBoundingRect;
  9. }
  10.  
  11. const QRect& Item::boundingRect()
  12. {
  13.        return getBoundingRect();
  14. }

February 15, 2011

Ivan Čukić Ivan Čukić
Lab Rat
120 posts

You could also cache the svg render output to a pixmap.

 Signature 

Ivan Čukić | ivan.cukic(at)kde.org | KDE e.V.
Qt Ambassador

February 16, 2011

MarekR22 MarekR22
Lab Rat
14 posts

onurozcelik wrote:
MarekR22

How should I implement boundingRect()?
Sample code please.


The joke is that you don’t have to. QGraphicsWidget returns boundingRect which in most cases should be ok.
But like I said describe what you are trying to achieve then we will show you how code should look like.
Note there is a class QGraphicsSvgItem [doc.trolltech.com]. Maybe this is enough for you.

February 17, 2011

onurozcelik onurozcelik
Lab Rat
19 posts

implementing boundingRect correctly solved the infinite repaint loop problem.

February 17, 2011

Andre Andre
Area 51 Engineer
6067 posts

zgulser wrote:

Although it won’t solve your problem totally, it should be something like;

@

void Item::setBoundingRect(const QRect& pBoundingRect)
{ mBoundingRect = pBoundingRect;
}

const QRect& Item::getBoundingRect()
{ return mBoundingRect;
}

const QRect& Item::boundingRect()
{ return getBoundingRect();
}
@

For performance critical code, you should just inline the stuff above.

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

 
  ‹‹ QSocketNotifier help?      Is it possible to put one native Win32 window and one Qt window together in same app ››

You must log in to post a reply. Not a member yet? Register here!