fillRectList on openGL Graphic Context efficiency


#1

Trying to optimize graphic display in my plugin.
I have a bunch of almost vertical 1 pixel width bars, stucked together, same colour.

fillRectList is very fast on CoreGraphics. But using it in a OpenGL grahic context is dramatically slow - even the Software Renderer is faster.
It looks the cluster is cut into thousands of quad-vertex (sorry no GL Expert) via the EdgeTable?, but in a very inefficient way.

Is there a way to draw these Rectangles, straightforward, without this weird EdgeTable- Transformation, directly as gl-quads, like it is done in the CoreGraphics renderer?

PS: without using pure gl-commands


#2

wow, it looks like the renderer drops down anything as horizontal lines, wow this is pretty inefficient, if you draw single vertical lines :frowning:

I also tried to simulate painting rectangles, via reduceClipRegion & fillAll(), but it has the shows the same inefficient behavior.


#3

Yes, that’s true. The renderer will always use horizontal lines which can result in thousands of vertices. Still, OpenGL should have no problem rendering thousands of vertices - however, calculating the edge table can take some time. A few tips:

  • as the boundaries of the edge tables are calculated on the CPU, turning on compiler optimizations will really speed this up
  • can you somehow cache the graphics to an image? JUCE’s opengl renderer is very fast at drawing images.

#4

No, its definitely not fast enough for my purpose. And it wastes the whole potential of OpenGL.
I already use rendering on a background thread (isolated from the message thread). I think there is an enormous potential for optimizing which should be used.

(Especially drawing Waveforms!)

If i render the same lines horizontally -> its 100x faster, i think it should be not to complicated to modify the renderer that at least plain colored rectangles or horizontal lines will be rendered with less vertices. Especially this is important for people which using openGL for android, which still using pure CPU rendering.

BTW: Jules already mentioned rectangle rendering: “which is optimised to use a minimal number of triangles”, but it seems not true (maybe its just a bug/unintended?)


#5

Just spoke to Jules and he re-iterated what he wrote in that post. It should not being going down the EdgeTable path if your rects have integer coordinates and there is no clip-region. Can you step through the code (or provide simple code for us to reproduce) and see why the slow path is being taken?


#6

Look at the other thread:

I modified the ShaderQuadQueue to create each quad with a different colour

 void add (const int x, const int y, const int w, const int h, const PixelARGB colour) noexcept
    {
        jassert (w > 0 && h > 0);

        VertexInfo* const v = vertexData + numVertices;
        v[0].x = v[2].x = (GLshort) x;
        v[0].y = v[1].y = (GLshort) y;
        v[1].x = v[3].x = (GLshort) (x + w);
        v[2].y = v[3].y = (GLshort) (y + h);

       #if JUCE_BIG_ENDIAN
        const GLuint rgba = (GLuint) ((colour.getRed() << 24) | (colour.getGreen() << 16)
                                    | (colour.getBlue() << 8) |  colour.getAlpha());
       #else
        const GLuint rgba = (GLuint) ((colour.getAlpha() << 24) | (colour.getBlue() << 16)
                                    | (colour.getGreen() << 8) |  colour.getRed());
       #endif
        
        static int test=0;
        test++;

        v[0].colour = rgba+test*255;;
        v[1].colour = rgba+test*255;
        v[2].colour = rgba+test*255;;
        v[3].colour = rgba+test*255;;

        numVertices += 4;

        if (numVertices > numQuads * 4 - 4)
            draw();
    }

Than compile the JUCE demo, and choose OpenGL as rendering engine (i use mac OS Retina Screen)

Also i found no way how to directly draw a integer-rectangle with a few triangles. (See stack)
No matter what i do, the SubRectangleIterator or SubRectangleIteratorFloat gets involved.

Both could be optimized, to draw the the space between the first, last, left & right line with only one Quad.

void juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::SubRectangleIterator::iterate<juce::OpenGLRendering::StateHelpers::EdgeTableRenderer<juce::OpenGLRendering::StateHelpers::ShaderQuadQueue> >(juce::OpenGLRendering::StateHelpers::EdgeTableRenderer<juce::OpenGLRendering::StateHelpers::ShaderQuadQueue>&) 
#1	void juce::OpenGLRendering::StateHelpers::ShaderQuadQueue::add<juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::SubRectangleIterator>(juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::SubRectangleIterator const&, juce::PixelARGB)
#2	void juce::OpenGLRendering::SavedState::fillWithSolidColour<juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::SubRectangleIterator>(juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::SubRectangleIterator&, juce::PixelARGB, bool) const
#3	juce::RenderingHelpers::ClipRegions<juce::OpenGLRendering::SavedState>::RectangleListRegion::fillRectWithColour(juce::OpenGLRendering::SavedState&, juce::Rectangle<int> const&, juce::PixelARGB, bool) const 
#4	juce::RenderingHelpers::SavedStateBase<juce::OpenGLRendering::SavedState>::fillTargetRect(juce::Rectangle<int> const&, bool)
#5	juce::RenderingHelpers::SavedStateBase<juce::OpenGLRendering::SavedState>::fillRect(juce::Rectangle<int> const&, bool) 
#6	juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::OpenGLRendering::SavedState>::fillRect(juce::Rectangle<int> const&, bool) 
#7	juce::Graphics::fillRect(int, int, int, int) const

#7

Fabian - if there’s some optimisation magic for integer, non-clip region rectangle fills it’d be super useful if that statement could make it to the documentation…


Mutiple OpenGLContext issue
#8

And if we have this, it could be easily used to draw the float rectangle too.
Just cut out the integer part, and draw that optimized. Clipping a rectangle is also not to complicated.

Any feedback from @jules or @fabian?