Looking for some general help about drawing Images efficiently and possibly using openGL

Hello hello,

My plugin is very visual based. In particular I have two components that are hogging up quite a bit of CPU. One is pretty much just and SVG that moves back and forth frequently and the other is some custom art that is animated by a film strip and flips through the different frames. I would really like to make these more efficient, and I have done quite a lot to optimize the repaint calls and what not so theres as few of those as possible.

I am on OSX and as I understand, atleast for the image based component, drawing the Image with open GL would probably be far more efficient than coreGraphics. This component is non-interactable and just needs to draw the image. However, this image has transparent parts and as I understand openGL doesn’t support transparent images. What would be the proper way to go about using OpenGl and drawing this image (or is this overkill and theres a more effecient way to do it with coreGraphics). Right now Im just using drawImageWithin to draw my Image.

Side Note: This is a really noob question so forgive me, but how do I “turn on” the JUCE_ENABLE_REPAINT_DEBUGGING flag.

$ /usr/bin/find . -type f -exec grep -Hn JUCE_ENABLE {} \;

./juce_gui_basics/juce_gui_basics.h:66: #define JUCE_ENABLE_REPAINT_DEBUGGING 0

Also in my first DAWn coding week-end session I added a Toolbar that reads svg files from a memory stream:
see:

You might be able to reuse so of the juce toolbar button image code?
see my new createButtonFromZipFileSVG() and
createZipStreamFromEmbeddedResource()

Thanks for the reply, so wait the paint debug flag gets enabled in terminal? And for the image drawing, Im not having any issue drawing the images and SVGs, just rather I have to draw them quite frequently and Im looking to lower the CPU cost of that.

Did you profile before trying to optimize anything?
how long does it take to display your image atm?

https://wiki.c2.com/?RulesOfOptimization

No it gets enabled in the file that I listed there, I just showed the shell code so that you could find it yourself in 1min next time so that u don’t need to ask

1 Like

Yes I have done some profiling. The drawing time for everything is perfectly fine. Essentially, I have a knob that when turned up to its fullest creates chaos on the screen by animating multiple components. When everything is fully animating, my CPU usage hits around 60-70%. After profiling, almost all of that is coming from repainting the animating components. As previously mentioned, Im looking to lower the CPU load from the repaints, which is why I was considering using OpenGL to draw some of the components if that would lower the CPU usage, and if so, how to go about doing so.

It seems OpenGL use may greatly help, there was a similar question (but not about svg) here:

But maybe just caching your svg rendered bitmap and reusing the cache might suffice, don’t know yet how it works there but I could have a look if you’re really stuck.

This looks like a very helpful thread! Thank you! I promised I searched the forums before posting lol

NP let’s call it noobs solidarity!

Mhm, you’d normally not modify juce source files to set such macros but define them in your CMake script or in the Projucer. If you are using CMake use target_compile_definitions to set such flags. If you are using the Projucer, these module config flags are nicely accessible through the module view in the Projucer

1 Like

Better indeed to have it autogenerated, searching through sources helps too as it provides you where it would be (juce_gui_basics) and where it is used in the code.

Totally agree that reading the juce sources and trying to get an idea of how things work is a good thing :slight_smile:

Okay so after a couple days, I got my plugin reworking using OpenGL and it saves quite a bit of CPU as predicted. If anyone can I would appreciate if someone could look at this snippet of code I have, built after reading openGL Juce Demo, to see if Im doing this correctly or if theres a way to improve my methodology.

So first I have a struct which basically just acts as drawing instructions. I have multiple of these, one for each animating component I have.
//=================================================================

struct Title : public Component
{
    Title() //
    {
        createImage();
    }
    
