Do you think this is a good idea to avoid absolute abstraction and write it directly in OpenGL ES 2.0?
Your main difficulties with this will concern those parts of the ES 2.0 specification that do not actually match OpenGL 2.1.
For example, you simply cannot plug ES 2.0 shaders through the GLSL 1.20 compiler on your desktop. In ES 2.0, you use things like precision indication; these are illegal designs in GLSL 1.20.
However, you can #define around them, but this requires a little manual intervention. You will need to insert #ifdef in the source shader file. There are shader compilation tricks you can do to make this a little easier.
Indeed, since GL ES uses a completely different set of extensions (although some of them are mirrors and subsets of GL desktop extensions), you can do this.
Each GLSL shader (desktop or ES) must have a "preamble." The first thing without comment in the shader should be the #version . Luckily for you, the version is the same between the desktop GL 2.1 and GL ES 2.0: #version 1.20 . The problem is this: the #extension list (if any). This allows the use of shader extensions.
Since GL ES uses different extensions from the desktop GL, you will need to modify this list of extensions. And since the chances are good, you will need additional GLSL ES extensions than GL 2.1 extensions, these lists will not only be a 1: 1 mapping, but also completely different lists.
My suggestion is to take advantage of the ability to generate GLSL shaders with multiple lines. That is, your actual shader files do not contain any preambles. They have only actual definitions and functions. The main body of the shader.
When running on GL ES, you have a global preamble that you will attach to the top of the shader. You will have another global preamble on the GL desktop. The code will look like this:
GLuint shader = glCreateShader(); const char *shaderList[2]; shaderList[0] = GetGlobalPreambleString();
The preamble may also include the #define platform. User defined, of course. This way you can #ifdef code for different platforms.
There are other differences between them. For example, while valid ES 2.0 texture load function calls will work well on the desktop GL 2.1, they may not necessarily be optimal. Things that will load perfectly on large machines, such as all mobile systems, will require a bit of rotation from the driver on desktop computers with small hands. Thus, you might want to specify various pixel transfer options on the GL ES and the desktop GL.
In addition, there are different extension sets in ES 2.0 and Desktop GL 2.1 that you will want to use. Although many of them try to mirror each other (OES_framebuffer_object is a subset of EXT_framebuffer_object), you may encounter similar "not entirely subsets" like the ones mentioned above.