Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe usage of glMapBufferRange() on Android/Java

I have working code using glMapBufferRange() from OpenGL-ES 3.0 on Android that looks like this:

  glBindBuffer(GL_ARRAY_BUFFER, myVertexBufferName);
  glBufferData(GL_ARRAY_BUFFER, myVertexBufferSize, null, GL_STATIC_DRAW);
  ByteBuffer mappedBuffer = (ByteBuffer)glMapBufferRange(
    GL_ARRAY_BUFFER,
    0, myVertexBufferSize,
    GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

  // [fill buffer...]

  glUnmapBuffer(GL_ARRAY_BUFFER);

My question is about downcasting the result of glMapBufferRange() to ByteBuffer on the third line. glMapBufferRange() is declared to return a Buffer:

public static Buffer glMapBufferRange (int target, int offset, int length, int access)

On my test platform the function returns a subclass of ByteBuffer so the cast works, but making this assumption for all platforms or Android versions supporting OpenGL-ES 3+ doesn't seem very safe. Although it seems reasonable, I haven't found any documentation that guarantees it, and if it were guaranteed it seems like the function should be declared as returning ByteBuffer.

What is the correct way (preferably supported by documentation) of using the Buffer returned by glMapBufferRange()?

like image 519
rhashimoto Avatar asked Apr 28 '15 13:04

rhashimoto


1 Answers

As you already found, the documentation is lacking. But there is still a fairly conclusive reference: The implementation of the OpenGL Java bindings is part of the public Android source code.

If you look at the implementation of the JNI wrapper for glMapBufferRange(), which is in the file glMapBufferRange.cpp, you can see that the buffer is allocated by calling a function named NewDirectByteBuffer(). Based on this, it seems safe to assume that the buffer is indeed a ByteBuffer.

While vendors can change the Android code, it seems very unlikely that anybody would change the behavior of the Java bindings (except maybe to fix bugs). If you are concerned that the implementation could change in later Android versions, you can certainly use a standard Java type check:

Buffer buf = glMapBufferRange(...);
ByteBuffer byteBuf = null;
if (buf instanceof ByteBuffer) {
    byteBuf = (ByteBuffer)buf;
}

Or you could use more elaborate reflection, starting with calling getClass() on the returned buffer. The next question is of course what you do if the returned buffer is not a ByteBuffer. It's really the only type that makes sense to me.

like image 58
Reto Koradi Avatar answered Oct 27 '22 15:10

Reto Koradi