Why do NDK-updated bitmaps show black when hardwareAccelerated is turned on in Honeycomb?
I have an Android imaging application and have been using native code to draw directly into Java bitmaps; everything has been working fine. I just got an Acer A500 tablet and decided to try using the new Honeycomb android:hardwareAccelerated attribute. The bitmaps all show up as b开发者_高级运维lack when it's enabled. I am using a simple, full-screen view with canvas drawing. Does anyone have an idea of how to get it to update the OpenGL texture when I draw into my bitmaps?
As said in this article, the pixel data for Bitmap objects is stored in byte arrays on Android 3.0 (Honeycomb). Previously it was not stored in the Dalvik heap but was stored in external heap which is not managed by Dalvik VM.
So it is a big difference between Android 2.x and 3.x. And it might not be safe to draw into bitmap from native code because NDK does not provide native API for levels higher then 9. In general API should be backward compatible but hardwareAccelerated attribute changes the behavior of several methods and may break compatibility.
For example the following operations behave differently when hardware acceleration enabled:
- Canvas
- clipRect: XOR, Difference and ReverseDifference clip modes are ignored; 3D transforms do not apply to the clip rectangle
- drawBitmapMesh: colors array is ignored
- drawLines: anti-aliasing is not supported
- setDrawFilter: can be set, but ignored
- Paint
- setDither: ignored
- setFilterBitmap: filtering is always on
- setShadowLayer: works with text only
- ComposeShader
- A ComposeShader can only contain shaders of different types (a BitmapShader and a LinearGradientShader for instance, but not two instances of BitmapShader)
- A ComposeShader cannot contain a ComposeShader
Here are more details about hardware acceleration: http://android-developers.blogspot.com/2011/03/android-30-hardware-acceleration.html
The problem seems to be that Android doesn't update the 'generation number' of the texture it uses behind the scenes for the bitmap, so it doesn't make any use of the new pixel data. I had a similar problem (in my map-drawing library, CartoType, which runs as native code on Android) and solved it by writing the value 0 to the top-left pixel before getting the fresh data. Here's my Java code with explanatory comment:
private void getMap()
{
NativeInterface.getMap(iDemoFrameworkRef,iBitmapData);
iBuffer.rewind();
/*
Hack: we have to change the bitmap because the Android hardware-accelerated canvas will not
re-upload the bitmap unless it has a different generation number,
and copyPixelsFromBuffer doesn't change the generation number.
See http://osdir.com/ml/Android-Developers/2011-10/msg02215.html.
*/
iBitmap.setPixel(0,0,0);
iBitmap.copyPixelsFromBuffer(iBuffer);
}
This problem occurred on a Galaxy Nexus using Android 4.0. The code worked perfectly on the simulator, but not on the hardware till I added the hack. Then everything was fine.
精彩评论