Search code examples
androidopengl-esallocationbytebufferfloatbuffer

why do we allocate blocks in bytes rather than floats in OpenGL (ES) android , though we work with float most of the times


this is how i am made an array of triangle

float[] tableVerticesWithTriangle = {

                    // triangle 1
                    0f, 0f, 9f, 14f, 0f, 14f,

                    // triangle 2
                    0f, 0f, 9f, 0f, 9f, 14f

            };

and this is how i have allocated the block in native environment

 vertexData = ByteBuffer
                .allocateDirect(
                        tableVerticesWithTriangle.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
 vertexData.put(tableVerticesWithTriangle);

Solution

  • The reason people use ByteBuffer.allocateDirect() is that other buffer classes, like FloatBuffer, do not have an allocateDirect() method. Only ByteBuffer can be allocated as a direct buffer. So allocating a ByteBuffer, and then using the memory as a FloatBuffer, is the only way to get a directly allocated FloatBuffer.

    What is a direct buffer?

    The documentation of isDirect() of the FloatBuffer class explains it like this:

    Indicates whether this buffer is direct. A direct buffer will try its best to take advantage of native memory APIs and it may not stay in the Java heap, so it is not affected by garbage collection.

    A float buffer is direct if it is based on a byte buffer and the byte buffer is direct.

    In other (less formal) words, a native buffer is a native memory allocation that Java is not messing with.

    When are direct buffers required?

    Strangely enough, I have never been able to find clear documentation for this. So the following is a hypothesis that I confirmed with experiments, without finding any counter-examples so far.

    Direct buffers have to be used when a buffer is passed to an OpenGL API where the memory is used by the OpenGL implementation after the call returns.

    There is only one example of this I could find: client side vertex arrays (which BTW are marked as a legacy feature in ES 3.0, but still supported). This is the glVertexAttribPointer() call with the following signature, which supports vertex arrays without the use of VBOs:

    glVertexAttribPointer(int indx, int size, int type, boolean normalized,
                          int stride, Buffer ptr)
    

    In this case, OpenGL will pull vertex data from the buffer in later draw calls, so the buffer content has to remain accessible to OpenGL after the call returns, and will potentially be read directly by the GPU.

    In all other cases (again according to my hypothesis), it is not necessary to use direct buffers. You can for example do the following:

    float[] vertexData = {...};
    GLES20.glBufferData(GL_ARRAY_BUFFER, vertexData.length * 4,
                        FloatBuffer.wrap(vertexData), GLES20.GL_STATIC_DRAW);
    

    The glBufferData() call consumes the data during the call, and the original buffer can not be accessed by OpenGL after the call returns. Therefore, it is not necessary to use a direct buffer.