    void createImage() //Draws all SVGs into an image, called again when slider moves to adjust hue
    {
        colourPath = titleColours->getOutlineAsPath(); 
        colourPath.applyTransform(AffineTransform::translation(13.f,6.f));

        Graphics ID (titleImage);
        ID.addTransform(AffineTransform::scale(2.0f,2.0f));
        titleBack -> drawWithin(ID, Rectangle<float> {177.f,57.f,static_cast<float>(getWidth()),static_cast<float>(getHeight())}, RectanglePlacement(juce::RectanglePlacement::doNotResize),1.0f);
        ColourGradient titleGradient (editColour(Colour(0xfffc955b)),0.f,0.0f,editColour(Colour(0xfffb2b6b)),0.f,100.0f,false);
        ID.setGradientFill(titleGradient);
        ID.fillPath(colourPath);
        
    }
    
    void drawTitle(OpenGLContext* context, float desktopScale) // Draws the image and applies animation
    {
        std::unique_ptr<juce::LowLevelGraphicsContext> glRenderer (createOpenGLGraphicsContext (*context,desktopScale*getWidth(),desktopScale*getHeight()));
        if (glRenderer.get() != nullptr)
        {
            Graphics g (*glRenderer);
            g.addTransform(AffineTransform::scale(desktopScale/2,desktopScale/2));
            if (isJiggle)
            {
                float randX = randomNumber.nextInt(Range<int>(-3,3));
                float randY = randomNumber.nextInt(Range<int>(-3,3));
                
                g.drawImageAt(titleImage, 300 + randX, 0 + randY, false);
            }
            else
            {
            g.drawImageAt(titleImage,300,0,false);
            }
        }
    }
    
    void setHue(float newHue)
    {   hue = newHue/7; }
    
    void setJiggleFlag(bool jiggle)
    {
        isJiggle = jiggle;
    }
    
    Colour editColour(Colour initColour)
    {
        initColour = initColour.withRotatedHue(hue);
        initColour = initColour.withSaturationHSL(1.1f);
        return initColour;
    }
    
private:
    float hue = 0;
    bool isJiggle = false;
    Random randomNumber;
    
    std::unique_ptr<Drawable> titleColours = (Drawable::createFromImageData(BinaryData::titleColour_svg,BinaryData::titleColour_svgSize));
    std::unique_ptr<Drawable> titleBack = (Drawable::createFromImageData(BinaryData::titleBack_svg,BinaryData::titleBack_svgSize));
    Image titleImage {Image::ARGB,345*2, 115*2, true};
    Path colourPath;
};

Then in my main editor, Ive created an open GL context, and call title.drawTitle in my renderOpenGL method.

//=================================================================
DistortionPluginAudioProcessorEditor::DistortionPluginAudioProcessorEditor (DistortionPluginAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
//the openGlContext was created in the header
        setOpaque(true);
        openGLContext.attachTo (*this);
        openGLContext.setRenderer(this);
        openGLContext.setContinuousRepainting(true);
        setSize (660, 440);

}

DistortionPluginAudioProcessorEditor::~DistortionPluginAudioProcessorEditor()
{
openGLContext.detach();
}

void DistortionPluginAudioProcessorEditor::renderOpenGL()
{
    auto desktopScale = (float) openGLContext.getRenderingScale();

    if (openGLContext.getCurrentContext() != nullptr)
    {
        background.drawBackGround(openGLContext.getCurrentContext(), desktopScale);
        actionLines.drawActionLines(openGLContext.getCurrentContext(), desktopScale);
        title.drawTitle(openGLContext.getCurrentContext(), desktopScale); 
    }   
}

If anyone has any critiques about my code in general Id also appreciate feedback

Extra Question: My VST has no problem opening and closing, but sometimes when I drag my VST window onto another monitor, it causes this error

******* GL_INVALID_FRAMEBUFFER_OPERATION at /Users/Wiznat/Desktop/JUCE/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp : 1282**

JUCE Assertion failure in juce_opengl.cpp:216

As I hardly understand openGL, I really have no clue what causes this or how I would go about fixing it. I did not have this issue in a test project I used to practice the openGL module.