LWJGL 3 - API Freeze (request for feedback)

Started by spasi, September 29, 2015, 18:50:47

Previous topic - Next topic

spasi

A major difference is that Configuration contains mutable state. The user may set values there and LWJGL reads those values (usually only once at startup). The Sys and LWJGLUtil fields are all immutable (finalized at runtime, on class init).

Kai

Okay, I just had a more closer look at the LWJGLUtil and Sys classes what they actually do.
As I see it, there are the following aspects currently dealt with by those classes:
1. Obtaining the platform that LWJGL is running on (LWJGLUtil)
2. Loading shared libraries (LWJGLUtil)
3. Obtaining the architecture pointer size (Sys)
4. Querying the build version (Sys)
5. Querying the fields of some classes (LWJGLUtil) - it is used in some *_ERROR_TOKENS fields, but I am not sure why and what for

So, if I leave the last point of the above iteration behind, I would do it this way:
Implement the aspects 1., 2. and 3. in a class called "Runtime". This is mainly because in Java the class dealing with shared library loading is also called Runtime and it somewhat suits aspects 1. and 3. as well, I think.
Implement aspect 4. maybe also in "Runtime", or add a small class called "Version" directly under org.lwjgl.

FortressBuilder

The problem with calling it Runtime is that this would clash with java.lang.Runtime. Maybe something like LWJGLRuntime?

abcdef

*side question*

Is there a reason why the LWJGLUtil shared library loader tries to individually extract the right library files from a directory with all the platform jars in? I'd have thought it would be much easier to have sub directories per platform / architecture and to just reference everything in that directory. LWJGL2 had a loader which did this (the directory structure was in a JAR).

spasi

LWJGL 3 originally had a platform/arch directory structure for natives, but was changed to a monolithic directory due to user feedback. The SharedLibraryLoader just mirrors that decision I guess. Note that it was contributed by Mario Zechner, I only cleaned up the code. Also keep in mind that it works with getResourceAsStream, it doesn't know anything about the library JARs. You could have a JAR per platform or a fat JAR with everything in it and it will still work, as long as the classpath is set up correctly.

Does the current implementation cause any issues for you?

spasi

Quote from: Kai on November 05, 2015, 10:38:02
Implement the aspects 1., 2. and 3. in a class called "Runtime". This is mainly because in Java the class dealing with shared library loading is also called Runtime and it somewhat suits aspects 1. and 3. as well, I think.
Implement aspect 4. maybe also in "Runtime", or add a small class called "Version" directly under org.lwjgl.

Quote from: FortressBuilder on November 05, 2015, 17:35:29The problem with calling it Runtime is that this would clash with java.lang.Runtime. Maybe something like LWJGLRuntime?

Runtime sounds good to me. LWJGLRuntime feels verbose ("lwjgl" is already part of the package name). Any other ideas?

Kai

"Environment" comes to my mind when thinking about aspects 1. and 3.
However, I think "Environment" does not fit aspect 2. as good as "Runtime."

EDIT: Or better (I think) would be "Platform."

kappa

adding the LWJGL* prefix to any class makes it feel verbose :)

FortressBuilder does raise a good point about the Runtime being confusing with java.lang.Runtime as that is a core java vm class.

Other names options could include "Library", "Lib", "LibLWJGL", "LibUtil", "Version" (as mentioned above) or "LRuntime".

abcdef

Quote from: spasi on November 06, 2015, 10:54:11
LWJGL 3 originally had a platform/arch directory structure for natives, but was changed to a monolithic directory due to user feedback. The SharedLibraryLoader just mirrors that decision I guess. Note that it was contributed by Mario Zechner, I only cleaned up the code. Also keep in mind that it works with getResourceAsStream, it doesn't know anything about the library JARs. You could have a JAR per platform or a fat JAR with everything in it and it will still work, as long as the classpath is set up correctly.

Does the current implementation cause any issues for you?

none :) I already had some code to do this and I package the natives up with a script. It was more from a curiosity perspective as I personally feels its not very extensible.

spasi

Did a few experiments on this and in the end decided that most of the functionality in Sys and LWJGLUtil is not really interesting to most LWJGL users. For example, loading shared libraries (the LWJGL JNI code + 3rd party libraries) should work transparently most of the time and only advanced users will need to take control of things. This is exactly what the system package is useful for.

So, in order to avoid making an unfortunate decision now that will be very hard to change later, I moved everything except the version stuff in org.lwjgl.system. Sys and LWJGLUtil are gone and the base package has only 3 classes now: BufferUtils, PointerBuffer and the new Version class. The library loading functionality has been moved to org.lwjgl.system.Library, the platform stuff in org.lwjgl.system.Platform and the rest went into APIUtil, Checks and MemoryUtil (depending on where they fit best). The SharedLibraryLoader was also moved in system and the DynamicLinkLibrary interface renamed to SharedLibrary.

The latest nightly build (3.0.0b #57) includes the above changes, as well as some general cleanup in preparation for the beta release. Tomorrow I'll upgrade the LibOVR bindings to 0.8 and if there are no other suggestions/objections in this thread, I'll release the 3.0.0 beta.

kappa

very good changes, really does make the api much nicer and cleaner.

spasi

I'm afraid I had to do another breaking change. I was still not at all satisfied with the struct API, it was too heavy and too ugly. The latest nightly build (3.0.0b #60) includes the following changes:

1) Struct member accessors now match the native member names. The get/set prefixes are gone and there are no lower-to-upper case modifications like before. For example:

GLFWImage img = GLFWImage.malloc();

// before
img.setWidth(128);
int w = img.getWidth();

// after
img.width(128);
int w = img.width();


2) All getter implementations have been changed to prefer returning a view of the underlying struct data, instead of a copy of the struct data. This affects getters that return buffers and nested structs.

3) Direct accessors to members of nested structs have been removed. They were making the parent struct classes very heavy. This change will result in more garbage in cold code, but escape analysis should take care of unnecessary instances in hot methods.

4) The static accessors were simplified considerably, there are fewer overloads now. The static API is not as rich as before, but the StructBuffer classes should cover most use-cases.

5) Javadoc is now generated for all accessors. Also, the native struct definition is generated in the class javadoc, along with documentation per struct member.

As always, any user not satisfied with 2, 3 or 4 may use the unsafe tools in MemoryUtil to implement exactly the functionality they need.

I think I'm done for real this time. Let me know what you think and I'll release 3.0.0b if there are no objections.