I do wonder that you might be overcomplicating JOGL in an attempt to please everybody and ending pleasing nobody How many systems out there are your bog standard 1-or-2 CPU, single consumer class 3D card on an AGP bus, single monitor system versus oddball workstations with multiple graphics cards? I'd say the ratio was something like 99.9999% and to make the entire API cater for the 0.00001% of uses at the expense of a ton of complexity is a bit baffling. After all most of the rest of the Java APIs are a big concession to lowest common denominators, or hacked together slightly inefficiently

Having multiple OpenGL context support is an absolute requirement for JSR-231. This effectively implies that the OpenGL function calls must be contained in an object and not be static, so that there can be a per-context function pointer table; otherwise you have to do a lookup in thread-local storage per call. That's one of the few major API design decisions forced by multiple context support. JOGL's current use of high-level callbacks was done principally for better multithreading safety in most people's programs when dealing with the AWT. The JSR will still have the high-level callback mechanism, but will also expose the GLContext and makeCurrent/free to the programmer, which can result in simpler code in some situations.

Incidentally, the other requirement of AWT interoperability introduces much more complexity in the implementation than multiple context support. Many OpenGL drivers, especially older ones, aren't multithread-safe and require some sort of workaround or another to work correctly in an MT environment. The issue of having the window torn out from under you by the AWT while you're doing OpenGL rendering on another thread is another tricky one. I'm don't think JOGL handles this 100% correctly yet, and it may become more difficult given the APIs the JSR exposes.

Frequently an extension will accept not only the tokens it defines, but also many other GL_ constants from either the core or another extension, as a parameter to a certain function. How do you organize the extension classes in this case?

The "contract" is simple; Any constant/function that appears in the New Tokens/New Procedures and Functions of a given extension, will be present in the corresponding LWJGL class. For extensions that use constants (or even functions) of other extensions, a user is responsible for reading the extension spec and knowing which other extensions are involved (and use them accordingly).

Quote

As one example, I see you've cleverly made e.g. ARBVertexBufferObject and ARBPixelBufferObject extend ARBBufferObject; do you have other examples of this?

Yes, this is (almost) an exception to the above rule, to avoid code duplication and it's more natural too. Other examples:

Is all of the LWJGL OpenGL interface code handwritten, or do you have any tools that help automate the process?

Java-side, yes it is. For C code, we once had a nice tool that auto-generated the functions (signature only, with parameter names, plus some special support for Buffer parameters). After several revisions and changes to how the extensions are initialised, it is so straightforward now that we just do it by hand.

Having multiple OpenGL context support is an absolute requirement for JSR-231. This effectively implies that the OpenGL function calls must be contained in an object and not be static, so that there can be a per-context function pointer table; otherwise you have to do a lookup in thread-local storage per call. That's one of the few major API design decisions forced by multiple context support.

I'm curious as to why you went the instanced GL objects route instead of the static route with a thread local function pointer table. With static GL methods, you can't ever call the wrong gl function by accidentially caching an GL instance, and you avoid having to pass it around altogether. And you keep the multithreaded properties of the instance objects of course.

I did a quick and dirty test of thread local storage on my linux 1.4.2 JVM, and initial measurements shows that ThreadLocal.get() is quite fast; in fact, it is much faster than a single env->GetDirectBufferAddress() (and probably even more faster than the array pinning equivalent). Using the server vm makes the overhead even smaller.

I'm curious as to why you went the instanced GL objects route instead of the static route with a thread local function pointer table.

There were a few reasons. First, we wanted to support the composable pipeline paradigm introduced by the Magician Java/OpenGL binding. This can be done with static functions, but you end up implementing the GL object wrapping behind the scenes anyway. Second, because of the per-context nature of the function pointer table, we felt it was better to make it explicit to the programmer that they are dealing with a specific drawable's GL interface.

We can still implement checking of the validity of the GL instances, especially with some of the bookkeeping that now goes on behind the scenes in JOGL. We just have to make sure the GL's context is current on the thread before dispatching to the function; this could be done in the DebugGL pipeline.

I'm pretty much agnostic on the whole LWJGL vs. JOGL issue - the rendering layer in my apps is a thin layer (only 2 small classes) under the scene graph where all the heavy lifting is done. I can have multiple independent renderers and so far have JOGL and 'null' renderers. It'd be easy for me to add support for LWJGL as another renderer if it met all my needs.

When I looked at LWJGL, there were a number of goals/stated targets of the project that just don't coincide with my goals and requirements - note that this is not a criticism of LWJGL - it's designed with tight focus with a specific problem domain in mind, and I think it's a great API for that domain.

The drop-dead issues for me so far with LWJGL are the lack of AWT/Swing integration (I need a subclass of java.awt.Component); I need to be able to render into multiple windows at the same time; I need a version of glBufferDataARB that takes a float[]; and I want to be able to render even when there isn't hardware acceleration. (I also seriously dislike the static method style of LWJGL, but that's purely an emotional response :-) )

I think (hope!) that JOGL is aiming for a wider audience than LWJGL - i.e. that of supporting OpenGL programming in a wider sense and not with such a tight focus on full-screen games.

Note that I'm not trying to suggest that LWJGL be changed to meet my needs - I think that the focus it has is entirely laudable - but that does leave JOGL as my hope for getting these wider needs addressed.

Rob: thanks for your detailed post. I agree that in many cases an array offset should be able to be supplied. I am sure this is going to come up in the JSR 231/239 expert groups, and I'll point the EG to this thread so they can see the ongoing discussion.

Thanks for that - you could no doubt tell that the post was deliberately written for a wider audience than just yourself.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org