I usually use the latest GL only. Today that would be GL 4.2 core profile. Or GLES2.
Sure the old fixed function pipeline and immediate mode are gone. But the API still sucks. Bind-to-modify semantics, using integers for handles, global state everywhere, etc. They are the big problems, for both, users and implementors.
And I don't really know what 'global state everywhere' means. Do you mean that you keep OpenGL-related info in your program's global state? In that case, you should be using some AppState object to keep the state (and pass a pointer around). Otherwise, what global state is there "everywhere"?
glBindTexture(GL_TEXTURE_2D, my_texture_handle);
glTexImage2D(GL_TEXTURE_2D, ....);
Why not: glTexImage(my_texture_handle, ....);
In addition to being used for accessing and modifying, the bindings are global values that affect rendering. In the example above, it affects which texture is used on the texture unit that has been selected by glActiveTexture. What a mess.> With my limited knowledge of OpenGL, I know you get a number, describing a resource in video card memory. I bet for an OpenGL implementation, binding a resource id means finding a pointer to the resource. Sounds reasonable to me.
Wrong. There's a lot of software in between, before we start talking about GPU resources, so it refers to a structure on the CPU side. The integer-to-pointer lookup in between is another cache miss that we don't need (it has measurable L1 cache effects). This has, to some degree, been worked around by adding state objects like "Vertex Array Objects" (similar to D3D input layout).
> Would you rather get an invalid pointer that you should refrain from dereferencing (because you'll be reading from RAM, not GPU RAM)? That would've been a disaster.
Opaque pointers are used quite a lot in that way (e.g. D3D, via object pointers), it's a common idiom in C that adds a little type safety and documentation. In this case the pointers would be internal structures in the GL driver's user space. But you should not dereference them anyway. Unix uses integers as handles because the stuff it refers to is inside kernel memory, and you could poison the kernel by giving invalid pointers.
> Do you mean that you keep OpenGL-related info in your program's global state? In that case, you should be using some AppState object to keep the state (and pass a pointer around).
I don't. OpenGL does. In OpenGL, you have a global variable (actually: thread local) called the "context" which contains all the state of the rendering pipeline. In essence, it's a global variable that has side-effects when you access it.
Macro?
It has 1) inescapable measurable performance overhead and 2) affects state that changes the rendering output.
So if you macro it, you're forcing yourself to calling glBindTexture even in the cases where that wasn't necessary. (say, if you had just called glBindTexture and knew that the right texture was bound anyway). And, in addition, you have to remember to store the previous state of the bound texture in case someone down the execution path wants to use that value. Macroing things which change global state is, in general, a terrible idea.
If you don't macro it, your code has to remember whether the right texture has been bound, and design around that. It can be done for sufficiently simple cases, but the general solution also has performance overhead (checking a local variable before calling glBindTexture will get you into branch misprediction problems)
You can imagine complicated solutions like state batching: writing a better, retained-mode domain-specific language atop OpenGL which will analyze the sequences of your calls before making it, and then remove all the unnecessary glBindTexture, etc. calls. But it's a major pain in the ass that simply shouldn't exist.
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, ...);
vs glTextureImage2DEXT(texId, GL_TEXTURE_2D, ...);