PDA

View Full Version : QPropertyAnimation+QGraphicsItem : use 25% of the CPU



pl01
15th June 2013, 12:32
Hi,

I use a QPropertyAnimation to animate a QGraphicsItem but when the animation start it use 25% of the CPU (and I need this CPU for other operations).

All I do is an "update" on the item when the property is changed... so it request an item redraw !

How can I reduce this ?

Thanks

wysota
15th June 2013, 13:46
Show us your item implementation, in particular its boundingRect() code.

pl01
17th June 2013, 10:01
Thanks,

Here is the code of my class:

https://docs.google.com/file/d/0B4Cnbnu5_uCbbXpRQ25Va2pUbHM/edit?usp=sharing
https://docs.google.com/file/d/0B4Cnbnu5_uCbUzBPakpuR0tiWXc/edit?usp=sharing

wysota
17th June 2013, 10:58
We still have no idea how the boundingRect() for your item is defined. What do you set it to?

pl01
17th June 2013, 11:07
I have not redefined the 'boundingRect' method !

wysota
17th June 2013, 11:23
I know but you are calling setRect() somewhere which defines the bounding rect. By the way, why are you manipulating the animation in the function related to drawing your item?

pl01
17th June 2013, 11:30
Yes,

I call : setRect(0, 0, 90, 90); in the "initializeNode()" method.


By the way, why are you manipulating the animation in the function related to drawing your item?

Because, when the item is selected I want to animate a "circle" around the item... a simple color transition... that will highlight the selected item.

wysota
17th June 2013, 12:14
I call : setRect(0, 0, 90, 90); in the "initializeNode()" method.
Try enabling cache for your items. However this will surely break your already broken animation code. I wouldn't expect miracles performance wise if you are changing the highlight color constantly. Maybe making the highlight a separate item would help more.



Because, when the item is selected I want to animate a "circle" around the item... a simple color transition... that will highlight the selected item.
paint() routine is for painting, not for starting animations. Manipulate the animation when the selection value changes. And set the loop count to infinite instead of manually checking the state of the animation every frame and restarting it when it finishes its course.

pl01
17th June 2013, 12:35
Thanks,

1) I used setCacheMode(QGraphicsItem::DeviceCoordinateCache) ; for caching... Notice I also need anti-aliasing !
2) Sure, I can start the animation somewhere else... but it would'nt change anything to performance ! (I have just try of course) ;-)

wysota
17th June 2013, 13:38
1) I used setCacheMode(QGraphicsItem::DeviceCoordinateCache) ; for caching... Notice I also need anti-aliasing !
I don't see how anti-aliasing is relevant here. I would rather use ItemCoordinateCache.


2) Sure, I can start the animation somewhere else... but it would'nt change anything to performance ! (I have just try of course) ;-)
If you change the item every frame, then caching only makes your app slower since it has to be regenerated again and again. If you move the animation outside your item then at least the item itself can be cached properly and will not execute your quite complex code on each frame of the animation. All this does not change the fact that putting animation controlling code into a paint routine is simply wrong.

pl01
17th June 2013, 16:43
Thanks,

So,

1) I have change to : ItemCoordinateCache, but nothing change :-P
2) I have move the animation code outside the paint
3) All I need is to partially update the item, only the "selection circle" around the item should be animated !

Thx

Added after 1 7 minutes:

I have do a simple test, I have remove all the "painting" code, except the "selection circle", but it continue to use 20% of my CPU !

There is no way to slow-down this animation ?

wysota
17th June 2013, 17:15
1) I have change to : ItemCoordinateCache, but nothing change :-P
Some things did change but not performance-wise.


3) All I need is to partially update the item, only the "selection circle" around the item should be animated !
There are not partial updates. Either you redraw an item or not. That's why I suggest to separate it into two items -- one that is redrawn and one that is not.


There is no way to slow-down this animation ?
Change the duration or modify the grade of changes (maybe it is enough to animate through 4-8 colours instead of the whole hue range?).

pl01
17th June 2013, 17:59
Thanks,

I have also remove the "update" in the 'setSelectionHue' and.... the CPU is still at 20% !!!!!

And no painting is done !!! It seems the problem is related to the 'QPropertyAnimation' only ?

Added after 23 minutes:

I have also try with a QTimer, that refresh every second.... and still 15% CPU (still without call "update()" ) !!!!

So, it seems that the problem is somewhere in QT loops/timers/...

wysota
17th June 2013, 18:12
Can you prepare a minimal compilable example reproducing the problem?

pl01
17th June 2013, 18:32
Hum,

I have finaly find something really strange :-P

If I use the default theme... everything works as expected, but with my own "style" (based on "cleanlooks") the CPU goes to 20% !!!!!!
It seems that simply "selecting" my item use the CPU (even without all the animation stuffs) !

