Native buffer blitting

997 views
Skip to first unread message

Mfabbri77

unread,
May 20, 2010, 5:48:23 AM5/20/10
to android-ndk

I'm in the need to draw/blit/display a native ARGB buffer (allocated/
malloced by my native library) at the Java application side.
Please take into account that the buffer content is changed
dynamically at runtime, using drawing functions of my native library.
I'm searching the most efficient method to realize such blit
operation.

One method could be to use a Bitmap:

- during View constructor I can create a 32bit bitmap: Bitmap mBitmap
= Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- during View constructor I can create a direct buffer, that will
contain the copy of my native buffer: IntBuffer mDirectBuf =
IntBuffer.allocate(width * height);
- at runtime I call my native drawing function
- when I need to display my native buffer I call a method of my native
library that copies its internal native buffer into the passed Java
direct buffer (previously created):

JNIEXPORT void JNICALL
Java_javax_microedition_AmanithVGJNI_vgGetSurfacePixelsAM(JNIEnv
*jenv, jobject obj, jintArray mDirectBuf) {

int width = vgGetSurfaceWidthAM();
int height = vgGetSurfaceHeightAM();
// get access to the internal malloced 32 ARGB buffer
unsigned int *pixels = vgGetSurfacePixelsAM();

(*jenv)->SetIntArrayRegion(jenv, mDirectBuf, 0, width * height,
(const jint *)pixels);
}

then from Java side I copy the content of the updated direct buffer
into the Bitmap, using the copyPixelsFromBuffer method:
mBitmap.copyPixelsFromBuffer(mDirectBuf).
Finally I display the Bitmap on the screen using canvas.drawBitmap()
method.

It seems to me that there are too many buffer copies. I'm wondering if
it's available a better solution, for example:

- during View constructor I can create a 32bit bitmap: Bitmap mBitmap
= Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- using native code to create a direct buffer linked with the native
(i.e. malloced) buffer:

JNIEXPORT jobject JNICALL
Java_javax_microedition_AmanithVGJNI_vgCreateDirectBufferAM(JNIEnv
*jenv, jobject obj) {

int width = vgGetSurfaceWidthAM();
int height = vgGetSurfaceHeightAM();
// get access to the internal malloced 32 ARGB buffer
unsigned int *pixels = vgGetSurfacePixelsAM();

return (*jenv)->NewDirectByteBuffer(jenv, pixels, width * height *
sizeof(unsigned int));
}

- during View constructor I can create the direct buffer, that will
contain the direct link to my native buffer: IntBuffer mDirectBuf =
AmanithVGJNI_vgCreateDirectBufferAM();
- at runtime I call my native drawing function
- when I need to display my native buffer now I copy the content of
the direct buffer into the Bitmap, using the copyPixelsFromBuffer
method: mBitmap.copyPixelsFromBuffer(mDirectBuf).
Finally I display the Bitmap on the screen using canvas.drawBitmap()
method.

This method avoids the use of redundand buffer/copies, but it has the
problem that JavaVM will try to deallocate the direct buffer created
with native vgCreateDirectBufferAM method; unfortunately the native
buffer MUST be deallocated from the native library, and I don't want
Java put his hands on it. Is there a solution?

Any better idea to share with me ?

Many thanks in advance!

--
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.

C.J. Adams-Collier

unread,
May 20, 2010, 8:03:47 AM5/20/10
to andro...@googlegroups.com
Hey there,

I asked a question similar to this a while ago. I wrote a little about
it in a blog post.

http://wp.colliertech.org/cj/?p=442

Cheers,

C.J.

signature.asc

Hans-Werner Hilse

unread,
May 20, 2010, 9:37:41 AM5/20/10
to andro...@googlegroups.com
Hi,

On 05/20/2010 11:48 AM, Mfabbri77 wrote:
> One method could be to use a Bitmap:
>
I think you - like me at first - just overlooked Canvas'
drawBitmap(int[] colors, ...) method which can directly "paint" an int[].

