What I prefer in GUI (window management related) is to update everything into a pixel based backbuffer. This way one could react onto changes very location related, for example a button change will affect only the button rect area. It has two effects that provide some benefit for the application:
- Whenever the OS requests a redraw, one can send the entire buffer instead of drawing everything on demand. This speeds the redraw up a lot, you can process GUI changes in parallel and/or on another thread and you could also modify single pixels
- Since you're not doing draws on the GPU, you don't stress the framerate unless OS requests redrawing on a high frequency
In UI (game related) we have to deliver performance. This means optimization of the rendering process, baking UI elements together into as few draw calls as possible since GPUs are very good at performing as much vertex processing as possible in parallel. So a switch between VBOs is more costly than batching a lot of static geometry together. It becomes difficult if UIs change a lot, for example by typing or if the HUD has a lot of dynamic elements. Text can be made very easy by a shader that moves a texture depending on the glyph currently used while the framework has to manage dynamic UI in a smart way.
I've implemented the text thing very efficiently for several projects. Mostly debug text and ingame command line but that doesn't matter ? The system requires one texture font and at least one control texture, that has the character ID set (and probably a position encoded in case of the command line/debug text) that's it. The shader is then processing the command texture and prints text to the screen.
Both ways are art friendly or at least they can be if they're designed well. Our GUI system is entirely data driven, the look and feel of the elements is determined by the provided data consumer whenever an element is layouted and/or drawn. It is based on a DOM or graph like in HTML or XAML (WPF) so data is provided very efficiently and can be customized to support new elements very well. The UI engine component is designed to work somehow similar but the graph is already compiled into a faster binary format since we need to know which components belong together, which ones are animated and how so we could manage them either by shader (best performance) or code (requires an own VBO and decreases per frame performance) and so on. Everything to keep rendering efforts low and frametime high