wysota
17th June 2013, 18:38
It's hard to believe since graphics items are not styled by QStyle, as far as I can tell.

pl01
17th June 2013, 18:44
I don't understand what is happening, here is my stack :



> Qt5Guid.dll!QTextEngine::resolveAdditionalFormats( ) Line 2725 + 0x5 bytes C++
Qt5Guid.dll!QTextEngine::itemize() Line 1450 C++
Qt5Guid.dll!QFontMetrics::boundingRect(const QString & text="DSCS 3154") Line 674 C++
Qt5Widgetsd.dll!QComboBoxPrivate::recomputeSizeHin t(QSize & sh={...}) Line 307 + 0x33 bytes C++
Qt5Widgetsd.dll!QComboBox::sizeHint() Line 2336 + 0x1d bytes C++
Qt5Widgetsd.dll!QWidgetItemV2::updateCacheIfNecess ary() Line 715 C++
Qt5Widgetsd.dll!QWidgetItemV2::minimumSize() Line 790 C++
Qt5Widgetsd.dll!QGridBox::minimumSize() Line 76 + 0x29 bytes C++
Qt5Widgetsd.dll!QGridLayoutPrivate::setupLayoutDat a(int hSpacing=6, int vSpacing=6) Line 795 + 0x15 bytes C++
Qt5Widgetsd.dll!QGridLayoutPrivate::distribute(QRe ct r={...}, int hSpacing=6, int vSpacing=6) Line 928 C++
Qt5Widgetsd.dll!QGridLayout::setGeometry(const QRect & rect={...}) Line 1371 C++
Qt5Widgetsd.dll!QLayoutPrivate::doResize(const QSize & r={...}) Line 592 C++
Qt5Widgetsd.dll!QLayout::activate() Line 1094 C++
Qt5Widgetsd.dll!QLayout::widgetEvent(QEvent * e=0x000000000436efb0) Line 639 C++
Qt5Widgetsd.dll!QApplicationPrivate::notify_helper (QObject * receiver=0x0000000004395c90, QEvent * e=0x000000000436efb0) Line 3394 C++
Qt5Widgetsd.dll!QApplication::notify(QObject * receiver=0x0000000004395c90, QEvent * e=0x000000000436efb0) Line 3363 + 0x1a bytes C++
Qt5Cored.dll!QCoreApplication::notifyInternal(QObj ect * receiver=0x0000000004395c90, QEvent * event=0x000000000436efb0) Line 767 + 0x26 bytes C++
Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver=0x0000000004395c90, QEvent * event=0x000000000436efb0) Line 203 + 0x53 bytes C++
Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEv ents(QObject * receiver=0x0000000000000000, int event_type=0, QThreadData * data=0x0000000001b6bee0) Line 1368 + 0x17 bytes C++
Qt5Cored.dll!QCoreApplication::sendPostedEvents(QO bject * receiver=0x0000000000000000, int event_type=0) Line 1229 C++
Qt5Guid.dll!QWindowSystemInterface::sendWindowSyst emEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 516 C++
qwindowsd.dll!QWindowsGuiEventDispatcher::sendPost edEvents() Line 87 C++
Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd=0x0000000000340c74, unsigned int message=1025, unsigned __int64 wp=0, __int64 lp=0) Line 423 C++
user32.dll!0000000077269bd1()
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]
user32.dll!00000000772698da()
Qt5Cored.dll!QEventDispatcherWin32::processEvents( QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 744 C++
qwindowsd.dll!QWindowsGuiEventDispatcher::processE vents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 78 + 0x15 bytes C++
Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 137 C++
Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) Line 212 + 0x3d bytes C++
Qt5Cored.dll!QCoreApplication::exec() Line 1020 + 0x2b bytes C++
Qt5Guid.dll!QGuiApplication::exec() Line 1184 C++
Qt5Widgetsd.dll!QApplication::exec() Line 2674 C++

wysota
17th June 2013, 19:00
I really suggest you test your approach against a minimal example to reduce any external influences. I can see some resizing code here and nothing related to QGraphicsView.

pl01
17th June 2013, 19:02
I have find the "buggy" line !

In the custom theme, I write the following :

void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{

case CC_ComboBox:
if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
{
painter->save();
((QComboBox*)widget)->setStyleSheet("QComboBox QAbstractItemView{background-color: black;selection-background-color: #600000;selection-color: white;}");
painter->restore();
}
break;

}

wysota
17th June 2013, 22:55
Another case of using a drawing routine to do something unrelated to drawing.

pl01
18th June 2013, 10:01
Sure,

It is because I have find no other way to style this combo-item.

Thanks for your help

wysota
18th June 2013, 11:25
You have to do that by implementing the style methods (drawPrimitive, etc.). Overwriting the stylesheet like that is a terrible idea. The widget is const here for a reason :)