Bitmap.Config.HARDWARE vs Bitmap.Config.RGB_565

2022-09-01 04:00:51

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

答案 1

文档和公共源代码尚未推送到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);

寻找AHardwareBuffer的文档,在引擎盖下,它正在Android共享内存(“ashmem”)中创建一个由ANativeWindowBuffer(本机图形缓冲区)支持的缓冲区。但实际实现可能因硬件而异。EGLClientBuffer

至于问题:

  1. 我们应该总是更喜欢现在的Bitmap.Config.HARDWARE而不是Bitmap.Config.RGB_565吗?

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

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

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

更新:实验表明,没有抛出任何 OutOfMemoryException。虽然分配成功 - 但一切正常。分配失败后 - 模拟器崩溃(刚刚消失)。在其他情况下,我在应用程序内存中分配位图时遇到了一个奇怪的问题。NullPointerException

由于不可预测的稳定性,我不建议目前在生产环境中使用此新API。至少没有广泛的测试。

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

像素数据将位于共享内存中(可能是纹理内存),但Java中仍然有一个小对象引用它(因此“ANY”是不准确的)。Bitmap

每个供应商都可以决定以不同的方式实现实际分配,这不是他们绑定到的公共API。所以可能仍然是一个问题。我不确定如何正确处理它。OutOfMemoryException

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

标志不是关于质量,而是关于像素存储位置。由于配置标志不能被 -ed,我认为默认 () 用于解码。HARDWAREORARGB_8888

(实际上,枚举对我来说似乎是一个黑客)。HARDWARE

  1. 解码本身的速度是否相同/更好/更糟...?

HARDWARE标志似乎与解码无关,因此与 相同。ARGB_8888

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

当内存耗尽时,我的测试结果非常糟糕。模拟器有时会崩溃得很糟糕,而我在其他情况下会遇到意想不到的无关NPE。没有发生OutOfMemoryException,也没有办法判断GPU内存何时耗尽,因此无法预见这一点。


答案 2

推荐