You can also use JNI methods to keep the GC away from the buffers you're
still using in native code.

You can always use direct-allocated (byte-)buffers which will provide
you with a continuous region of memory (and use its method for
presenting it as an int[] to drawBitmap()). You can directly access such
buffers via JNI.

But OTOH, directly allocated memory is a bit slower than an int[] array.
In practice, Dalvik will try to allocate continuous memory for a
fixed-size int[], so using array functions on this is sufficiently fast.
In fact, using a native-code-only allocated memory buffer and doing a
copy into an int[] array in native code (by JNI means) has been the
fastest approach for me.

Then just use drawBitmap(int[],...) for blitting.

I cannot say much about using GL textures from native code for blitting
your buffer, but this seems to be another possibility.

-hwh

Mfabbri77

unread,
May 21, 2010, 6:50:38 AM5/21/10
to android-ndk


On May 20, 3:37 pm, Hans-Werner Hilse <hwhi...@googlemail.com> wrote:
> Hi,
>
> On 05/20/2010 11:48 AM, Mfabbri77 wrote:> One method could be to use a Bitmap:
>
> I think you - like me at first - just overlooked Canvas'
> drawBitmap(int[] colors, ...) method which can directly "paint" an int[].
>
> You can also use JNI methods to keep the GC away from the buffers you're
> still using in native code.
>
> You can always use direct-allocated (byte-)buffers which will provide
> you with a continuous region of memory (and use its method for
> presenting it as an int[] to drawBitmap()). You can directly access such
> buffers via JNI.
>
> But OTOH, directly allocated memory is a bit slower than an int[] array.
> In practice, Dalvik will try to allocate continuous memory for a
> fixed-size int[], so using array functions on this is sufficiently fast.
> In fact, using a native-code-only allocated memory buffer and doing a
> copy into an int[] array in native code (by JNI means) has been the
> fastest approach for me.
>
> Then just use drawBitmap(int[],...) for blitting.
>
> I cannot say much about using GL textures from native code for blitting
> your buffer, but this seems to be another possibility.
>
>

Many thanks, I will try all options you suggested me!
Yes you're right, unfortunately I missed the drawBitmap(int []
colors, ...) method when reading the docs ;)

Cheers!

David Turner

unread,
May 21, 2010, 3:15:40 PM5/21/10
to andro...@googlegroups.com
You might be interested by the new <android/bitmap.h> API that is exposed in NDK r4 for Android 2.2. and above.
Note that the Bitmap must be allocated from Java, but this gives you access to the pixel buffer with lock/unlock semantics.

Mfabbri77

unread,
May 22, 2010, 5:02:42 AM5/22/10
to android-ndk

Thanks for the information David, I will look into it asap; in the
meanwhile I'm working on standard Android 1.6+ support (so using
standard array/buffer mechanism).
Do you know if the Canvas method drawBitmap(int[] colors, int offset,
int stride, int x, int y, int width, int height, boolean hasAlpha,
Paint paint) supports hw acceleration (e.g. mdp for Qualcomm MSM7k
chips) under some conditions (e.g. hasAlpha = false, paint = null)
Any tips on this?

Thanks!
> > android-ndk...@googlegroups.com<android-ndk%2Bunsu...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/android-ndk?hl=en.
>
> --
> 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 athttp://groups.google.com/group/android-ndk?hl=en.

Mfabbri77

unread,
May 22, 2010, 5:04:34 AM5/22/10
to android-ndk

Could you point me to such JNI methods?

>
> You can also use JNI methods to keep the GC away from the buffers you're
> still using in native code.
>

Angus Lees

unread,
May 23, 2010, 4:07:11 AM5/23/10
to andro...@googlegroups.com
drawBitmap(int[] colors) copies from the int[] array into a newly
created SkBitmap - and then a copy from the SkBitmap to whatever the
Canvas's target is. Not great for a full-screen blit :(

 - Gus

Mfabbri77

