Bernd Kreimeier writes:
> OpenGL Red Book, p65-78, "Vertex Arrays"
> glColorPointer( GLint size, GLenum type, GLsizei stride,
> const GLvoid* pointer );
> used as
> glColorPointer( 4, GL_UNSIGNED_BYTE, 0, data );
>
> In Java, using byte[4] is simply way too expensive. The
> Color objects store as r,g,b,a separately, and return
> values are packed in 32bit. I use the 32bpp GL_C4UB format,
> which is
> int as byte[4] as {byte R,G,B,A}
I'm with you so far.
> To save JNI overhead, I put together an int[] in Java as a
> packed array of GL_C4UB colors for the above OpenGL function,
> hand it over to native code en block - and have JNI changing
> the endianess on the fly? First a redundant swap by JNI,
> then me swapping it back, and you do have a screwed up
> situation.
I'm not sure why you think there's a redundant swap by JNI. You have
no way of knowing whether there is or not without looking at the
source code of the JVM. In all likelihood, most of the JVM's internal
representations (the ones we can't see because there's no interface to
them) have the endianness of the underlying processor. So, in all
likelihood, JNI is not doing a swap at all.
Remember, the JVM spec says the JVM appears **from the perspective of
the Java byte code** to be big-endian. There are very few Java byte
code operations where endianness matters, so "in all likelihood" (not
having looked at the code) it's more efficient to store values in the
format that the hardware generates them. Consider
int a = b + c;
int e = d * a;
Do you really think an IA-32 JVM stores all those values in a
big-endian representation? Then it would swap b, swap c, add them,
swap the result, store the result in a, swap d, swap a, multiply them,
swap the result, and store the result in e. (!!) I think it's safe
to say it adds b and c, stores the result in a, multiplies d and a,
and stores the result in e.
I'm somewhat at a loss to see what JNI is doing wrong here. If, in
Java, you pass 0x12345678 as an integer argument to a native method,
and in your C-language native method you compare the argument's value
to 0x12345678, C tells you they're equal. To me, that sounds like a
feature. You told it you wanted to pass an integer, and most of the
time when you tell it you're passing an integer you really are.
But more importantly, that feature also results in a more efficient
JVM implementation, because the JVM's values are already represented
in the endianness that JNI wants (i.e. the hardware endianness).
> >From Jack Middleton @ SUN, OpenGL ARB/interleaved array
> > over JNI, stripped for this discussion:
> > intVal = r;
> > intVal = intVal << 8;
> > intVal = intVal | g;
> > intVal = intVal << 8;
> > intVal = intVal | b;
> > intVal = intVal << 8;
> > intVal = intVal | a;
>
> Which breaks for the same reason, incidentally.
The problem here, it seems to me, is that OpenGL is *not* using a
packed integer, it is using an array of four bytes; yet the native
interface is trying to use a packed integer. I see a few options, and
there may be more I haven't seen.
- Pass a byte array and hope you can lock it without copying,
which you won't be able to do if the JVM has stored the byte
array internally as an array of integers, or if the GC
doesn't support locking. This is undoubtedly inefficient
for small array sizes.
- Pass a fixed number of distinct byte arguments and let your
native code arrange them. This is inefficient for large
number of bytes, and it fails with a variable number of
bytes. However, if there are common numbers of bytes it
might make sense to have several overloaded native methods
to handle them. You would use some other approach to handle
the general case, albeit less efficiently.
- Encode the bytes into integers as Sun suggests, but call a
native method isBigEndian() to tell your Java method which
field should be in the Java MSB so that things will come out
right in the native representation. I've elaborated on this
in a private email. In the general case this is probably
the best option.
- Use a different interface to OpenGL, if there is one, that
encodes r, g, b, and a as a real integer with r in the MSB,
g in the next-MSB, b, in the next-LSB, and a in the LSB (or
whatever). That eliminates the endian issue altogether,
because Java automatically ensures the Java MSB is the JNI
MSB, the Java LSB is the JNI LSB, etc. (I.e. That's the
normal behaviour of integers.) If OpenGL has such an
interface, this is the best option, having the same
performance as the previous option but lower code
complexity.
If JNI has a problem here, it's not that it guarantees that its values
are in the endianness appropriate for the hardware, it's that passing
byte arrays is too slow.
> What would be needed instead is a way to get a 32bit array across
> JNI without JNI changing the byte order.
You've got to stop thinking that JNI changes the byte order. Java is
big-endian only when you're dealing with 100% pure Java. When you
write the Java code
int n = (r << 24);
you are telling the JVM to put the LSByte of r into the MSByte of n.
That is very likely exactly what an IA-32 JVM is doing in hardware
when it executes the Java byte codes corresponding to that statement.
Read r (a little-endian value),
Left arithmetic shift by 24 bits,
Write the (little-endian) result into n.
Look ma, no swapping. And r and n are directly passable to JNI
without swapping.
You are asking for a Java language expression that tells the JVM to
put the LSByte of r into the the byte of n that happens to correspond
to pc[0] in the C-language
typedef <a-type-corresponding-to-a-32-bit-integer> int32;
union { int32 n; char pc[4]; }
whatever byte that happens to be on the underlying hardware. That's
the only way to specify the requirement you've asked for, and it would
make the Java language definition (not the JNI definition) dependent
on something that is about as processor-specific as you can get.
That's not worth it, because:
You are asking for something very strange, used only with the native
interface, and even then used only when trying to pass *byte arrays*
as integers. As noted above, MSB/LSB-based packing schemes do not
need the capability you are asking for.
Best,
daniel dulitz
Valley Technologies, Inc. Peak Performance Real-Time DSP
State College, PA
----------------------------------------------------------------------
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]