How to distinguish between OpenGL and Metal shaders?

SpriteKit transparently supports both OpenGL and Metal, with the click of a mouse button (more precisely, with one setting in the Info.plist file).


Perhaps a bit too transparently.


The problem is, shaders in OpenGL and in Metal use slightly different syntax, and are thus not interchangeable. Unless you restrict yourself to an astonishingly small common overlapping subset of both, you need to know which kind of shader source to supply to SKShader.


But how? As far as I can gather, there is no way of knowing which API is being currently used. Either one could, and there's no way of knowing. There appears to be no way of forcing the application to use only Metal. It could be either one, and there doesn't seem to be any way of knowing which. (For a concrete example, if you enable Metal, your app will probably run using the Metal API on an iOS/tvOS device, but still using OpenGL on the simulator. There doesn't seem to be any way of making the simulator use Metal. And anyway, I suppose in theory with some devices the app could still be run using OpenGL.)


If you supply the wrong shader source code to SKShader, it will probably not compile, and the shader won't work at all.


How is this supposed to be done?

Replies

And by the way, I need to add a correction to my original post: The problem is not actually in SKShader, but in SCNMaterial shader modifiers. SKShaders will transparently transliterate glsl source to Metal. However SCNMaterial shader modifiers apparently do not.


If I could get the info from somewhere which API is being currently used, I could write two versions of the shader, and choose at runtime which one will be used as the shader modifier. (I need to do this with SCNMaterial because I need to use an SK3DNode that uses a vertex shader.)

I found the actual source of the problem.


It seems that SceneKit does support shader source code written in glsl even in SceneKit, and even if Metal is actually being used. It transparently detects if the source is glsl, and transliterates it to Metal.


The problem was that it requires for all uniforms to be declared one at a time, rather than comma-separated. I had the equivalent of this:


uniform mat4 a, b, c;


but the SceneKit shader modifier glsl-to-Metal transliterator requires it to be like this:


uniform mat4 a;
uniform mat4 b;
uniform mat4 c;


When I changed the shader like this, it started working.