Features in LWJGL Next(tm)

Started by elias, December 19, 2003, 21:49:58

Previous topic - Next topic

elias

No, the next version of LWJGL isn't out yet, but hopefully it will be before Longhorn ships. Anyway, here's where the discussion on the reworking of GL extensions and other stuff is taken from private email:

To sum up, Spasi is now working on implementing quite a few interesting GL extensions (think shaders) and is also involved in splitting GL extensions out from GL.java and into per-extension classes. To help things go a little smoother, he even created a tool to auto-create native files from the class and java files. Pretty neat!

Here's the lastest mail:
Quote
Elias wrote:
       "What about the unsigned versions of the calls? Like *ub for
example, that type doesn't map to a similar java type, and therefore you
can't make two "overloaded" functions, one taking C unsigned bytes and one
taking C signed bytes."

That's why I said "where applicable". We can keep the u (and others) "flags"
where needed. Check this out:

public static native void glVertexAttribARB(int index, short x);
public static native void glVertexAttribARB(int index, float x);
public static native void glVertexAttribARB(int index, short x, short y);
public static native void glVertexAttribARB(int index, float x, float y);
public static native void glVertexAttribARB(int index, short x, short y,
short z);
public static native void glVertexAttribARB(int index, float x, float y,
float z);
public static native void glVertexAttribARB(int index, short x, short y,
short z, short w);
public static native void glVertexAttribARB(int index, float x, float y,
float z, float w);
public static native void glVertexAttrib4NuARB(int index, byte x, byte y,
byte z, byte w);

Everything is cool, right? The last one clearly shows that the arguments are
unsigned bytes that will be normalized. Sweet... We should post this
proposal on the forum, to see what other users think. I would prefer to see
the following in my code:

public static native void glVertex(float x, float y);
public static native void glVertex(int x, int y);
public static native void glVertex(float x, float y, float z);
public static native void glVertex(int x, int y, int z);
public static native void glVertex(float x, float y, float z, float w);
public static native void glVertex(int x, int y, int z, int w);

Instead of

public static native void glVertex2f(float x, float y);
public static native void glVertex2i(int x, int y);
public static native void glVertex3f(float x, float y, float z);
public static native void glVertex3i(int x, int y, int z);
public static native void glVertex4f(float x, float y, float z, float w);
public static native void glVertex4i(int x, int y, int z, int w);

The {2,3,4}{i,f} just make them ugly and unreadable.

- elias

elias

Now, my opinion is that if the postfixes can't be removed in all cases (like the signed/unsigned case), they shouldn't be removed in any case (in the principle of least surprise). But what is the opinion of the rest of the crowd? Do we want consistency or simpler names?

- elias

princec

I'd rather not remove the postfixes, as they avoid method overloading, which I hate (it causes unexpected bugs when java automatically casts up primitives). It would also be a big regression f*ck up like the one I'm currently dealing with with Sys.DEBUG :oops: Can we not keep Sys.DEBUG the way it was and add the new functionality in some way coz otherwise I've got to fix a bunch of code ;) And a boolean is much nicer to deal with...

Cas :)

elias

I'm not totally sure what exactly is bothering you - is it the fact that DEBUG is an int (can't be _that_ hard to change) or some other thing?

- elias

cfmdobbie

Quote from: "elias"[...] is it the fact that DEBUG is an int [...]

DEBUG is now an int?!? :shock:  Okay, quick check of CVS: so DEBUG is now an int that can take one of the two values "DEBUG_DISABLED" or "DEBUG_ENABLED"?  I have to admit, that sounds rather like a boolean to me... Ah, no, I see.  You have "disabled", "enabled" and "greater than enabled"... :wink:

Might I suggest ripping the logging level names from Log4j and creating a "proper" debug level system?  Do away with the debug-level-follows-asserts concept and make the library pick up its debug level from a system property (default to NONE).  You'll need to separate the concepts of "debug output" and "data verification", but I think it might be worth it.
ellomynameis Charlie Dobbie.

elias

Yeah well mock me all you want, but that was the general intention - to include more levels of debugging than just on-off and removing the assertion check to enable it. Now I might have given the two first levels stupid names (I did, didn't I? :-), but that easily fixable. All this is, after all, only in CVS.

- elias

princec

Well, this is what I'm getting at really.

If we want more logging, well, why not just the built-in Java logging features?

Otherwise, Sys.DEBUG was a handy way to know if assertions were enabled or disabled, and that's all it ever meant.

Are we still going to remove all those CHECK_ERRORs from the native code and move everything up in to Java-land so we can get rid of lwjgl_d.dll? (which is where I thought this idea was stemming from)

Cas :)

cfmdobbie

Apologies, no mocking intended - that first paragraph is more my confusion than anything else!

I think it would be great to have multiple logging levels, but I just think things might benefit from separating the assertion concept completely out from logging (and you say this is your intention - hurrah!), and you may as well borrow the research that Log4j has already done on the naming of the logging levels.  You can use the same Log4j concept of isDebugEnabled() etc, which will allow Cas to still deal with a boolean.  The regression issues would then collapse to a project-wide search-and-replace, wouldn't they?

