Mise en cache sous forme de bitmap

Appliquez la fonction de mise en cache sous forme de bitmap au contenu vectoriel complexe, lorsque cela est possible.

La fonction de mise en cache sous forme de bitmap permet d’effectuer une bonne optimisation. Cette fonction met en cache un objet vectoriel, puis effectue en interne son rendu sous forme de bitmap. Elle utilise ensuite ce bitmap pour le rendu final. Si ce processus se traduit éventuellement par une nette amélioration des performances de rendu, il peut cependant être gourmand en mémoire. Utilisez la fonction de mise en cache sous forme de bitmap pour le contenu vectoriel complexe, tel que les dégradés ou le texte complexes.

L’activation de la fonction de mise en cache sous forme de bitmap pour un objet animé contenant des graphiques vectoriels complexes (tels que du texte et des dégradés) améliore les performances. Cependant, si la fonction de mise en cache des bitmaps est activée sur un objet d’affichage tel qu’une animation dont le scénario s’exécute, vous obtenez le résultat inverse. Sur chaque image, le moteur d’exécution doit mettre à jour le bitmap mis en cache et le retracer à l’écran, ce qui sollicite fortement l’unité centrale. La fonction de mise en cache sous forme de bitmap ne présente des avantages que lorsqu’il est possible de générer une seule fois le bitmap mis en cache, puis de l’utiliser sans le mettre à jour.

Si vous activez cette fonction pour un objet Sprite, il est possible de déplacer celui-ci sans que le moteur d’exécution soit obligé de régénérer le bitmap mis en cache. La modification des propriétés x et y de l’objet n’entraîne pas sa régénération. En revanche, toute tentative de rotation, mise à l’échelle ou modification de sa valeur alpha force le moteur d’exécution à régénérer le bitmap mis en cache, ce qui affecte les performances.

Remarque : cette limitation ne concerne pas la propriété DisplayObject.cacheAsBitmapMatrix, que proposent AIR et l’outil Packager for iPhone. La propriété cacheAsBitmapMatrix permet de faire pivoter, mettre à l’échelle, incliner et modifier la valeur alpha d’un objet d’affichage sans déclencher une régénération de l’image bitmap.

Un bitmap mis en cache peut utiliser plus de mémoire qu’une occurrence de clip courante. Un clip de 250 x 250 pixels sur la scène, par exemple, utilise environ 250 Ko une fois mis en cache, mais seulement 1 Ko lorsqu’il n’est pas mis en cache.

L’exemple ci-dessous est fondé sur un objet Sprite contenant une image de pomme. La classe suivante est associée au symbole de pomme :