unread,
May 23, 2010, 1:04:30 PM5/23/10
to android-ndk

Hi Angus,

On May 23, 10:07 am, Angus Lees <al...@google.com> wrote:
> drawBitmap(int[] colors) copies from the int[] array into a newly
> created SkBitmap - and then a copy from the SkBitmap to whatever the
> Canvas's target is.  Not great for a full-screen blit :(

Any better way/tips to do fullscreen blitting? I'm looking for the
best way to do so (i.e. the way that minimizes redundant memory copies
and that can take advantage of hw acceleration like mdp on MSM7k
chips).

Angus Lees

unread,
May 23, 2010, 6:30:51 PM5/23/10
to andro...@googlegroups.com

No, as far as I can work out, all the public APIs involves intermediate copies.
GLES texture uploads are excellent if you don't need to read the pixels back - and want to draw more often than update.  If you can somehow ignore all the older devices out there, the new 2.2 jnigraphics stuff is better than what was there before (but still involves another copy before making it to the screen). The pre 2.2 Canvas options involve multiple copies and various limitations on subimage updates.
You can break the rules and get access to the raw Surface pixels but the constant churn in this internal API makes it *very* hard to do that across multiple platforms (believe me I've tried).

Unfortunately you have to choose your least worst option :(

- Gus

On 24 May 2010 03:04, "Mfabbri77" <fabbri....@gmail.com> wrote:


Hi Angus,


On May 23, 10:07 am, Angus Lees <al...@google.com> wrote:

> drawBitmap(int[] colors) copies from th...

Any better way/tips to do fullscreen blitting? I'm looking for the
best way to do so (i.e. the way that minimizes redundant memory copies
and that can take advantage of hw acceleration like mdp on MSM7k
chips).

--

You received this message because you are subscribed to the Google Groups "android-ndk" group.

To po...

Hans-Werner Hilse

unread,
May 26, 2010, 5:54:07 AM5/26/10
to andro...@googlegroups.com
Hi,

sorry, I missed your post first since I was busy with family matters
over the weekend.

Basically it's not disabling the GC but rather it's proper "registering"
your objects so that your JNI code holds references to the objects you
don't want the GC to clean up.

Persistence across JNI calls can be archieved by using Global
References. You can use the JNI method "NewGlobalReference" for that.
See the JNI specs for more details. I still try to fully grasp what
"weak References" are for, though. But that's just a side note, you'll
want (non-weak) Global References.

HTH,
-hwh

Zoran Angelov

unread,
May 26, 2010, 7:17:37 AM5/26/10
to andro...@googlegroups.com
I think that weak references are just object observers, no reference counting, so object can be garbage collected while still having weak reference to it.


 

guich

unread,
May 26, 2010, 3:50:38 PM5/26/10
to android-ndk
Hi fabbri,

I posted a code some months ago that shows how to update the screen,
because i do that in my app too.
Search for guihazan and you'll find it.

There's a sample in the new ndk, bitmap-plasma.

Does someone know if the ndkr4 will work with Android 1.6?

regards

guich

Angus Lees

unread,
May 26, 2010, 5:46:40 PM5/26/10
to andro...@googlegroups.com
On Thu, May 27, 2010 at 05:50, guich <guih...@gmail.com> wrote:
> Does someone know if the ndkr4 will work with Android 1.6?
>

Most of the NDK will work with 1.6 just fine. The <android/bitmap.h>
code that bitmap-plasma uses requires 2.2, however.

- Gus

Android dev

unread,
May 26, 2010, 4:33:38 PM5/26/10
to android-ndk
Please guich, do you have the link to the post? Because I searched for
guihazan and I couldn't find it...
Also, about the "new stable API for accessing the pixel buffers of
Bitmap objects from native code" from ndkr4 (used in the bitmap-plasma
sample) : does anybody have already tested it to see if it is really
the fastest way to update the screen from a native code?
Reply all
Reply to author
Forward
0 new messages