glGenTextures : detecting the GL context

Howdy-

I’m rendering to several GLJPanels with some texture mapping. I’m trying to determine when I need to allocate a new texture id. I’d ideally like to have code that I can call at any time from display() saying “use texture foo”, without having to do any external initialization, or tracking whether I’ve initialized the texture in that context previously. E.g., just call:

TextureManager.bind(“RedBrick”, gl)

and it will register the new texture (via glGenTextures) as needed, or reuse a previously allocated texture id if it has one. To do this, I was maintaining a map from gl instances to texture ids for each texture. If the map had no entry for a gl, I called glGenTextures and added a new entry to the map.

This mostly works. But the gl object changes for a GLJPanel as the viewport is increased in size, causing my code to think it needs to reallocate the texture. But it appears that the new GL context has a shared context with the original context (in which I already allocated the texture.) So the result is that I’ve allocated the same texture twice (and gotten two different ids), presumably wasting memory somewhere.

How can I reliably determine which rendering context I’m in, so that I can correctly allocate new texture ids only when its necessary?

Or, is the usual OpenGL-ism to create all the viewports with shared contexts, in which case I only need to track whether or not I’ve registered the texture at least once? (I’m new to OpenGL coding.)

And as a random aside, do I need to be concerned about the memory footprint of the textures I allocate and bind, separately from the size of the textures actually used during rendering? Does the GL driver do the right magic to swap textures in/out of video RAM automatically?

Thanks!

The fact that the GL object changes for the GLJPanel, and that the textures are shared between them, is a detail of its implementation. The underlying pbuffer for the GLJPanel may be destroyed and recreated during resize operations; the fact that the textures and display lists persist is a bug in the GLJPanel, because the GLEventListener.init() method may be called during these resize operations. I was somewhat reluctant to fix this bug due to concerns about stability but just implemented it and it is fairly simple. The fix will be in the next release.

Therefore, in the next release the GLJPanel will behave exactly as advertised, in that during GLEventListener.init() calls you may need to reinitialize your textures and display lists.

If you’re rendering to multiple GLJPanels and want the texture objects to be shared among them, simply pass one of them into GLDrawableFactory.createGLJPanel() as the shareWith parameter. This should make management of your texture objects easier because you can generate the texture object in any of the panels’ GLEventListeners and use it in any other one. If you see any problems with this approach (like textures not being shared properly among GLJPanels) please post or file a bug. I can see that if all of the GLJPanels are removed from the user interface and then reinserted, for example, that the texture objects will all be gone.

I’m confused. Can init() be called more than once on other (non-jogl) platforms? If so, does it indicate that all of your textures and display lists are gone?

It seems to me that the right behavior is to “inherit” textures and display lists between the backing pbuffers and ensure that init() is called exactly once per GLDrawable. I imagine, but don’t actually know, that this would best mimic the behavior of OpenGL on other non-jogl platforms.

Is it common practice to initialize all of your textures in init(), as you suggest? Or is it better to do so lazily? If your texture footprint is very large, it might not fit in memory (system or video). In this case, you need to allocate and deallocate them on demand from display().

To do this efficiently, you need to determine whether you’ve already allocated the texture in a given context. So again, the question comes up of how to reliably determine the GL context. A GL object should have some property that is 1:1 with GL contexts. (Does the GLDrawable have this property?)

JOGL is different from other OpenGL bindings because it needs to integrate cleanly into an existing high-level GUI framework, namely Swing and the AWT. The notion of the GLEventListener originated with the now-defunct Magician binding, but it closely parallels the callback model in GLUT and some other libraries.

There is more state in the OpenGL context than just textures and display lists. I think it would be too complicated to try to either specify that textures and display lists are preserved while the component has been removed from the hierarchy, or try to preserve the complete OpenGL state between context destruction and re-creation.

I would recommend initializing your textures lazily. Share textures and display lists among all of your GLJPanels and you’re guaranteed that you don’t have to create the same texture object for more than one GLJPanel. The GLDrawable is intended to be the 1:1 mapping you can use to index into a HashMap or similar structure, though in your case if you share textures with all of your OpenGL widgets you really only need one global data structure to indicate whether a given texture has been loaded.