Yeah pretty much that, AnimatedAppComponent is just a few lines wrapper around Timer, I tend to implement this behaviour myself too usually, activating/deactivating it only when needed.
Just wanted to add some related things to look out for, since I recently went through a pretty heavy software rendering rollercoaster trying to get a fancy visualizer to render fast enough. I ended up implementing my own antialiased line plotter and used all kinds of 1990s demoscene approaches to get this fast enough, since it turned out that using any of JUCEs path drawing or blending things killed performance too quickly - and what I rendered wasn’t even close to fullscreen
this is about software rendering - if you are okay with using opengl, maybe check out NanoVG as a lightweight solution for rendering a few things.
some learnings for CPU rendering:
shared ui performance in plugins:
if we’re talking plugins, ui performance is usually shared with other plugin instance in one single thread. a good test is using Reaper and testing how many instances of your plugin ui you can open at the same time until Reapers UI freezes to a standstill. prepare to raise your eyebrows, it might be worse than you expect. (bonus challenge: enable 2x high dpi)
pretty much what has been written here already. if something is not opaque, the underlying components must be rendered. buffering to images may help, but in case of software rendering it mostly comes down to fillrate/memory access.
repaint debugging and profiling:
enabling repaint debugging, having the invalidated components flash in random colors, helps getting an idea what is being rendered. try to layout your components in a way that they do not overlap, even if one pixel of an underlying component overlaps with a transparent component on top of it, it’s paint method will be called. clipping reduces some pixel access, but doesn’t help much more.
in addition to that, it’s a good idea to add some highresolutionticks time measurements to various paint calls, or just do it in Component and log everything.
paint calls unnecessarily exceeding screen FPS a lot:
this may be mitigated in juce7, haven’t checked yet how well it works - but as far as juce6 goes, on windows there was no limit on the repaints - as soon as something invalidated, that led to a paint, as fast as the windows message dispatcher can go, potentially executing hundreds of repaints per second.
this can be caused by automated parameters attached to sliders, for example - but mouse events can cause it too, e.g. when dragging a slider. so if you do a performance test in Reaper with a few open windows, add some automation and use a small audio buffer size to cause tons of ui invalidations and take this into account for rendering performance.
in addition to what was already mentioned, it’s a viable option to write own renderers for particularly heavy things in your ui, avoiding the overhead of JUCEs drawing methods. from my experience, directly pushing rgba data into an image on a low level basis does work if you are careful with pixel formats etc. think of it like writing shader code on the CPU and try to touch each memory address only once, using small acceleration structures, and avoiding all the method call overhead that typically occurs when using the juce graphics API (just step into the deceptively innocent looking drawLine).
make sure to take actual rendering dpi into account, because any resampling should be avoided at all costs when not using hardware acceleration. but blitting without a transform is as fast as it can get.
with the same approach, I “baked” background graphics that rarely change into an image. you can do this with buffering components to images, but in some cases it may be worth doing this yourself, with the opportunity of creating a shared cache and reusing previously created versions at the cost of a few megabytes of ram.
just my two cents, maybe it gives you some further ideas optimizing your rendering.