package org.bytearray.bitmap 
{     
    import flash.display.Sprite; 
    import flash.events.Event; 
     
    public class Apple extends Sprite 
    { 
        private var destinationX:Number; 
        private var destinationY:Number; 
         
        public function Apple () 
        { 
            addEventListener(Event.ADDED_TO_STAGE,activation); 
            addEventListener(Event.REMOVED_FROM_STAGE,deactivation);     
        } 
         
        private function activation(e:Event):void  
        { 
            initPos();     
            addEventListener (Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function deactivation(e:Event):void  
        { 
            removeEventListener(Event.ENTER_FRAME,handleMovement);     
        } 
         
        private function initPos():void 
        { 
            destinationX = Math.random()*(stage.stageWidth - (width>>1)); 
            destinationY = Math.random()*(stage.stageHeight - (height>>1)); 
        } 
         
        private function handleMovement(e:Event):void  
        { 
            x -= (x - destinationX)*.5; 
            y -= (y - destinationY)*.5; 
             
            if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
                initPos(); 
        } 
    } 
}

Le code utilise la classe Sprite plutôt que la classe MovieClip, car les pommes ne nécessitent pas un scénario chacune. Pour optimiser les performances, utilisez l’objet le plus léger possible. La classe est ensuite instanciée avec le code suivant :

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(MouseEvent.CLICK,createApples); 
stage.addEventListener(KeyboardEvent.KEY_DOWN,cacheApples); 
 
const MAX_NUM:int = 100; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
function createApples(e:MouseEvent):void 
{ 
    for (var i:int = 0; i< MAX_NUM; i++) 
    { 
        apple = new Apple(); 
         
        holder.addChild(apple); 
    } 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holder.numChildren; 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holder.getChildAt (i) as Apple; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Lorsque l’utilisateur effectue un clic de souris, les pommes sont créées sans être mises en cache. Lorsqu’il appuie sur la touche C (code de touche 67), les vecteurs pomme sont mis en cache sous forme de bitmaps et affichés. Cette technique améliore considérablement les performances de rendu sur le bureau et les périphériques mobiles, lorsque l’unité centrale est lente.

En revanche, elle peut très rapidement se révéler très gourmande en mémoire. Dès qu’un objet est mis en cache, sa surface est capturée en tant que bitmap transparent et stockée en mémoire, comme illustré ci-dessous :

Objet et son bitmap de surface stockés en mémoire

Flash Player 10.1 et AIR 2.5 optimisent l’utilisation de la mémoire en appliquant la technique décrite à la section Filtres et déchargement dynamique de bitmaps. Si un objet d’affichage mis en cache est masqué ou hors écran, le bitmap correspondant est libéré de la mémoire après une certaine période d’inutilisation.

Remarque : si la propriété opaqueBackground de l’objet d’affichage est définie sur une couleur spécifique, le moteur d’exécution considère que l’objet est opaque. Utilisé conjointement avec la propriété cacheAsBitmap, le moteur d’exécution crée un bitmap 32 bits non transparent en mémoire. Le canal alpha est défini sur 0xFF, ce qui se traduit par une amélioration des performances, car il est inutile d’appliquer une transparence pour tracer le bitmap à l’écran. Le rendu est encore plus rapide si la fusion alpha n’est pas nécessaire. Si la profondeur d’écran actuelle est limitée à 16 bits, le bitmap en mémoire est stocké sous la forme d’une image 16 bits. L’utilisation de la propriété opaqueBackground n’active pas implicitement la mise en cache sous forme de bitmap.

Pour économiser de la mémoire, utilisez la propriété cacheAsBitmap et activez-la sur chaque objet d’affichage mais pas sur le conteneur. L’activation de la mise en cache sous forme de bitmap sur le conteneur génère un bitmap final beaucoup plus gros en mémoire, soit un bitmap transparent de 211 x 279 pixels utilisant environ 229 Ko de mémoire :

Afficher le graphique en taille réelle
Activation de la mise en cache sous forme de bitmap sur le conteneur

En outre, si vous mettez en cache le conteneur, il se peut que la totalité du bitmap soit mise à jour en mémoire, si une pomme se met à se déplacer sur une image. En revanche, l’activation de la mise en cache sous forme de bitmap sur des occurrences individuelles consiste à mettre en cache six surfaces de 7 Ko, qui consomment uniquement 42 Ko de mémoire :

Afficher le graphique en taille réelle
Activation de la mise en cache sous forme de bitmap sur les occurrences

Si vous accédez à chaque occurrence de la pomme par le biais de la liste d’affichage et appelez la méthode getChildAt(), les références sont stockées dans un objet Vector pour un accès plus rapide :

import org.bytearray.bitmap.Apple; 
 
stage.addEventListener(KeyboardEvent.KEY_DOWN, cacheApples); 
 
const MAX_NUM:int = 200; 
var apple:Apple; 
var holder:Sprite = new Sprite(); 
 
addChild(holder); 
 
var holderVector:Vector.<Apple> = new Vector.<Apple>(MAX_NUM, true); 
 
for (var i:int = 0; i< MAX_NUM; i++) 
{ 
    apple = new Apple(); 
     
    holder.addChild(apple); 
     
    holderVector[i] = apple; 
} 
 
function cacheApples(e:KeyboardEvent):void 
{ 
    if (e.keyCode == 67) 
    { 
        var lng:int = holderVector.length 
         
        for (var i:int = 0; i < lng; i++) 
        { 
            apple = holderVector[i]; 
             
            apple.cacheAsBitmap = Boolean(!apple.cacheAsBitmap); 
        } 
    } 
}

Souvenez-vous que la mise en cache sous forme de bitmap améliore le rendu, à condition de ne pas faire pivoter, mettre à l’échelle ou modifier le contenu mis en cache sur chaque image. Cette amélioration ne se produit pas pour toute transformation autre qu’une translation sur les axes x et y. Flash Player met en effet à jour la copie du bitmap mis en cache pour chaque transformation de l’objet d’affichage. Cela peut se traduire par une forte sollicitation de l’unité centrale et de la batterie et une baisse des performances. Pour rappel, cette limitation ne concerne pas la propriété cacheAsBitmapMatrix, que proposent AIR ou l’outil Packager for iPhone

Le code suivant agit sur la valeur alpha dans la méthode de mouvement, ce qui a pour effet de modifier l’opacité de la pomme à chaque image :

private function handleMovement(e:Event):void  
{ 
        alpha = Math.random(); 
        x -= (x - destinationX)*.5; 
        y -= (y - destinationY)*.5; 
             
        if (Math.abs(x - destinationX) < 1 && Math.abs(y - destinationY) < 1) 
            initPos(); 
}

L’utilisation de la fonction de mise en cache sous forme de bitmap entraîne un ralentissement des performances. A chaque modification de la valeur alpha, le moteur d’exécution doit mettre à jour le bitmap mis en cache en mémoire.

Les filtres s’attendent à ce que les bitmaps soient mis à jour à chaque déplacement de la tête de lecture d’un clip mis en cache. Par conséquent, l’application d’un filtre entraîne automatiquement la définition de la propriété cacheAsBitmap sur true. La figure suivante illustre une animation :

Clip animé

Il est préférable de ne pas appliquer de filtres à du contenu animé, car ils risquent d’entraîner des problèmes de performances. Dans l’exemple suivant, le concepteur ajoute un filtre d’ombre portée :

Clip animé doté du filtre Ombre portée

Si le scénario que contient le clip s’exécute, le bitmap doit être régénéré. Cette opération est également nécessaire si le contenu subit toute modification autre qu’une simple transformation x ou y. Le moteur d’exécution doit retracer le bitmap sur chaque image. Cette opération sollicite fortement les ressources de l’unité centrale, entraîne des performances médiocres et consomme plus de batterie.

Paul Trani fournit des exemples d’utilisation de Flash Professional et d’ActionScript pour optimiser les graphiques à l’aide de bitmaps dans les vidéos de formation suivantes :