PDA

View Full Version : QGraphicsScene render thread



nicolas1
25th October 2008, 06:32
Hello,

I call QGraphicsScene->render to painter which redirects to QPixmap and scene contains only QGraphicsTextItem. Then I call this from thread (QThread child). Program stops and exits unexpectedly.

Same method works fine when is called from GUI thread.

Any ideas? I need to call from separate thread because of lengthy operation.

wysota
25th October 2008, 12:38
You can't paint to pixmaps from threads other than the main thread. Find another solution, like rendering to QImage and then converting to QPixmap in the main thread.

nicolas1
25th October 2008, 13:22
some new facts.
Actually QGraphicsScene::render works fine in separate thread.

Problem happens when I try to call QPixmap::toImage() method. There is much time taken and finally program got crashed.

So, some problems in QImage.

Same situation happen when call QGraphicsScene::render to QImage based QPainter.

I have got some workaround, but this is strange that GUI thread is required. No painting to widgets was requested...

wysota
25th October 2008, 16:24
Believe me, QImage has nothing to do with it. The rule is simple - you can't operate on any graphical object from non-main thread. QPixmap is a GUI object, QWidget is a GUI object and QImage is not a GUI object. If you create a QPixmap from QImage, you operate on both QImage and QPixmap hence you break the rule.

nicolas1
26th October 2008, 05:26
QGraphicsScene::render works fine in separate thread (non-main) with QPainter based on QPixmap. How would you explain this?

Also this limitation makes QGraphicsScene/QGraphicsView api limited only for display rendering and for getting simple sceenshots. So, it seems to be not suitable for output to image file in case of large scale data?

wysota
26th October 2008, 09:24
QGraphicsScene::render works fine in separate thread (non-main) with QPainter based on QPixmap. How would you explain this?

It causes problems that are revealed later. The fact that a function completes doesn't yet mean it doesn't break something internally (in this case probably in X11 communication). If you don't believe me, that's your choice. If you have a commercial licence for Qt, mail Qt Software support and ask them. If you don't, then search this forum for similar problems and deduce the rest. You might even look into the documentation, it's written there as well... If you choose otherwise - go ahead.


Also this limitation makes QGraphicsScene/QGraphicsView api limited only for display rendering and for getting simple sceenshots. So, it seems to be not suitable for output to image file in case of large scale data?

Why so? Render to QImage and save it to file. You can (probably) do both from external thread if you really have to (which is probably not true, I bet you can do that in the main thread).

And what is the point of making an image of what is displayed on the screen if you want to display it back on the screen again? Are you implementing some stills functionality? You can do that without actually making a still. Simply don't change the scene immediately, only store data and "execute" it afterwards.

One more thing to state - people think that if they have constant flow of data, they have to spend all the time of the application updating the data. This is not true - the human eye can only see about 20 separate images per second and that's only if your constantly looking at the display. Another question to answer yourself is - will anything happen if I see the image 100ms later than the data actually arrives? In most cases the answer is "no". You don't have to see each point on a plot as it arrives - you can add multiple points at the same time without negative impact on user's reception.

Oh, and maybe one more thing which I tend to repeat on every occasion - threads slow down your application instead of speeding it up unless you have multiple execution units and do things in parallel. I don't know if this affects your situation but I want to say it anyway.

nicolas1
26th October 2008, 11:17
From Qt doc:

"Because QImage is a QPaintDevice subclass, QPainter can be used to draw directly onto images. When using QPainter on a QImage, the painting can be performed in another thread than the current GUI thread, that is except rendering text (because QFont is GUI dependent). To render text in another thread, the text must first be derived as a QPainterPath in the GUI thread. "
As I see, problem is only with font. So, I should read this before posting topic here. ))

I need simply to save displayed scene to image file once after all edit actions were finished. But not as a screenshot quality. I need rather good resolution. That's why some workaround was used, except for text items...
There are some problems when render to QImage (for example, picture items with alpha channel) and no progress indication and one memory chunk is allocated for output QImage... If chunk is big, this becomes a problem.

Operation is lengthy, many subroutines are used, with different complexity. That's why separate thread was used. So, your suggest was to process messages in some number of operations. This is possible in some cases but GUI becomes not so interactive.

1 additional thread is typically OK for PC with 1 processor. Currently, most processors are 2 core. No problem at all.

wysota
26th October 2008, 12:57
There are some problems when render to QImage (for example, picture items with alpha channel) and no progress indication and one memory chunk is allocated for output QImage... If chunk is big, this becomes a problem.
Divide your work into pieces and do one piece at a time. There is a (hopefully nice) article about it in latest Qt Quarterly (issue 27). Believe me, in your situation there is no need to use threads :)


This is possible in some cases but GUI becomes not so interactive.
This is not true. See the article mentioned.


1 additional thread is typically OK for PC with 1 processor. Currently, most processors are 2 core. No problem at all.

You are probably running some other things beside your application so you have less cores than processes running thus you lose (at least) on context switching and cpu affinity (often all threads of a single application will be ran on the same core). Besides that you have to synchronize which is expensive thus slows down the application even more.