krisnye's picture

Differences between ES20.GL and OpenGL.GL

I am using the same source code file to handle my OpenGL rendering and my ES 2.0 rendering.

I just use some conditional compilation at the top, and the rest of the code in the page just refers to GL.SomeMethod.

#if ES20
using OpenTK.Graphics.ES20
#else
using OpenTK.Graphics.OpenGL
#endif

GL.VertexAttribArray(...) etc.

This works very well since I am basically sticking to the ES20 subset of functionality which is also supported by standard OpenGL.

The only pain is the instances of the ES20 API that are unnecessarily different from the OpenGL api's . These are often minor things like using REF for a parameter instead of OUT, or using the ALL enumeration instead of a more specific enumeration such as ProgramParameters.

Is there a plan to try to keep the methods as consistent as possible, and to provide the more specific OpenGL enumerations in the ES20 namespace?

I wouldn't mind helping with this effort, since I'm basically merging the differences anyways on my side.

For the lack of enumerations in ES20, I have to use using statements that alias OpenTK.Graphics.ES20.All enumeration. This is all very manageable for me, but it might be nice to merge the two more in order to simplify allowing others to use the same code with a small conditional at the top to compile against both OpenGL and ES20.

Here are some of the differences between the classes that don't seem necessary:

ES20 is missing all of the following Enumerations, so I have to alias them to the ALL enumeration:

using TextureTarget = OpenTK.Graphics.ES20.All;
using TextureParameterName = OpenTK.Graphics.ES20.All;
using EnableCap = OpenTK.Graphics.ES20.All;
using BlendingFactorSrc = OpenTK.Graphics.ES20.All;
using BlendingFactorDest = OpenTK.Graphics.ES20.All;
using PixelStoreParameter = OpenTK.Graphics.ES20.All;
using VertexPointerType = OpenTK.Graphics.ES20.All;
using ColorPointerType = OpenTK.Graphics.ES20.All;
using TexCoordPointerType = OpenTK.Graphics.ES20.All;
using BeginMode = OpenTK.Graphics.ES20.All;
using MatrixMode = OpenTK.Graphics.ES20.All;
using PixelInternalFormat = OpenTK.Graphics.ES20.All;
using PixelFormat = OpenTK.Graphics.ES20.All;
using PixelType = OpenTK.Graphics.ES20.All;
using ShaderType = OpenTK.Graphics.ES20.All;
using VertexAttribPointerType = OpenTK.Graphics.ES20.All;
using ProgramParameter = OpenTK.Graphics.ES20.All;
using ShaderParameter = OpenTK.Graphics.ES20.All;

ES20 GetProgramInfoLog is broken because it uses a string as it's last parameter.
ES20 GetShaderInfoLog is broken because it uses a string as it's last parameter.

Es20 GetProgram method uses a 'ref', opengl uses 'out'.
Es20 GetShader method uses a 'ref', opengl uses 'out'.

Es20 ShaderSource uses different parameters from OpenGL

ES20 GenTextures uses a 'ref', opengl uses 'out'.

ES20 UniformMatrix4 uses different parameters from OpenGL.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Yes, the plan is to make the APIs as consistent as possible.

  • The enums will be fixed in the 0.9.9-4 release (around next Sunday). Inertia has done the necessary legwork - all that's left is a modification to the generator and verifying that the new signatures are correct.
  • Get[Program|Shader]InfoLog should be fixed already (and will be available in the 0.9.9-3 release, today).
  • GetProgram, GetShader, GenTextures - I wasn't aware of this difference. Easy to fix, will also be available in 0.9.9-3.
  • ShaderSource, UniformMatrix4 - these overloads where written by hand for OpenGL, so they must be copied manually to ES.

Please post all other differences you come across. With the 1.0 quickly approaching, the sooner we can fix those the better!

krisnye's picture

Additional Methods that have the 'ref'/'out' difference:

GenBuffers => 'out' in opengl, 'ref' in es20
GenFrameBuffers => 'out' in opengl, 'ref' in es20
GenRenderBuffers => 'out' in opengl, 'ref' in es20

Thanks for the good news. This is the class I use right now to abstract the differences. I listed all of the ones I'm currently aware of in my previous post though, I will add any more that I come across. It is very cool using the same source code for Windows and for iPhone rendering... and I did get the AMD ES2.0 emulator running on windows, which really helps.

