GetFloatArrayElements Vs Float Direct Buffer

1,666 views
Skip to first unread message

George

unread,
Nov 19, 2009, 1:39:53 PM11/19/09
to android-ndk
When I am passing an array of floats from Java to C, I have two
options:

One is to create a direct float buffer, like so
(1)
ByteBuffer b= ByteBuffer.allocateDirect(3* 4);
FloatBuffer floatBuffer =b.asFloatBuffer();
float[] values={1.0f,2.0f,3.0f};
floatBuffer.put(values);

nativeSendFloatArrayAsDirectBuffer(floatBuffer)

and use float* nativebuffer = (float*) env->GetDirectBufferAddress
(buffer); in C

OR
(2)
float[] values={1.0f,2.0f,3.0f};
f.put(values);

nativeSendFloatArray(values);

and use

float* nativeValues = (float *)env->GetFloatArrayElements(values, 0);
//use nativeValues
env->ReleaseFloatArrayElements(values, nativeValues, 0);

I know that in option (1) no extra copies are made while reading/
writing to the direct buffer in native. But, I am not sure in option
(2) - is a copy made only on write or even on a read? Any other
disadvantages of using (2) over (1)?

fadden

unread,
Nov 19, 2009, 5:18:58 PM11/19/09
to android-ndk
On Nov 19, 10:39 am, George <bipi...@gmail.com> wrote:
> float* nativeValues = (float *)env->GetFloatArrayElements(values, 0);
> //use nativeValues
> env->ReleaseFloatArrayElements(values, nativeValues, 0);
>
> I know that in option (1) no extra copies are made while reading/
> writing to the direct buffer in native. But, I am not sure in option
> (2) - is a copy made only on write or even on a read? Any other
> disadvantages of using (2) over (1)?

A copy *might* be made in #2. It's up to the VM to decide if it wants
to give you a pointer to the original values or allocate a new buffer
for them.

Alex

unread,
Nov 23, 2009, 2:10:23 PM11/23/09
to android-ndk
get*ArrayElements will do a copy; I suspect that this is done to
preserve memory ownership and would be unlikely to change. Looking at
the source for Donut it would appear that the copy is a relatively
lightweight memcpy when native types are used.

Alex

fadden

unread,
Nov 23, 2009, 7:48:20 PM11/23/09
to android-ndk
On Nov 23, 11:10 am, Alex <goo...@glastonbridge.co.uk> wrote:
> get*ArrayElements will do a copy; I suspect that this is done to
> preserve memory ownership and would be unlikely to change.  Looking at
> the source for Donut it would appear that the copy is a relatively
> lightweight memcpy when native types are used.

Actually, Get<Primitive>ArrayElements uses the
GET_PRIMITIVE_ARRAY_ELEMENTS macro in Jni.c which currently just pins
the memory. In the future this might do a copy, since pinning makes
heap compaction less effective. (You can test if you're making
unwarranted assumptions about copy vs. no-copy by enabling CheckJNI's
"forcecopy" mode; see dalvik/docs/jni-tips.html for details.)

Get<Primitive>ArrayRegion uses GET_PRIMITIVE_ARRAY_REGION, and uses
memcpy() to copy data into a user-supplied buffer.

Bipin George Mathew

unread,
Nov 23, 2009, 8:46:45 PM11/23/09
to andro...@googlegroups.com, android-ndk
Thanks fadden.

While using a direct FloatBuffer, we copy float values into the buffer
in Java and then access the pointer address in C. We still do one copy
at the Java level.

In the case of using getFloatArrayElements, there is only a possibilty
of a copy at the native level.

Given this, why do APIs (like the opengl wrappers) that need to pass
float arrays prefer method 1 (direct float buffer) over method 2?
> --
>
> You received this message because you are subscribed to the Google
> Groups "android-ndk" group.
> To post to this group, send email to andro...@googlegroups.com.
> To unsubscribe from this group, send email to android-ndk...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en
> .
>
>

fadden

unread,
Nov 24, 2009, 1:43:25 AM11/24/09
to android-ndk
On Nov 23, 5:46 pm, Bipin George Mathew <bipi...@gmail.com> wrote:
> Given this, why do APIs (like the opengl wrappers) that need to pass  
> float arrays prefer method 1 (direct float buffer) over method 2?

I don't know much about OpenGL, so I can't give you a definite
answer. I can speculate a little, and hopefully someone will correct
me if I'm off track.

Generally speaking, direct byte buffers are cheaper to access from
native code. If we assume that the underlying OpenGL implementation
is written in C/C++, and uses JNI like everybody else, then using a
direct byte buffer allows OpenGL to access the data you provide
without involving the VM. If you used a float[] on the virtual heap,
it would have to use one of the primitive array calls to access the
data, guaranteeing that on certain VMs the data will be copied. Not
something you want to bake into the API itself.

If the geometry in the buffers can be re-used, you only need to copy
it once, and OpenGL can read it multiple times. (Again, possible
display of ignorance here.)

(It's also worth noting that direct buffers allow you to use data from
"native" sources. For example, you can use the JNI
NewDirectByteBuffer call to allocate a "direct" ByteBuffer that points
to memory mapped directly from a file. This can be very convenient in
some situations. Probably not important for geometry.)

The trade-off is that it's awkward and more expensive to manipulate
data in Java. Without a notion like "unsafe" arrays, I don't think
it's possible to have something that works efficiently on both sides
and never has to copy data.

Bipin George Mathew

unread,
Nov 24, 2009, 1:51:10 AM11/24/09
to andro...@googlegroups.com
This is very detailed and gives me enough food for thought. Yep,
'unsafe' arrays would have been the ideal way out.

Thanks fadden!

David Karla

unread,
Oct 3, 2013, 4:37:46 AM10/3/13
to andro...@googlegroups.com, bip...@gmail.com
I stumbled on this conversation searching for answers to the same question myself ... though it's a few years old, someone else might also so stumble: the clearest answer is the code, and as of 2013, the arrays are still pinned ... https://android.googlesource.com/platform/dalvik.git/+/android-4.2.2_r1/vm/Jni.cpp .. so fretting about get directbufferaddress etc is not yet anything to panic about Get<T>ArrayElements is still as good a way as any to do this ... I hope!
Reply all
Reply to author
Forward
0 new messages