[Qt-interest] fastest way to draw everchanging pixels

Sean Harmer sean.harmer at maps-technology.com
Sat Mar 21 18:47:57 CET 2009


Hi,

On Saturday 21 March 2009 14:53:26 you wrote:
> > Try reducing the number of function calls by calculating the positions
> > of each kind of point (gas molecules and walls) then just make two calls
> > to QPainter::drawPoints( const QPointF* points, int pointCount ) (or the
> > integer equivalent if you are not using QGraphicsView).
>
> I try to understand your suggestion: You're saying that I should create a
> list of QPointF which represent the visual area and set the color/status of
> these points after each iteration and then call QPainter::drawPoints( const
> QPointF* points, int pointCount ).
>
> The visual area is at max 1280x1024, so keeping a list of this size is not
> that bad, but not optimal either. But: isn't this even worse? I'll now have
> to change the color of any point (since with my initial approach the
> drawing area is cleared before I re-draw pixels).
>
> Ah, you mean since the number of walls and atoms is constant that I only
> create a list of atoms/walls and change their position. But now I have 2
> function calls per atom/wall ...
I mean to maintain an array of molecules and an array of walls. Then implement 
a function to update their positions. Then after their positions have been 
updated simply make one call to draw the molecules and one more call to draw 
the walls. Something like the attached. The important parts are:

class SimulationItem : public QGraphicsItem
{
public:
    SimulationItem( QGraphicsItem* parent = 0 );
    ~SimulationItem();

    virtual QRectF boundingRect() const;
    virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* 
option, QWidget* widget = 0 );

    void updateMolecules();

private:
    QPen m_moleculePen;
    QPen m_wallPen;
    QVector<QPointF> m_molecules;
    QVector<QPointF> m_walls;
};

void SimulationItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* 
option, QWidget* widget )
{
    //qDebug() << "SimulationItem::paint()";
    Q_UNUSED( option );
    Q_UNUSED( widget );

    // Draw the bounding rect of the simulation region
    painter->drawRect( QRectF( 0.0, 0.0, 1024.0, 1024.0 ) );

    // Draw all of the molecules in one go
    painter->setPen( m_moleculePen );
    painter->drawPoints( m_molecules.data(), m_molecules.size() );

    // Draw all of the walls in one go
    painter->setPen( m_wallPen );
    painter->drawPoints( m_walls.data(), m_walls.size() );
}

void SimulationItem::updateMolecules()
{
    /** \todo Implement real modelling code in here. If this is not performant 
restructure to use worker thread if on multi-core machine. */

    // For now just move molecules a little bit
    int moleculeCount( m_molecules.size() );
    for ( int i = 0; i < moleculeCount; ++i )
    {
        double dx = 2.0 * qrand() / RAND_MAX - 1.0;
        double dy = 2.0 * qrand() / RAND_MAX - 1.0;
        m_molecules[i] += QPointF( dx, dy );
    }

    // Force an repaint
    update();
}

As you can see we only make 5 calls to QPainter to draw the entire scene 
including setting the custom pens for molecules and walls.

The attached app creates 50000 molecules and 1000 walls and initialises them 
to random positions. We then set off a timer to update and re-draw the scene 
every 40ms. On a 2.4GHz Core 2 Duo this uses approx 22-25% of the CPU.

I'm guessing that your modelling code will be a little more complex than my 
dummy version in here :-) However if you are running on a multi-core machine 
there will likely be some benefit to doing the modelling updates in a worker 
thread. If you do this then I would advise you to refactor the example code so 
as do separate out the modelling from the drawing (good idea anyway).

I have added comments on what to do to enable this to use OpenGL updates to 
squeeze a little more performance out of your machine if you can use it.

HTH a little,

Sean

ps If your walls are really line segments then you would be better off storing 
them as QLineF's and calling QPainter::drawLines().
-------------- next part --------------
A non-text attachment was scrubbed...
Name: simulation.tar.gz
Type: application/x-compressed-tar
Size: 2616 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20090321/0bf81e22/attachment.bin 


More information about the Qt-interest-old mailing list