Bitmap.Config.HARDWARE与Bitmap.Config.RGB_565

Ale*_*mov 32 java performance android image bitmap

API 26 添加了新选项 Bitmap.Config.HARDWARE:

特殊配置,当位图仅存储在图形内存中时.此配置中的位图始终是不可变的.对于具有位图的唯一操作是在屏幕上绘制它的情况,它是最佳的.

文档中未解释的问题:

  1. 如果我们现在总是喜欢Bitmap.Config.HARDWAREBitmap.Config.RGB_565当速度是重中之重,质量和可变性都没有(如缩略图等)?
  2. 使用此选项解码后的像素数据实际上不消耗任何堆内存并仅驻留在GPU内存中吗?如果是这样的话,OutOfMemoryException在处理图像时,这似乎最终会令人担忧.
  3. 我们应该从这个选项中获得与RGB_565,RGBA_F16或ARGB_8888相比的质量?
  4. 是的速度解码本身相同/更好/更值得相较于RGB_565解码?
  5. (感谢@CommonsWare在评论中指出它)如果我们在使用此选项解码图像时超过GPU内存会怎样?会抛出一些异常(也许是相同的OutOfMemoryException:)?

Ami*_*val 15

文档和公共源代码尚未推送到Google的git.因此,我的研究仅基于部分信息,一些实验,以及我自己将JVM移植到各种设备的经验.

我的测试创建了大型可变位图,并通过单击按钮将其复制到新的硬件位图中,并将其添加到位图列表中.我设法在崩溃之前创建了大型位图的几个实例.

我能够在android-o-preview-4 git push中找到它:

+struct AHardwareBuffer;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
+#else
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
Run Code Online (Sandbox Code Playgroud)

并且在寻找AHardwareBuffer文档时,它在Android共享内存("ashmem")中创建了一个EGLClientBuffer支持ANativeWindowBuffer(本机图形缓冲区).但实际实施可能因硬件而异.

至于问题:

  1. 我们现在总是喜欢Bitmap.Config.HARDWARE而不是Bitmap.Config.RGB_565 ......?

对于SDK> = 26,HARDWARE配置可以通过防止每次相同位图返回到屏幕时将像素数据复制到GPU的需要来改进低级别位图绘制.我想它可以防止在将位图添加到屏幕时丢失一些帧.

内存不计入您的应用程序,我的测试证实了这一点.

本机库文档说null如果内存分配不成功,它将返回.在没有源代码的情况下,不清楚Java实现(API实现者)在这种情况下将做什么 - 它可能决定抛出OutOfMemoryException或回退到不同类型的分配.

更新:实验显示没有抛出OutOfMemoryException.虽然分配成功 - 一切正常.分配失败 - 模拟器崩溃(刚刚消失).在其他场合,我NullPointerException在app内存中分配Bitmap时有点奇怪.

由于不可预测的稳定性,我不建议目前在生产中使用这个新的API.至少没有进行大量测试.

  1. 使用此选项解码后的像素数据实际上不消耗任何堆内存并仅驻留在GPU内存中吗?如果是这样的话,OutOfMemoryException在处理图像时,这似乎最终会令人担忧.

像素数据将位于共享内存(可能是纹理内存)中,但BitmapJava中仍然有一个小对象引用它(因此"任何"都是不准确的).

每个供应商都可以决定以不同的方式实施实际分配,它不是他们必须遵守的公共API.所以OutOfMemoryException可能仍然是一个问题.我不确定如何正确处理它.

  1. 与RGB_565/ARGB_8888相比质量如何?

HARDWARE标志是不是质量,而是关于像素的存储位置.由于配置标志不能用于OR-ed,我认为default(ARGB_8888)用于解码.

(实际上,HARDWAREenum对我来说似乎是一个黑客).

  1. 解码速度本身是相同/更好/更差......?

HARDWARE标志似乎与解码无关,所以一样ARGB_8888.

  1. 如果超过GPU内存会发生什么?

当内存耗尽时,我的测试结果非常糟糕.模拟器有时会崩溃,我在其他场合遇到了意想不到的NPE.没有发生OutOfMemoryException,也没有办法判断GPU内存何时耗尽,所以没办法预见到这一点.

  • 干得好。令人难以置信的是,官方文档中对此的记录如此糟糕。 (3认同)