Btw- how long does it take for changes you make to get propagated to Monotouch builds?

   public static class GLM
    {
 
#if ES20
        [DllImport(OpenGLVersion.Library)]
        public static extern void glGetProgramInfoLog(int program, int bufsize, ref int length, StringBuilder infolog);
 
        [DllImport(OpenGLVersion.Library)]
        public static extern void glGetShaderInfoLog(int shader, int bufsize, ref int length, StringBuilder infolog);
#endif
 
        public static string GetProgramInfoLog(int program)
        {
#if ES20
            int length = 0;
            GL.GetProgram(program, ProgramParameter.InfoLogLength, ref length);
            StringBuilder log = new StringBuilder(length);
            glGetProgramInfoLog(program, log.Capacity, ref length, log);
            return log.ToString();
#else
            return GL.GetProgramInfoLog(program);
#endif
        }
 
        public static bool GetProgramLinkStatus(int program)
        {
            int status = 0;
#if ES20
            GL.GetProgram(program, ProgramParameter.LinkStatus, ref status);
#else
            GL.GetProgram(program, ProgramParameter.LinkStatus, out status);
#endif
            return status == (int)All.True;
        }
 
        public static bool GetShaderCompileStatus(int shader)
        {
            int status = 0;
#if ES20
            GL.GetShader(shader, ShaderParameter.CompileStatus, ref status);
#else
            GL.GetShader(shader, ShaderParameter.CompileStatus, out status);
#endif
            return status == (int)All.True;
        }
 
        public static string GetShaderInfoLog(int shader)
        {
#if ES20
            int length = 0;
            GL.GetShader(shader, ShaderParameter.InfoLogLength, ref length);
            StringBuilder log = new StringBuilder(length);
            glGetShaderInfoLog(shader, log.Capacity, ref length, log);
            return log.ToString();
#else
            return GL.GetShaderInfoLog(shader);
#endif
        }
 
        public static void ShaderSource(int shader, string source)
        {
#if ES20
            int length = source.Length;
            GL.ShaderSource(shader, 1, new string[]{source}, ref length);
#else
            GL.ShaderSource(shader, source);
#endif
        }
 
        public static int GenTexture()
        {
            int texture = 0;
#if ES20
            GL.GenTextures(1, ref texture);
#else
            GL.GenTextures(1, out texture);
#endif
            return texture;
        }
 
        public static void UniformMatrix(int location, Matrix4 matrix)
        {
#if ES20
            //  with ES20, we must pre-transpose the matrix before setting it.
            matrix.Transpose();
            GL.UniformMatrix4(location, 1, false, ref matrix.Row0.X);
#else
            GL.UniformMatrix4(location, true, ref matrix);
#endif
        }
 
        public static void TexImage2D(int width, int height, object pixelsIntPtrOrByteArray)
        {
            if (pixelsIntPtrOrByteArray is IntPtr)
            {
                IntPtr pointer = (IntPtr)pixelsIntPtrOrByteArray;
#if IPHONE
                GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormatType)PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, ref pointer);
#else
                GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormatType)PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pointer);
#endif
            }
            else
            {
                GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormatType)PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, (byte[])pixelsIntPtrOrByteArray);
            }
        }
 
    }
the Fiddler's picture

Starting with rev. 2382, ES 2.0 bindings should have the same API and helper methods as regular OpenGL. For the largest part, porting between ES and GL should be a matter of #if ES20 in the using directives.

I would appreciate it if you could download the es20 branch and double-check that the API works as intended. You'll need TortoiseSVN, if you don't already have it, and then you can checkout the code from https://opentk.svn.sourceforge.net/svnroot/opentk/branches/es20. Simply run Build.exe and open OpenTK.sln to build.

krisnye's picture

I will test that they work. I also build my classes for the iPhone Simulator using #ES20. How long will it be before these changes make it into the Monotouch project?

krisnye's picture

Ok, here's what I've found:

Different Enum names:
(OpenGL Enum => ES20 Enum)

VertexAttribPointerType => VertexAttribType
BeginMode => PrimitiveMode
StencilOp => StencilOperation
BlendEquationMode => BlendMode
BlendingFactorSrc/BlendingFactorDst => BlendFactor

Also:

ES20.GL.GetAttribLocation is wrongly using a StringBuffer parameter instead of a String.

the Fiddler's picture

Thanks, I will fix those issues.

I'm afraid I cannot answer your question, you will have to ask the MonoTouch developers about this. I have sent an email about the updated bindings, but there are some additional matters to be sorted before they can be brought to MonoTouch (ABI issues regarding ref vs out parameters).

the Fiddler's picture

These issues are fixed now. Please post if you encounter anything else!

krisnye's picture

2 Remaining Issues I have found:

BlendingFactorDest used in OpenGL, BlendingFactorDst used in ES20. (ES20 contains a BlendingFactorDst enum AND a BlendingFactorDest enum, but uses the former.)

Als0 Since BlendingFactorSrc and BlendingFactorDst are identical enumerations, why aren't they merged? or is that planned for later?

ES20 GetUniformLocation incorrectly uses a StringBuilder where it should use a String.

Inertia's picture

Actually it should be void BlendFunc( BlendFactor sfactor, BlendFactor dfactor ) it appears the changes did not make it in time.

I've renamed enums quite a lot in the cleanup, e.g. GL's BeginMode should be PrimitiveMode in ES. This was mostly done so the enums read more intuitive and less technical. (PrimitiveMode.TriangleStrip sure beats BeginMode.TriangleStrip, especially because ES 2.0 does not support Begin/End-block drawing)

"krisnye" wrote:

BlendingFactorDst enum AND a BlendingFactorDest enum

This is by design, the generator does not remove unused enums.

krisnye's picture

Let me know when complete and I'll test again.