Yeah, GLs global state is awful. The least-bad way to deal with it is to build your own pipeline abstraction on top, similar to the native pipeline constructs of newer APIs like WebGPU, so most of the messy global state manipulation is centralized in your "bindPipeline" function. Then the rest of your codebase can mostly pretend it's running on a sane (albeit dated) API instead of a giant ball of spaghetti.