作为绘制缓冲区的Android Bitmap对象

3

设置: 我已经实现了一种本地(即JNI)机制,用于从Bitmap对象复制像素到本地内存。这是通过在本地内存中使用malloc()uint23_t数组并稍后使用memcpy()将像素从/到位图的本地指针进行的。这很有效,并且已经过测试。成功地将像素保存在本地内存中,从Bitmap对象中复制回来,并在屏幕上可见。它在复制方面非常快,对于相当大的位图,速度高达几毫秒的级别。但在渲染方面极慢。

意图: 以上内容是为了摆脱默认Android Bitmaps的堆限制而完成的(请参阅https://dev59.com/dHI-5IYBdhLWcg3wQV8Z#1949205)。只会有1个Java Bitmap对象在本地内存和目标画布之间充当缓冲区。

保存形状:

  1. 清除缓冲区位图。
  2. 在位图上绘制形状。
  3. 将像素复制到本地内存并保存内存指针。
  4. 清除缓冲区位图。

因此,可以将任意数量的形状保存到本地内存中,而不会遇到堆大小限制。这有效。

稍后需要绘制形状时(例如在onDraw()中):

  1. 清除缓冲区位图。
  2. 使用保存的内存指针从本地内存复制像素到缓冲区位图。
  3. canvas上绘制缓冲区位图。
  4. 清除缓冲区位图。
  5. 为下一个形状重复以上步骤。

问题:当快速从内存中绘制许多形状时,缓冲区Bitmap会有点卡顿。基本上我们正在做的是

clear bitmap -> load pixels from memory onto it -> draw it on view canvas

onDraw()中,快速连续地绘制形状时,只有最新的形状像素被绘制到画布上。看起来好像有以下两种情况:
  1. canvas.drawBitmap() 是异步的,有时会稍后从位图中复制像素。
  2. Android的 Bitmaps 有一些隐藏的缓存机制。
有人遇到过这样的问题吗?或者对此有什么见解?
我知道可以在JNI中获取本地skia lib的画布实例并在其上进行绘制,但这是一种非标准的方式。

我不认为两种可能性都是正确的。我想知道你在查看不同图像时如何使用它的代码。 - berserk
@berserk 我会尝试更新源链接。谢谢。 - S.D.
好的,我会等待它。 - berserk
2个回答

2

在最近的Android版本(包括3.0及以上版本,这是大多数设备所使用的版本),像素使用常规的Java内存堆。随着硬件加速技术的引入,位图会异步绘制,并且有一个缓存系统来管理作为纹理加载到GPU的位图。因此,您尝试进行的hack可能会降低新设备的性能。如果需要更多的内存,请尝试在清单文件中使用largeHeap="true"。


我同意。而且问题中的“对于相当大的位图,最多几毫秒的顺序”实际上并不快,考虑到您只有16ms来跟上60fps。 - Dmitry Zaytsev
@DmitryZaitsev memcpy 对于 1000x1000 像素的数据来回传输大约需要 3ms-8ms。瓶颈在 Java 端的 Bitmap 上。它太慢了,无法在 Java 端复制像素。 - S.D.
@yoah 你说得对。问题在于 canvas.drawBitmap(int[],..)canvas.drawBitmap(bitmap,..) 的区别。前者没有缓存但非常慢,后者非常快但有缓存,因此对我的意图毫无用处。我看到 GL 纹理每次都被创建/销毁。虽然我不明白安卓开发人员为什么要采用这种实现方式。无论如何,感谢你的回答 :)。 - S.D.

1
在相对较新的Android设备上(从3.0开始,如果我没记错的话),使用硬件加速的canvas.drawBitmap方法实际上并不会绘制任何东西(包括dispatchDrawdrawonDraw)。相反,它会在显示列表中创建记录,这些记录可能会被缓存无限长的时间,并且将来(而不是立即)进行绘制。目前它不完全是异步的,只是稍后在同一线程中执行。
我认为这两点就是你问题的答案。
或者,您可以为您的视图/窗口禁用硬件加速,并查看您的方法是否有效。
更多阅读资料:

http://android-developers.blogspot.de/2011/03/android-30-hardware-acceleration.html

http://developer.android.com/guide/topics/graphics/hardware-accel.html#model


我认为你关于纹理缓存和显示列表的想法是正确的。当我使用一个 int[](像素)而不是 Bitmap 作为缓冲区时,所有的形状都被正确地绘制出来了。 - S.D.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接