PDA

View Full Version : waterfall display



jmsbc
14th November 2008, 01:20
Hello,

Sorry I needed help in creating a "waterfall display" which basically takes in a 2 dimensional array of 8bit pixels and displays it streaming down the screen. This data is just 8bit pixel data and keeps streaming into my display.

Currently I just copy the data into a QImage with width and height equal to the size of the screen:

screenImage = new QImage(desktop.width(),desktop.height(),QImage::Fo rmat_Indexed8);

and print it to screen. Each time I have more pixel data coming in, I memmove the data in the qimage down and repaint the qimage using paintEvent.

Obviously this is kind of slow because I have to repaint the qimage each time. Can somebody please please help me optimize by explaining a better method or pointing me in the right direction?

Thank you,
James

wysota
14th November 2008, 08:08
Could we see the exact code? I mean the one used for filling the image with data and the one for rendering it to the widget.

jmsbc
14th November 2008, 17:56
Hi Wysota,

Thanks for replying. Sure, here is the general idea:



GLWidget::GLWidget(QGLWidget *parent)
:QGLWidget(parent)
{

// Initialize new QImage to 8bit format
screenImage = new QImage(desktop.width(),desktop.height(),QImage::Fo rmat_Indexed8);

/* Initialize image array */
for (int i=0; i<BUFFERSIZE; i++) {
imageBuffer[i] = (unsigned char)(i % 256);
}

/* Start timer to repaintevent */
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(animate()));
timer->start(10);
}

void GLWidget::animate()
{
update();
}

void GLWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);

/* Memcopy pixel data into my QImage FRAMESIZE lines at a time */
for (int i=FRAMESIZE-1; i>=0; i--) {
memcpy(screenImage->scanLine(i),&imageBuffer[(imageLine*imageWidth)%BUFFERSIZE],imageWidth);
imageLine++;
}

// Draw the QImage to screen
painter.drawImage(0,0,*screenImage);

// Shift qimage down to look like it is streaming down the screen
memmove(screenImage->scanLine(FRAMESIZE),screenImage->scanLine(0),linesFilled*screenImage->bytesPerLine());

}



Basically I'm calling paintEvent() as often as possible using the timer set on a small time interval. Please help as I've already been searching many hours on a good solution.

Thanks a lot!
-James

philwinder
14th November 2008, 21:48
Qwt (http://qwt.sourceforge.net/) has a spectrogram plot that you could animate? Could be ideal if you need more flexibility.

jmsbc
14th November 2008, 22:10
Hi Phil,

Sorry I should clarify, my Qimage has dimensions of my monitor, basically 1600X1200. So it is actually an image that's streaming down my display. I'm not sure if that spectrogram plot would work, but I'll take a look. Thanks.

In the meantime, Wysota do you have any hints? Thanks.

wysota
14th November 2008, 22:15
First thing to do is to change
timer->start(10); to
timer->start(50);. You won't be able to see 100 frames per second so you can safely limit it to 20 frames per second. You should immediately get a five times increase in speed ;)

Second of all you are murdering your processor data cache by processing data from the last line to the first one. Try reversing the order and you should get significant speedup there. It would also be a good idea to process data in larger chunks instead of single lines. Using a chunk of size equivalent to memory page size in your platform (like 1kB or 4kB) should result in a better speed as well.

All this should already give you much. If that's not enough, we can go further.

One more thing - don't expect miracles when scrolling such a large image. Currently used graphics architectures are not prepared for good scrolling performance (contrary to times where most games involved scrolling the "game board").

jmsbc
15th November 2008, 00:15
Wysota!

Thanks for your suggestions. However, the problem exists in the paintEvent not being able to draw a big QImage fast enough. Addressing your suggestions:

1. The timer is just set to be as fast as possible, so paintEvent gets called as often as possible. I changed it up to 50 but there's no difference because drawImage is the limiting factor.

2. Even if I change the memcopy/memmove functions around, they're not the limiting factor, drawImage() is. I tried changing my memcopy to copy bigger chunks of data but I still get the same performance.

I'm wondering if there some hardware acceleration that can be done to paint the images faster. Also are there other possibilites with openGL? I don't know much about graphics so if somebody could give me some guidance that would be great.

Thanks!

wysota
15th November 2008, 08:29
1. The timer is just set to be as fast as possible, so paintEvent gets called as often as possible. I changed it up to 50 but there's no difference because drawImage is the limiting factor.
Good.


2. Even if I change the memcopy/memmove functions around, they're not the limiting factor, drawImage() is. I tried changing my memcopy to copy bigger chunks of data but I still get the same performance.
If you still build the image from end to the beginning, you waste cycles which could be spent on rendering.


I'm wondering if there some hardware acceleration that can be done to paint the images faster. Also are there other possibilites with openGL?
Use your image as a texture for an OpenGL rectangle that you put orthogonally on your screen. Using some OpenGL extensions you'll gain additional speedup while building the texture if you don't build it from scratch at each frame but instead reuse what you already have.