Processing Direct Int Buffers

171 views
Skip to first unread message

Robert Green

unread,
Nov 8, 2009, 3:44:47 AM11/8/09
to android-ndk
Hey guys,

I have found a spot where I can realize some incredible performance
gains if I can just pass two IntBuffers into a native method and have
the results written into a third IntBuffer.

Here's my c:

void Java_com_myproject_MyClass_interpolate( JNIEnv* env,
jobject thiz, jobject verts1, jobject verts2,
jobject outBuf, jint mix, jint count) {
int i;
jint* vArray1 = (jint *)(*env)->GetDirectBufferAddress(env,
verts1);
jint* vArray2 = (jint *)(*env)->GetDirectBufferAddress(env,
verts2);
jint* out = (jint *)(*env)->GetDirectBufferAddress(env, outBuf);
for (i = 0; i < count; i++) {
out[i] = vArray1[i] + ((jint) (((jlong) (vArray2[i] - vArray1[i])
* (jlong) mix) >> 16));
}
}

I know the algorithm there works, I've tested that separately through
JNI. The problem seems to be that I just get garbage results written
to "out". I'm not sure if I'm getting the correct values in vArray1
or vArray2.

All of the IntBuffers passed in are created via
ByteBuffer.allocateDirect().asIntBuffer() and I'm attempting to
manipulate the backing int arrays directly.

I admit that I'm terrible with c. Any ideas here?

Thanks!

Robert Green

unread,
Nov 8, 2009, 4:38:26 AM11/8/09
to android-ndk
Just FYI, I got the same code to work using arrays, which is
surprisingly fast still but inconsistent. I'm seeing about a 3ms
processing time using arrays but every 10 or so times it jumps to
10-15ms. Not sure what's causing that.

Here's my working arrays version:

void Java_com_myproject_MyClass_interpolate2( JNIEnv* env,
jobject thiz, jintArray verts1, jintArray verts2,
jintArray out, jint mix, jint count) {
int i;
jint vArray1[count];
jint vArray2[count];
jint outBuf[count];
(*env)->GetIntArrayRegion(env, verts1, 0, count, vArray1);
(*env)->GetIntArrayRegion(env, verts2, 0, count, vArray2);
(*env)->GetIntArrayRegion(env, out, 0, count, outBuf);
for (i = 0; i < count; i++) {
outBuf[i] = vArray1[i] + ((jint) (((jlong) (vArray2[i] - vArray1
[i]) * (jlong) mix) >> 16));
}
(*env)->SetIntArrayRegion(env, out, 0, count, outBuf);
}

So now I'm feeling confident that if I can get the direct int buffers
to work, I'll be golden on this and have it running at 3ms or less
consistently for my largest data set. This makes me love that we have
the NDK right now.

Can anyone take a stab at what I'm doing wrong with the IntBuffer
method?

Thanks!

fadden

unread,
Nov 8, 2009, 4:03:08 PM11/8/09
to android-ndk
On Nov 8, 1:38 am, Robert Green <rbgrn....@gmail.com> wrote:
>           (*env)->GetIntArrayRegion(env, verts1, 0, count, vArray1);
>           (*env)->GetIntArrayRegion(env, verts2, 0, count, vArray2);
>           (*env)->GetIntArrayRegion(env, out, 0, count, outBuf);

If "out" is strictly an output buffer, you don't need to copy it in
first.

fadden

unread,
Nov 8, 2009, 4:13:11 PM11/8/09
to android-ndk
On Nov 8, 12:44 am, Robert Green <rbgrn....@gmail.com> wrote:
> I know the algorithm there works, I've tested that separately through
> JNI.  The problem seems to be that I just get garbage results written
> to "out".  I'm not sure if I'm getting the correct values in vArray1
> or vArray2.

What version of the software are you running? The JNI direct buffer
stuff changed significantly in 1.6. (Should work in all releases, but
it's faster and doesn't cause allocations in 1.6. And there was some
funny business with split() that didn't work right before.)

> All of the IntBuffers passed in are created via
> ByteBuffer.allocateDirect().asIntBuffer() and I'm attempting to
> manipulate the backing int arrays directly.

It's all just bytes on the native heap underneath. The asIntBuffer()
call wraps the DirectByteBuffer in an IntToByteBufferAdapter, which
provides the int-oriented get/put calls. The underlying storage
doesn't change.

Can you characterize the garbage? Maybe print values for in1/in2/out
when "count < 4" and see if they match up with expectations?

Do you need to configure the byte ordering? The default order is
always big-endian, which is probably not what you want.

Robert Green

unread,
Nov 8, 2009, 5:36:53 PM11/8/09
to android-ndk
You know, I was wondering if it was an endianness problem last night
when I went to bed. That's the problem with 4am coding is that you
stop thinking clearly about the environment. Sure enough, the two
input IntBuffers didn't specify order. Once I changed them to native
order, everything worked correctly.

This is producing results for me that are a bit faster than the array
version. It's also easier in my code because I can hand the resulting
data directly to OpenGL instead of copying it back into a buffer,
which is another small performance boost.

Thank you very much for your help!!
Reply all
Reply to author
Forward
0 new messages