But to get back on topic...  Postfixes don't really interest me.  One point I'd make is that one good reason for keeping the postfixes is to maintain compatibility with the C binding naming conventions.  However, as many other postfixes have been removed, it would make sense to remove them all.

Cas' point about overloading with widening conversions is valid however.  I've not had a problem with that myself - has it popped up frequently for you?

The unsigned problem is annoying, but I guess I can live with it.  There's no way unsigned can be removed entirely - it's vital when dealing with pixel data. :?
ellomynameis Charlie Dobbie.

elias

There you go, you can now set the system property lwjgl.debuglevel to one of DEBUG, INFO, WARN, ERROR, FATAL, NONE. I haven't separated the data verification checks though. They might even be enabled at all times in the next version.

- elias

elias

The unsigned problem is worse than widening problems, because it makes it impossible to remove all postfixes without also removing some calls. Consider a function that takes unsigned and signed data in java:

glDoStuff4b(byte b1, byte b2, byte b3, byte b4);
glDoStuff4ub(byte b1, byte b2, byte b3, byte b4);

There's no way you can remove the postfixes without removing one of the calls and thereby remove functionality. That's the primary reason I want to keep the postfixes for primitive type calls as it is now.

- elias

elias

Cas: We should definitely move the gl checks to java side. Actually they will be replaced bya boolean check in each extension class, like this:

public class ARB... {
	private static boolean is_supported;

	static setSupported(boolean supported) {
		is_supported = supported;
	}

	public static boolean isSupported() {
		return is_supported;
	}

	public void glDoStuff() {
		if (!isSupported())
			throw new OpenGLException("Unsupported extension ARB_...");
	}
...
}


The setSupported will be called whenever the Window is initialized. That way, we'll keep per function availability check without asking native code. The glError() check is more difficult as it can be potentially more expensive and we might not have it called for every function called (at least I don't). A solution would be to always call the function at some regular interval (Window.paint()?) and let Sys.DEBUG be the level to check them at each function. The user is free to do his own checking if he want to.

- elias

princec

Well, ok, how's about this:

We should be able to selectively enable or disable chunks of debugging functionality. We must not allow any feature that could compromise the VM to be disabled; so it's perfectly reasonable to not call glGetError() at all but it we should not turn off our other forthcoming security checks for buffer bounds and such.

Let's have separate flags for:

Sys.DEBUG
This can be a simple way to specify that we're running in debug mode for general application use, and should have no other semantic meaning.

Sys.ASSERTS
This is automatically set to true on classload if asserts are enabled, and is merely a handy way to know if assertions are enabled in the LWJGL packages.

And in CoreGL and CoreAL respectively, we will have separate flags controlling their behaviour:

CoreGL.CHECKGLERRORS
This must be explicitly set and will cause glGetError() to be called after all GL functions.

CoreAL.CHECKALERRORS
This must be explicitly set and will cause alGetError() to be called after all AL functions.

All of these flags should be settable from System properties eg. -Dorg.lwjgl.Sys.CHECKGLERRORS=true on the commandline.

We should then use the official Java Logging APIs (rather than Log4j, even though log4j is supposed to be a better API) because it's built in to Java, for any logging we want doing.

We can now get rid of the CHECK_GL_ERROR macro or whatever it was called from the native code. We will have to prefix each C function with 'n' and provide a similar naming scheme in the Java code that we have already done, eg.

public static void glNormal3f(float x, float y, float z) {
nglNormal3f(x, y, z);
checkGLError();
}
private static native void nglNormal3f(float x, float y, float z);

where checkGLError() is defined in CoreGL as
public static void checkGLError() {
if (BaseGL.CHECKGLERRORS) {
int errorCode = glGetError();
if (errorCode != 0) {
throw new OpenGLException(GLU.gluGetErrorString(errorCode));
}
}
}

which will be totally optimized away by the server VM and otherwise just a simple boolean check in the client VM. Interestingly I've barely noticed any slowdown at all when we check glGetError after every call - mainly because when you're doing GL right, you hardly call any GL methods per frame anyway, just a few state changes and big geometry dumps - it gets lost in the noise.

Someone once asked us why OpenGLException wasn't a checked exception; and the reason is, because they can be turned off voluntarily.

How's all this sounding?

Also I think we should get 1.5 fully supported in the next release.

Cas :)

elias

I'm not sure what we need the assertion status for? All asserts will be removed from LWJGL anyway, replaced by RuntimeExceptions.

- elias

princec

Just nice to know is all :D Can we keep it for nostalgia's sake?

Cas :)

spasi

Quote from: "princec"Also I think we should get 1.5 fully supported in the next release.

It'll be fully supported before February. Just some native code work to be done ;-)

About the postfixes, if we'are going to keep them in some methods, we should keep them in all of them. I mean in methods that take Buffers as parameters as well. Just to make things consistent and predictable.

About the debug stuff, I like Cas' proposal the most. It'll be best if we could avoid the check in Client VM as well. He's right that it won't make any real difference in performance, but I don't think developers will like it.