While working on the HorusUI immediate mode GUI which will be used for the editor (instead of Qt or other libs, tried dear imgui but it was more like a debug viz ui), I have encountered a massive slowdown proportional with the number of drawcalls, logically. So, after the concept of the imgui worked, I’ve started to optimize for speed.
First, I was rendering around 200 batches (drawcalls), per frame, on a full GUI screen of widgets, that was bad. The culprit was that I was doing clipping on a lot of widgets contents, so of course I was setting scissor, also changing textures, etc., that’s why I needed so many drawcalls. I knew it but let it go while creating more and more functionality. So, to eliminate the many drawcalls, I have switched to a single texture atlas using a texture array which I set once so the shader can access all the textures at once. The atlas contains all the images used in the current theme plus all the font glyphs. When there is no more room in the current texture array slice for new images, a new texture is added to the array. The Vertex for the GUI rendering also has an auxiliary attribute called texIndex, which informs the shader what texture slice index is the current vertex using, so it will fetch texels from that image. So, from 200 drawcalls, now the GUI is using just 1 (or more if special rendering needs to be done, like with some custom texture or user related viewports, but I will strive to make it 1 also, by dynamic updating the atlas images with user images).
When new font glyphs are needed, they will be added to the dynamic atlas also. For the user images, that change often, for example an asset browser with tens of dynamic thumbnails, they can be updated fast on-place in the already allocated rectangles in the atlas, so it will stay constant size.