Because I have glanced at the API
It is much more streamlined than OpenGL because it lacks all the historical baggage. The rendering code is just cleaner and the logic is 'automatically' modularised (because of state immutability etc.)
Hmmm, I must admit I have just "scrolled over" the Metal API (so even less "glance" than you did obviously
), so I have not much knowledge there.
I based my previous answer basically on
http://renderingpipeline.com/2014/06/whats-the-big-deal-with-apples-metal-api/
which explains - in easy terms - what those "closer to the Metal" APIs do different that traditional OpenGL (or DirectX 11 and older, for that matter).
Well, with Metal and other APIs the sanity checks are just usually moved somewhere else (object creating phase). Also, the API itself gives less opportunity for error, because most state is immutable.
Yes, that is one aspect which was also mentioned in the above linked site. In OpenGL "shaders" might need to be "patched" by the OpenGL driver. For instance if one shader stage expects "int" data, but the previous stage delivers "float" (or vice versa). Then the OpenGL driver needs to implicitly add "conversion code" which converts "float" to "int".
As I understand in Metal that simply doesn't (can't) happen: shaders are validated "at construction time", and that's that. It's the up to the application to ensure that the shader stages are correctly wired.
And of course you have superior debugging capabilities. I am unsure though what happens if you mismatch the resources and the shader declaration (e.g. bind a 2D texture to a slot where a cube texture is expected), haven't had that much time to look though it. I guess you'd get undefined behaviour.
Yes, lack of debugging tools I also read a lot about elsewhere. But that actually uncovers another problem: "the unpredictability of a given OpenGL driver". And I don't mean "bugs" in the sense that the driver crashes or the resulting graphic is wrong, but how/when the driver decides to actually send the commands to the GPU - or when to patch (and re-load) the shader. So you end up with "command queue bubbles" (idle times), and don't really know why. Because it's all "hidden" in the OpenGL driver.
So from the above arcticle: "The Metal API reduces the time spend on the CPU by making state handling simpler and thus reducing error checks by the driver if the state combination is valid. Precomputing states also helps: not only can the error check be done at state build time, the state change itself requires fewer API calls."
And previously in that arcticle: " this way the application has full control over when the work is send to the GPU and how many frames delay it is willing to add (thus adding latency but increasing GPU utilisation).
Buffering GPU commands and sending them asynchronously in the next frame has to be implemented by the application itself."
And that "direct control" also brings more responsibility - and complexity, which was previously hidden in the "driver" - to the application!
But by carefully exploiting the knowledge an application has over its scene graph, the amount of "different objects" which require a state change the application can decide itself when to buffer what command, and when to finally send them to the GPU!
E.g. You have one huge mesh with the same texture or colour! Send the mesh and the draw command right away to the GPU! Thousands of little objects with different textures etc.? Buffer them first, batch them, only at the "beginning of the new frame" send them to the GPU.
(The above is just a simplified illustration, as I understand how those "closer to the Metal" APIs differ from OpenGL)
But this is not that different in OpenGL. You can still make a mistake and bind a wrong texture/uniform etc. And you might get undefined behaviour or a cryptic GL error. And debugging GL is a mess.
You're always supposed to get a "clean" GL error (which might or might not make sense to you). But the point here really is: it is the duty of the OpenGL driver to guarantee that you get such a GL error! Because it has to make those consistency checks.
With Metal you are on your own (my understanding): your synchronisation of command queues not done properly? Your bad! No one is going to tell you (unless you check the output on your screen yourself, please). In the worst case your application simply crashes, because you have deallocated a buffer which was still in use. Or you have overwritten data that is still in use "by the previous frame rendering pass".
For simple applications, nothing changes. You would use one command buffer and submit your drawing commands just as you would usually do in OpenGL. But you also have the choice to go one step beyond and have multiple command buffers.
Off course also OpenGL has advanced, e.g. you have "multi draw indirect": you first store all your draw commands, desired state changes and data in buffers, and then with a
single draw command you could basically draw your entire scene - including objects with different textures (which are all pre-loaded in VRAM, just like the draw commands themselves).
But we are talking OpenGL >= 4.3 here, which, as we all know, is not available on OS X...
And it is also possible to access OpenGL from multiple threads, as long as the GL context is made "current" for the given thread which accesses it. There is a free chapter in a book which described and compared various techniques, also with regards to "pinning memory" (for architectures which support that), but the conclusion was the usual: "depends on the GPU/driver/platform".
So yes, since those "closer to the Metal" APIs are simpler and designed "from the ground up" to be used in a multi-threaded way, the performance is much more predictable (especially since the application itself is in control).
BTW, Metal also guarantees correct drawing order! You can just be much more flexible about it. You can say for instance, that buffer 2 needs to be drawn after buffer 1, but you can submit the buffer 2 before buffer 1. The API is very simple and easy to use in this regard and gives you a lot of flexibility.
I guess you need to replace "can" by "must", if you really want to enforce that drawing order. And that's exactly the point where "closer to the Metal" becomes more complex than with a "driver which does it all for you": you
need to think about the correct order of buffers, commands etc., whereas with OpenGL the order of GL commands is the order you get. You don't even get access to the actual command buffer(s). And it's at the discretion of the OpenGL driver when it processes those buffers - but when it does it (finally), then in order.
So: more responsibility with "closer to the Metal" for the application, but much much more potential for (CPU) optimisation, more predictability of performance, simpler API ("no state changes allowed after creation", "only one way to set uniforms", etc.).
Whether Game Engines can exploit that potential, while providing the same flexibility ("shader languages"???) as when accessing those APIs directly, remains to be seen...
Because it's just not feasible for small game studios to invest so much into a "proprietary API" themselves (let alone "3D enthusiasts" like me, which are most likely interested in cross-platform solutions).