OpenGL error with cached component image

I’m drawing a waveform view that displays quite long audio files in a scrollable viewport. It also has the ability to zoom in and out, which I implemented by increasing and decreasing the width of the component inside the viewport.

Since the waveform itself doesn’t change very often, I set BufferedToImage to true to drastically improve performance.

Now I’m trying to enable OpenGL for the entire plugin (by attaching an OpenGL context to the top component) to improve performance further. It seemed to work great at first, but then when the waveform component gets too wide (it it’s a really long file or if I zoom in too far) it will of course hit the maximum texture size and fail to render…

I’m guessing that I will have to rethink the way that the viewport is used and how the waveform zoom is implemented? Thankful for any pointers or suggestions!

This might be helpful, in case you haven’t seen it:

1 Like

Thank you very much for that, I hadn’t seen it and it’s very interesting!

But even increasing the imageCacheSize to ridiculous amounts didn’t seem to help in this case…

Looking closer in the debugger I see that the error I get right after calling glTexImage2D() is 1281, “Invalid value”… Which I understand can mean a lot of different things?

If you’re able to test on Windows/Linux with setOpenGLVersionRequired (openGL4_3), you should get slightly more descriptive output when an error occurs.

Sounds like it’s trying to upload a texture that is bigger than the maximum allowed size.

If you use setBufferedToImage, JUCE will use the CPU renderer to draw/cache to an image in CPU memory.
Then if the component is drawn, the CPU texture gets uploaded into GPU memory (glTexImage2D).

Each GL version/drivers comes with a texture size limit. It can be queried with glGet* and GL_MAX_TEXTURE_SIZE.
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGet.xhtml

If you lookup gpuinfo.org you’ll see that this capability is not as big as you may think.
OpenGL Hardware Database by Sascha Willems

1 Like

Yeah, that’s my guess as well, since the texture is 96808 x 134 at the time of the assert!
I was thrown off a bit because getAllowedTextureSize() returns the original dimensions (which would indicate that the size is OK), but that function might not be working the way it should (or the way that I’m expecting it to)…

Ideally I would just want to render the parts that are visible in the viewport right now, even though it would mean a lot of redrawing when scrolling and zooming – I still think the performance will be better, and above all more predictable.

I guess that would mean having a child component inside the viewed component (in the viewport) that is the size of the viewedArea and just paint inside that. It will get a bit complicated and I’ll have to rewrite a fair amount of code, but it will feel better to have something that doesn’t depend on the length of the sound files… And that hopefully works on a larger range of GPUs!

A followup on this, I managed to find a solution the other night that worked great for me:

I added a child component to the viewed component, and I use this child component for drawing only. The child component always corresponds to the visible area in the viewport, so it moves along when you scroll the view.

This means that I have to redraw it whenever the viewport is scrolled, but it’s a relatively small area (and most importantly of a predictable size!), so it doesn’t take that long to draw. Since I now know exactly how big the component is, I can cache it without the fear of reaching the texture size limit, so I can move playheads etc on top of the waveforms at a very low cost.

From what I’ve seen so far, the performance is pretty good now! :slight_smile:

1 Like