web-dev-qa-db-fra.com

Bitmap.Config.HARDWARE vs Bitmap.Config.RGB_565

API 26 ajoute une nouvelle optionBitmap.Config.HARDWARE:

Configuration spéciale, lorsque le bitmap est stocké uniquement dans la mémoire graphique. Les bitmaps de cette configuration sont toujours immuables. Il est optimal pour les cas où la seule opération avec le bitmap est de le dessiner sur un écran.

Questions qui ne sont pas expliquées dans les documents:

  1. Faut-il TOUJOURS préférer maintenant Bitmap.Config.HARDWARE plus de Bitmap.Config.RGB_565 lorsque la vitesse est prioritaire et que la qualité et la mutabilité ne le sont pas (par exemple pour les miniatures, etc.)?
  2. Les données de pixels après décodage à l'aide de cette option ne consomment-elles AUCUNE mémoire de tas et résident-elles uniquement dans la mémoire GPU? Si tel est le cas, cela semble enfin être un soulagement pour OutOfMemoryException lorsque vous travaillez avec des images.
  3. Quelle qualité par rapport à RGB_565, RGBA_F16 ou ARGB_8888 devrions-nous attendre de cette option?
  4. La vitesse de décodage elle-même est-elle la même/meilleure/vaut-elle par rapport au décodage avec RGB_565?
  5. (Merci @CommonsWare de l'avoir signalé dans les commentaires) Que se passerait-il si nous dépassions la mémoire GPU lors du décodage d'une image à l'aide de cette option? Une exception serait-elle levée (peut-être la même OutOfMemoryException :)?
31
Alexander Abakumov

La documentation et le code source public ne sont pas encore poussés à git de Google . Donc, mes recherches ne sont basées que sur des informations partielles, quelques expériences et sur ma propre expérience de portage de JVM vers divers périphériques.

Mon test a créé un grand bitmap mutable et l'a copié dans un nouveau bitmap HARDWARE en un clic sur un bouton, l'ajoutant à une liste bitmap. J'ai réussi à créer plusieurs instances des grands bitmaps avant qu'il ne plante.

J'ai pu le trouver dans le 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);

Et en recherchant documentation de AHardwareBuffer , sous le capot, il crée un EGLClientBuffer soutenu par ANativeWindowBuffer (tampon graphique natif) dans = Android mémoire partagée ("ashmem"). Mais l'implémentation réelle peut varier d'un matériel à l'autre.

Pour les questions:

  1. Faut-il TOUJOURS préférer maintenant Bitmap.Config.HARDWARE à Bitmap.Config.RGB_565 ...?

Pour le SDK> = 26, la configuration HARDWARE peut améliorer le dessin bitmap de bas niveau en évitant d'avoir à copier les données de pixels sur le GPU chaque fois que le même bitmap revient à l'écran. Je suppose que cela peut empêcher de perdre certaines images lorsqu'un bitmap est ajouté à l'écran.

La mémoire n'est pas prise en compte dans votre application, et mon test l'a confirmé.

Les documents de la bibliothèque native indiquent qu'il renverra null si l'allocation de mémoire a échoué. Sans le code source, il n'est pas clair ce que l'implémentation Java (les implémenteurs d'API) fera dans ce cas - il pourrait décider de jeter OutOfMemoryException ou de retomber dans un autre type d'allocation.

Mise à jour: L'expérience révèle qu'aucune exception OutOfMemoryException n'est levée. Bien que l'allocation soit réussie - tout fonctionne bien. En cas d'échec de l'allocation - l'émulateur s'est écrasé (il vient de disparaître). À d'autres occasions, j'ai un NullPointerException étrange lors de l'allocation de Bitmap dans la mémoire de l'application.

En raison de la stabilité imprévisible, je ne recommanderais pas d'utiliser cette nouvelle API en production actuellement . Du moins pas sans tests approfondis.

  1. Les données de pixels après décodage à l'aide de cette option ne consomment-elles AUCUNE mémoire de tas et résident-elles uniquement dans la mémoire GPU? Si tel est le cas, cela semble enfin être un soulagement pour OutOfMemoryException lorsque vous travaillez avec des images.

Les données de pixels seront dans la mémoire partagée (probablement la mémoire de texture), mais il y aura toujours un petit objet Bitmap dans Java le référençant (donc "ANY" est inexact)).

Chaque fournisseur peut décider d'implémenter l'allocation réelle différemment, ce n'est pas une API publique à laquelle il est lié. OutOfMemoryException peut donc toujours poser problème. Je ne sais pas comment cela peut être géré correctement.

  1. Quelle qualité par rapport à RGB_565/ARGB_8888?

L'indicateur HARDWARE ne concerne pas la qualité, mais l'emplacement de stockage des pixels. Étant donné que les drapeaux de configuration ne peuvent pas être OR- ed, je suppose que la valeur par défaut (ARGB_8888) est utilisé pour le décodage.

(En fait, l'énumération HARDWARE me semble être un hack).

  1. La vitesse de décodage est-elle la même/meilleure/pire ...?

HARDWARE flag ne semble pas lié au décodage, donc identique à ARGB_8888.

  1. Que se passerait-il si nous dépassions la mémoire GPU?

Mon test donne de très mauvaises choses lorsque la mémoire est épuisée. L'émulateur s'est écrasé horriblement parfois, et j'ai eu NPE inattendu sans rapport à d'autres occasions. Aucune OutOfMemoryException ne s'est produite et il n'y avait également aucun moyen de savoir quand la mémoire du GPU s'épuisait, donc aucun moyen de le prévoir.

12
Amir Uval