filling a jogl texture from c++

I’m using C++ code to draw some stuff on a regular bitmap and I want to use this drawing code for multiple projects (say a java and a c# client).

Currently I copy the C++ bitmap’s pixel array to java and put that in a jogl texture, but I was hoping I could remove the step of copying the pixels to java.
Is there any way I can pass the pointer of a jogl texture to my C++ dll and then update the texture data in C++? That would hugely improve my performance, if possible.

Use JNI’s NewDirectByteBuffer function to create ByteBuffer of your data, and pass it to Java. Then use it for updating the texture and no copy will occur :slight_smile: Beware of proper usage of ByteBuffer generated this way, it doesn’t automatically get freed, or can crash VM if it will be used when the original memory is already freed.

Your texture data is located at a pointer in C.

Pass that pointer to Java (a long primitive).

Then hack the fields of a direct ByteBuffer…


private static Map<ByteBuffer, Long> buf2oldBase = new HashMap<ByteBuffer, Long>();
public static synchronized ByteBuffer createByteBufferAt(long pointer, int capacity)
{
   ByteBuffer bb = ByteBuffer.allocateDirect(1).order(ByteOrder.nativeOrder());

    if(buf2oldBase.get(bb) != null)
      throw new IllegalStateException("should never happen, but is here for security");

   Field baseField = bb.getClass().getDeclaredField("base");
   baseField.setAccessible(true);
   Long oldBase = (Long)baseField.get(bb);
   baseField.set(bb, pointer);

   Field capacityField = bb.getClass().getDeclaredField("capacity");
   capacityField.setAccessible(true);
   capacityField.set(bb, capacity);

   bb.limit(bb.capacity());

   // when the reference to 'bb' is not kept, the base
   // pointer of 'bb' can get freed by the VM, very nasty!
   // so we have to restore the ByteBuffer at some point
   buf2oldBase.put(bb, oldBase);


   return bb;
}

public static synchronized ByteBuffer restore(ByteBuffer bb)
{
   Long  oldBase = buf2oldBase.remove(bb);
   if(oldBase == null)
      throw new IllegalArgumentException("buf was not created here, or already restored");

   Field baseField = bb.getClass().getDeclaredField("base");
   baseField.setAccessible(true);
   baseField.set(bb, oldBase.longValue());

   Field capacityField = bb.getClass().getDeclaredField("capacity");
   capacityField.setAccessible(true);
   capacityField.set(bb, 1);

   bb.limit(bb.capacity());

   // now the VM can safely free the ByteBuffer
   // and the backing base pointer
   return bb;
}

sourcecode NOT TESTED and typed… so expect some typo’s

Then use JOGL to upload the data at the pointer to the GPU with some OpenGL calls, in the proper Thread… something that’s rather hard to ensure when uploading directly in C.

Damn… did I just write a Java version of NewDirectByteBuffer…?

I think it would also be possible to activate the OpenGL context created by JOGL in your native code, load the texture there and return the GLUint ref to Java.

That sounds superb, I would love to get that working if possible.

So if I’m in the java code where the opengl context is active I want to call my C++ function and work the texture.
Main question will be, how do I get hold of the reference to one texture from both java and C++.

If I create the texture in java, like I do now, how can I refer to it from C++, is there anyway to get the pointer reference?
the jogl function gl.glGenTextures(1, tmp, 0); doesn’t seem to produce an id that I can use from C++…
The advantage of creating the texture in java is that I won’t have to change any java code and keep things really simple.

If I would do it the other way around and create a texture in C++ (sure I can manage using some redbook example),
how can I refer to it from java? If I have the texture_id GLUint in C++ can I just pass it to java and use it to active the
texture with gl.glBindTexture(GL.GL_TEXTURE_2D, texture_id); ?

Another concern would be how I can work on the same opengl context from both java and C++. Has anyone done
something like this, any thoughts?

That’s also a possible way. Though I’m assuming you’re using JOGL’s Texture class, which handles many cases for you, and is not simple GL_TEXTURE_2D like in OpenGL (eg. it handles texture2d vs texture_rect, non-power-of-two textures depending on OpenGL support on given machine, etc.). If this is the case, I would stick with the approach of using JNI’s NewDirectByteBuffer, which is fast and clean (for best results use the same memory area and cache the returned ByteBuffer). The managing of OpenGL additionaly in your C++ code is not worth the cost, if you want to just update texture data.

First, OpenGL doesn’t work with pointers but handles. The glGenTextures creates number of texture handles (in your case 1) and stores them into the array, so use tmp[0] as handle.

Yes. Basically you would work with the same OpenGL context as in JOGL, in the end from both sides you’ll end up calling the same OpenGL functions (though I’m unsure how multiple OpenGL contexts for threads are handled).

I think it might be simple as dynamically loading libGL.so (opengl.dll) and retrieve pointers to functions from there. There might be also some per-platform dependant code. I can’t tell you more since I always used some library that managed it for me and didn’t work with barebone OpenGL/WGL/GLX/AGL.