Hello !
I’m implementing a digital phase oscilloscope with JUCE framework, but unfortunately, it is consuming a bit too much CPU - It does work, but it uses too much CPU!
I’ve made a little test application to illustrate the problems I’m encountering. At regular time interval, the main component redraws a set of random dots on itself. You can select the repainting rate, the number of dots and whether the position and/or the colour of the dots should be randomly generated at each repaint. [attachment=0]TestGuiApp3 - CMockOscillo.zip[/attachment] TestGuiApp3 - CMockOscillo.zip" contains a fully functional VS08 project (I actually have the problem under Win Vista, but I don’t think it is OS-related) as well as a Jucer file. I haven’t tried it, but it should allow you to generate any configuration you prefer. The *.jucer file was generated with the current most recent GIT Tip (5 Nov 2010 10:21:28)
My CMockOscillo class is a juce::Component with an Image* member (m_piBackGround) that stores the background of the oscillo (with no dot on it) At regular time interval (typically 30ms) a juce::Timer calls repaint(), and my paint methods does the following :
1° It ensures the stored image is still valid (regarding size, etc.) If not, it updates it.
2° It copies the image in the paint’s graphic context.
3° It finally adds all the dots with SetPixel() method.
…and that’s how simple it is. Here is my exact “paint” code (if you don’t feel like downloading all my app…)
Please look for the keyword “QUESTION” in the code below, these are my precise questions regarding how to optimize the code.
void CMockOscillo::paint(Graphics &g)
{
// The core of the job is done in this function.
////////////////////////////////////
// If needed, reallocation and
// repainting of the background
// image.
////////////////////////////////////
if(m_piBackGround) // if we have an image already...
{
if( m_piBackGround->getWidth() != getWidth()
|| m_piBackGround->getHeight() != getHeight()) // ...but its size is inappropriate...
{
delete m_piBackGround; // ...then delete the image !
m_piBackGround = NULL;
}
}
if(m_piBackGround == NULL) // If the image isn't ready.
// NB : either it's just been deleted, as size was wrong,
// or it has simply never been allocated. (first call of paint)
{
// allocate the image !
m_piBackGround = new Image(Image::RGB, getWidth(), getHeight(), false, Image::SoftwareImage);
jassert(m_piBackGround->isValid());
// QUESTION : What difference is there between a SoftwareImage
// and a NativeImage ? Which one would you recommend
// using in this case ?
// Redraw the background.
// NB : due to the above mechanism, this is only going to happen
// when size has changed, so I don't really care if some
// time-consuming operation happen here.
Graphics gBackGround(*m_piBackGround);
ColourGradient grad(Colours::black, 0.f, 0.f,
Colours::darkblue, (float)m_piBackGround->getWidth(), (float)m_piBackGround->getHeight(), false);
gBackGround.setGradientFill(grad);
gBackGround.fillAll();
}
////////////////////////////////////
// actual painting job.
// (performed at every call)
////////////////////////////////////
if(m_bRandomizeDotsPositions)
{
// If the user want us to generate
// new dot position, do so !
Random rdm(0);
rdm.setSeedRandomly();
for(int i = 0; i < m_nNbDots; ++i)
{
m_faDotsX[i] = rdm.nextFloat();
m_faDotsY[i] = rdm.nextFloat();
}
}
// Copy the (unaltered) background image
g.drawImageAt(*m_piBackGround,0,0); // QUESTION : Is it possible to make it faster, using one or the other JUCE class ?
// prepare dots' colour.
g.setColour(m_bRandomizeDotsColours
? Colour(Random::getSystemRandom().nextInt()).withAlpha(1.f).withBrightness(0.8f)
: Colours::yellow);
// draw the dots.
for(int i = 0; i < m_nNbDots; ++i)
{
g.setPixel((int)(m_faDotsX[i] * getWidth()), (int)(m_faDotsY[i] * getHeight()));
// QUESTION : After doing a little profiling, this loop seems to be where most time
// is spend. I suppose I could gain efficiency here, but how ?
//
// Would you recommend using Image::BitmapData ?
// - I don't need any aliasing (and SetPixel doesn't perform any anyway)
// - I can ensure that I don't jump out of the image as I know its size,
// and its size can btw only be changed by the present paint function.
// (I could add some critical section to protect from multiple thread
// calling this paint, just in case.)
//
// Should I rather copy the background to another member Image* (sth like
// "Image* CMockOscillo::m_piForeGround"), then light the pixels on this
// new image, and finally copy the foreground to the Graphic g ?...
}
}
///////////////////////////////////////////////////////////////////////////////
Thank you in advance for your help and hints !
Val
