2

I have developed a mobile game with OpenGL ES 3 on Xamarin (Which uses OpenTK). It's running fine on most devices, but crashes on some devices (HUAWEI Y5 lite). Unfortunately I don't get a detailed log of the error:

  #00  pc 0000000000093d2a  /vendor/lib/egl/libGLESv2_mtk.so
  #01  pc 000000000001c137  /vendor/lib/egl/libGLESv2_mtk.so
  #02  pc 000000000001eddf  /vendor/lib/egl/libGLESv2_mtk.so
  #03  pc 000000000001af75  /vendor/lib/egl/libGLESv2_mtk.so
  #04  pc 000000000001aabf  /vendor/lib/egl/libGLESv2_mtk.so (glDrawElements+54)
  #05  pc 000000000000ca0c  <anonymous>

I'm guessing it has something to do with my draw code or worse with some driver issues of the phone. I'm using the following code to render quads:

public void BeforeRender()
{
    // Use shader program.
    GL.UseProgram(shader.Program);

    // Enable transparency
    GL.Enable(EnableCap.Blend);
    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

    // Use texture
    GL.ActiveTexture(TextureUnit.Texture0);
    GL.Uniform1(shader.UniformTexture, 0);

    // Only bind once for all quads
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferId);
}

public void Render(Sprite sprite, Vector4 color, Matrix4 modelViewProjection)
{            
    // Set model view projection
    GL.UniformMatrix4(shader.UniformModelViewProjection, false, ref modelViewProjection);

    // Set color
    GL.Uniform4(shader.UniformColor, color);

    // Set texture
    GL.BindTexture(TextureTarget.Texture2D, sprite.TextureId);

    // Update attribute value Position
    GL.BindBuffer(BufferTarget.ArrayBuffer, sprite.Vbo);
    GL.VertexAttribPointer(shader.AttribVertex, 3, VertexAttribPointerType.Float, false, sizeof(float) * 5, IntPtr.Zero); // 3 + 2 = 5
    GL.EnableVertexAttribArray(shader.AttribVertex);

    // Update attribute value TexCoord
    GL.VertexAttribPointer(shader.AttribTexCoord, 2, VertexAttribPointerType.Float, false, sizeof(float) * 5, new IntPtr(sizeof(float) * 3));
    GL.EnableVertexAttribArray(shader.AttribTexCoord);

    // Draw quad
    GL.DrawElements(BeginMode.Triangles, faceIndexes.Length, DrawElementsType.UnsignedShort, IntPtr.Zero); 
}

public void AfterRender()
{
    // Unbind / Disable
    GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
    GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
    GL.Disable(EnableCap.Blend);
}

To draw multiple quads I just call the methods like this:

BeforeRender();

foreach(var sprite in sprites)
{
    Render(sprite);
}

AfterRender();

Is there something wrong with my code in general which might cause problems on some devices which other devices "tolerate"?

Thanks in advance!

Update:

Here is how I create the buffers:

public int Load<T>(T[] data) 
        where T : struct
    {
        int bufferId;

        GL.GenBuffers(1, out bufferId);

        bufferIds.Add(bufferId);

        GL.BindBuffer(BufferTarget.ArrayBuffer, bufferId);
        GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
        GL.BindBuffer(BufferTarget.ArrayBuffer, 0);

        return bufferId;
    }

For the index buffer i use:

ushort[] faceIndexes =
        {
            0, 1, 2, 1, 3, 2
        };

indexBufferId = bufferManager.Load(faceIndexes);

For the vertex buffer I use:

float[] vertices =
            {
                0f, 0f, 0f, 0f, ty,
                width, 0f, 0f, tx, ty,
                0f, height, 0f, 0f, 0f,
                width, height, 0f, tx, 0f
            };

int vboId = bufferManager.Load(vertices);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Snaketec
  • 471
  • 2
  • 14
  • 2
    How do you create the `BufferTarget.ElementArrayBuffer` buffer? – Rabbid76 Sep 02 '20 at 14:20
  • 1
    I updated my question with the code. BufferTarget.ElementArrayBuffer is just an enum. Thanks to your question I noticed, that I always use BufferTarget.ArrayBuffer inside the Load method. Do you think this might cause the problem? – Snaketec Sep 02 '20 at 14:38

2 Answers2

2

The indices have to be store to an ElementArrayBuffer rather than an ArrayBuffer:

GL.BindBuffer(BufferTarget.ArrayBuffer, bufferId); ...

GL.BindBuffer(BufferTarget.ElementArrayBuffer, bufferId);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);

Add a target argument to the generic Load method. For instance:

public int Load<T>(T[] data, BufferTarget target) 
    where T : struct
{
    int bufferId;
    GL.GenBuffers(1, out bufferId);
    bufferIds.Add(bufferId);

    GL.BindBuffer(target, bufferId);
    GL.BufferData(target, (IntPtr)(data.Length * Marshal.SizeOf(default(T))), data, BufferUsage.StaticDraw);
    GL.BindBuffer(target, 0);

    return bufferId;
}
indexBufferId = bufferManager.Load(faceIndexes, BufferTarget.ElementArrayBuffer);
int vboId = bufferManager.Load(vertices, BufferTarget.ArrayBuffer);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • 1
    Thanks for your fast answer. It's exactly how I did it now. You clearly discovered an inconsistency in my code. I will mark this answer as solved as soon as I get a feedback from the Android vitals or my customers! – Snaketec Sep 02 '20 at 14:49
  • Unfortunately it did not solve the problem. The error still occurs on some devices. – Snaketec Oct 10 '20 at 08:04
  • @Snaketec *"on some devices"* - so the issue is solved, but you have a different issue on some devices which is related to the hardware. – Rabbid76 Oct 10 '20 at 08:07
  • Not really because it was originally occuring only on some devices as I mentioned in the original question "HUAWEI Y5 lite". So it actually didn't change anything (Because it occurs on the same devices). I would like to mark it as solved but that would not be true. – Snaketec Oct 10 '20 at 08:12
  • @Snaketec So the issue is not related to the code. It is related to the hardware. – Rabbid76 Oct 10 '20 at 08:17
0

I have found the issue, that was causing my app to crash on some devices. Apparently there was an item slipping in to the drawing routine, which was passing a buffer id 0 into GL.BindBuffer. On some devices this was causing the following error when Gl.DrawElements was called: emuglGLESv2_enc: sendVertexAttributes: bad offset / len!!!!! The solution was of course to not execute this code anymore whenever the buffer id is 0 or no buffer for the id was created. In my case the 0 was not returned by GL.GenBuffers. I had some sprites which should be empty (not rendered), and my orignal solution was to set the buffer id to 0.

Snaketec
  • 471
  • 2
  • 14