Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Silverlight : Optimiser les performances des traitements graphiques

[new:12/6/2010] Silverlight est totalement graphique, optimiser les traitements graphiques pourrait s’appliquer à toutes les applications Silverlight donc. Mais en fait ici je parle de celles qui font réellement une utilisation intensive du graphique. Et il existe plusieurs choses importantes à savoir dans un tel contexte pour obtenir un résultat fluide et de bonnes performances .

Le Debug

Plusieurs options de Silverlight peuvent vous aider à trouver les failles de performances :

EnableRedrawRegions

Quand cette option est en route Silverlight affiche les rectangles qui sont redessinés. Les régions ainsi délimitées apparaissent en bleu, en jaune ou rose. C’est à la création du plugin qu’il faut ajouter l’option et non dans l’application elle-même en utilisant le paramètre de nom EnableRedrawRegions et en indiquant la valeur “true” (la façon exacte dépend de si vous utiliser une balise ASP.NET Silverlight ou d’une balise HTML Object).

MaxFrameRate

Cette option (au niveau plugin aussi) permet de fixer un frame rate (nombre d’images par seconde) autre que celui par défaut (60 d’après MSDN). Il est important de savoir que la valeur par défaut peut s’avérer excessive pour une application de type gestion (affichage d’informations, grilles de données, etc) et qu’il est souvent préférable de la descendre entre 10 et 30 pour éviter de consommer trop de puissance processeur pour rien. Le mieux est de descendre la valeur jusqu’à temps que cela se voit (artefacts visuels, animations perdant de leur fluidité, etc). Quand vous arrivez à cette valeur (enfin juste au dessus) vous avez optimisé le frame rate. Rappelons au passage qu’il s’agit bien du “Max” frame rate, c’est à dire la vitesse maximale qui dépend de l’hôte et de sa charge, le frame rate réel peut être bien inférieur si l’hôte rame comme un fou ! Aussi, rien ne sert de mettre au point une application avec un frame rate à 120 sur votre machine de compétition alors que les utilisateurs ne pourront au mieux obtenir peut-être que la moitié, voire moins…

EnableFrameRateCounter

Pour évaluer l’impact d’un traitement graphique ou vérifier la vitesse actuelle de rafraichissement de votre application, ou pour effectuer un réglage fin du MaxFrameRate, encore faut-il savoir combien d’images par secondes sont traitées par le plugin… En activant cette option (au niveau du plugin aussi) Silverlight affichera un compteur des FPS à l’écran.

Attention cela ne fonctionne que sur Internet Explorer et sur un OS Windows. Si vous testez l’application sous Chrome, Firefox ou sur un Mac, cette information ne sera pas affichée même si l’option est activée.

EnableGPUAcceleration

Par défaut les optimisations GPU sont désactivées… car avant d’activer cette option (dans le plugin aussi) il est préférable de comprendre comment elle agit. D’autant qu’elle a un fonctionnement assez limité. En effet, si WPF se repose totalement sur DirectX, puisque ces deux technologies fonctionnement exclusivement sur Windows, Silverlight par sa nature cross-plateforme est obligé de se baser sur un consensus minimaliste.

Ainsi, l’accélération matérielle ne fonctionne que sous Windows Vista, Windows 7 et Windows XP. Pas sur Mac par exemple. Et sous XP encore faut-il que le pilote de la carte (Nvidia, ATI ou Intel uniquement) soit plus récent que novembre 2004…

Autant dire que si cela fonctionne sur votre machine cela peut ramer sur celles des utilisateurs si leurs machines ne sont pas dans les rails de ces exigences !

Utiliser l’accélération GPU doit se faire dans un esprit particulier : si la machine le supporte l’application sera encore plus fluide, mais elle doit être au minimum “correcte” si l’accélération n’est pas possible. Ce qui implique de concevoir et d’optimiser les applications sans cette option puis de l’ajouter et de voir comment elle peut aider et rendre l’interface plus fluide.

N’oubliez pas non plus que l’accélération GPU fonctionne au niveau de l’objet et chaque objet visuel doit avoir son CacheMode défini à BitmapCache, avec des implications non négligeables et parfois imprévisibles sur le visuel (pixellisation, transformations plus lentes que sans accélérations…).

EnableCacheVisualization

Lorsque vous souhaitez activer l’accélération GPU il peut être intéressant de vérifier quelles zones en profite réellement. Cette option s’active aussi au niveau du plugin. Toutes les textures dont le rendu est effectué par logiciel (et qui donc ne bénéficient pas de l’accélération) seront affichées avec une couleur choisie au hasard (différente pour chaque couche).

XPerf

Il s’agit d’un utilitaire Microsoft fourni avec le SDK de Windows 7, on le trouve dans les Windows Performance Analysis Tools (WPT).

L’étude de cet outil dépasse le cadre de ce billet et je renvoie le lecteur intéressé au lien précédent pour plus d’information. Xperf n’est pas limité à Silverlight, c’est un outil complet d’analyse des performances. Il peut s’avérer essentiel pour débusquer les lenteurs et manques de fluidité dans les applications de tout type, dont Silverlight.

Les vidéos

Le pipe-line de Silvelight lorsqu’il joue un média de type vidéo est le suivant :

  1. Décodage de l’image
  2. Conversion YUV
  3. Calcul du resize si l’image n’est pas affichée dans sa taille originale
  4. Mélange des couches si nécessaires (par exemple surimpression d’une barre de commande, de symboles…)
  5. Dessin effectif de l’image.

Il en découle quelques évidences :

    • Encodez toujours vos vidéos dans la taille à laquelle vous les affichez… Si vous changez la taille d’affichage en cours de conception, réencodez la vidéo dans la nouvelle taille.
    • Encodez les vidéos avec un le frame rate le plus bas acceptable visuellement sauf si vous souhaitez faire de la HD réclamant une connexion ADSL que beaucoup de gens n’ont pas. L’élitisme en la matière est stupide. Même avec de l’ADSL2+ chez moi j’ai souvent des problèmes sur les vidéos HD tout simplement parce les prétentieux qui les fournissent n’ont pas forcément les moyens de mettre des serveurs à la hauteur… Alors soyez humble, choisissez un format correct le plus sobre possible que vos serveurs pourront supporter en offrant une video fluide, c’est mieux qu’un truc en HD avec des saccades ! Ou alors, pour la HD, “crachez le budget” serveur qui va avec ! :-) Et cela avec ou sans Silverlight.
    • Sur-impressionner des couches sur de la vidéo est très coûteux, évitez de le faire… (genre barre de commande en opacité réduite et autres zinzins qui peuvent parfaitement être affichés sur l’un des côtés plutôt qu’en surimpression).
    • Quand vous utilisez des vidéos dans votre application essayez de ne pas descendre sous un frame rate de 60 fps pour un affichage correct.

Le Texte

Le texte c’est simple, vectoriel, rapide. Mais en fait ce n’est qu’un dessin comme les autres, et souvent assez complexe ! Le moteur de rendu de Silverlight est amené a recréer l’image d’un texte dans de nombreuses conditions ce qui dégradera plus ou moins visiblement les performances. Par exemple une simple translation (ce qui n’est pas forcément “logique”) ou tout changement d’échelle oblige le moteur à recalculer le texte ce qui ralentit le rendu. Mettre du texte sur une vidéo implique un ralentissement important (rendu du texte, séquence de fusion image décodée / texte rendu).

Dans bon nombre de cas, et même si cela fait perdre beaucoup de souplesse, il est préférable d’utiliser un PNG avec transparence pour gérer du texte qu’un objet texte. Un PNG supportera facilement un changement de taille pas trop important sans impact visuel et sera bien plus rapide à afficher. Bien entendu cela s’entend pour les applications utilisant intensivement les graphiques (le titre de ce billet). La perte de souplesse (mise à jour du texte notamment) étant tellement importante qu’elle doit se justifier sérieusement.

Le plugin Silverlight

Certains réglages du plugin ont un impact plus ou moins important sur les performances. Certains sont évidents (frame rate, accélération GPU) d’autres sont plus “sournois”.

Sournois à double titre d’ailleurs. D’une part parce qu’il n’est pas évident de savoir qu’ils ont un impact sur les performances, et d’autre part parce que cet impact peut fort bien varier d’une version à l’autre de Silverlight sans que cela ne soit forcément mentionné quelque part.

Windowless

Laissez ce paramètre à false. Lorsqu’il est à “true” les performances sont dégradées. Le positionner à “true” n’a de toute façon d’intérêt que s’il est nécessaire de mixer le contenu de l’application avec de l’affichage Html.

Pourquoi cette dégradation ? il faut d’abord répondre à la question “à quoi sert ce paramètre ?” ! Et ça, je viens de le dire (deux qui suivent seulement pfff!), et oui, ça sert à pouvoir mixer du contenu Html avec l’affichage du plugin. Quand je dis mixer, c’est mixer, comme de la musique. Quand on mixe de la musique on superpose plusieurs couches, on ne les juxtapose pas. Mixer Html et affichage Silverlight signifie donc pouvoir écrire par dessus l’affichage de Silverlight depuis la page Html (ou le contraire).

Nous pouvons maintenant répondre à la première question. Qui se résume à en poser une troisième “comment ça marche le windowless ?”. C’est tout simple : au lieu que le plugin dispose de son propre espace rectangulaire dans lequel il fait ce qu’il veut, en mode windowless (=true donc) Silverlight délègue l’affichage au browser.

Vous imaginez maintenant la perte de performance : pour chaque frame, SL doit avertir le browser, lui passer l’image, et le browser doit recalculer son propre rendu, les éventuelles surimpressions et réafficher le tout.

Bien entendu Windowless a son utilité (ajouter des symboles vectoriels SL au dessus d’un affichage telle une carte géographique gérée par la page Html par exemple) mais ce mode ne doit pas être utilisé sans en comprendre son impact. Notons parmi ceux-ci, et outre les performances globales qui sont largement touchées :

    • Pas de possibilité de gérer la souris en Html si l’affichage SL est au dessus (même avec un fond transparent)
    • Pas de capture de la souris en dehors des limites du plugin SL (même si ces limites sont invisibles)
    • Pas d’IME ou de support pour l’Accessibilité
    • Pas de support du mode plein écran
    • Problèmes divers selon les browsers et les OS
      • effet de déchirement visuel dans les animations et les vidéos sous XP ou Vista avec DWM déconnecté et sous IE peut importe la plateforme
      • Rendu peu fiable sous Safari
      • Problèmes de focus sur les browsers Mozilla
      • etc.

Pluginbackground

Evitez autant que possible de mettre le fond du plugin en mode “Transparent” sauf si cela est absolument nécessaire. Le plus souvent j’ai vu cette pratique dans le seul but de s’assurer que le fond de l’application SL est le même que celui de la page Htm hôte. Si vous créez une application sérieuse devant s’intégrer sur des pages Html, il existe forcément une charte graphique pour ces dernières. Utiliser la couleur de fond indiquée par la charte comme couleur de fond du plugin. Vérifiez aussi que la taille d’affichage du plugin correspond bien celle fixée dans la page SL (si elle n’est pas en mode auto). Car si le plugin prend plus de place que la taille des pages SL, un bord blanc apparaitra autour !

Autres conseils

Bien d’autres choses sont à considérées si on souhaite qu’une application Silverlight soit efficace, fluide et rapide. Citons en vrac :

  • Ne gonflez pas votre code par des ajouts et des ajouts, principalement le code Xaml. Si lors de la conception vous devez complexifier le code, refactorez, réorganisez et tentez de conserver un code compact. Ce conseil porte sur le code behind autant que sur Xaml. Tout code Xaml a un impact sur le visuel et sa fluidité. Les lourdeurs, mauvaises approches et autres propriétés fixées pour les tests qu’on oublie sont autant de boulets que votre application traînera !
  • Lorsque votre application n’a rien de spécial à faire, coupez son activité : stoppez les animations, stoppez les calculs en tâche de fond, etc. Bien entendu cela peut s’avérer contre productif, à vous de juger au cas par cas, mais coupez toujours le maximum de choses, ne laissez pas tourner des animations pour rien notamment (objets cachés par d’autres, attention de l’utilisateur focalisée ailleurs…).
  • Toute brosse qui est resizée réclame la création d’une nouvelle texture ce qui coûte cher en temps de calcul et en mémoire. Eviter les resize autant que possible.
  • Quand Silverlight joue une animation il ne redessine que les parties rectangulaires qui le nécessitent ; animez des petits objets et évitez d’animer des placards !
  • Les videos peuvent nécessiter un FPS de 60 au minimum, mais une application standard se contente de 10 à 30 FPS, 20 à 30 étant généralement la fourchette la plus consensuelle (en termes de fluidité et de consommation de ressources).
  • Testez sur plusieurs plateformes et plusieurs browsers !
  • Pendant le développement affichez toujours le compteur de frames, c’est un bon indicateur qui, s’il se dégrade d’un seul coup, vous permettra de cibler immédiatement le code incriminé (le dernier ajouté…).
  • Quand vous animez l’opacité ou une transformation de tout descendant de UIElement, utilisez le CacheMode car si l’accélération GPU est en route (et disponible sur la plateforme hôte) ces opérations seront réalisées par le processeur graphique et non par votre application.
  • En même temps, méfiez-vous du CacheMode qui peut engendrer des contre-performances dans certains cas ! Testez au cas par cas.
  • Pour cacher un élément, utilisez Visibility plutôt qu’une opacité à 0. Dans ce dernier cas l’objet existe toujours et gère le Hit Test. Un coût inutile s’il est invisible car inutile. SL 4 permet d’animer par des transitions les propriétés de type Visibility ce qui n’était pas le cas avant. Vous pouvez donc cacher totalement un objet plutôt que de le rendre transparent sans pour autant que ce changement se fasse avec violence !
  • Sachez que Silverlight utilise pleinement les machines multi-coeurs pour son moteur de rendu et l’affichage des médias de type videos. Si vous avez comme moi une machine principale à 4 coeurs en hyperthreading (donc 8 apparents pour l’OS) il est préférable de tester vos applis sur la machine de votre petite soeur pour vous assurez qu’elles ne seront pas utilisables uniquement que par quelques geeks sur-équipés !
  • En mode plein-écran il est encore plus important de cacher (Visibility=false) les éléments inutiles qu’en mode normal (entendu pour les performances).
  • Evitez de fixer une taille précise à un élément média : laissez-le s’afficher dans sa résolution native et adaptez votre affichage à la place restante. Le resize des vidéos comme expliqué plus haut est coûteux.
  • Attention : Lorsque du code-behind s’exécute Silverlight ne met plus à jour l’affichage ! Cela ne se voit pas si ce code est court et rapide, mais si vous devez exécuter des méthodes lourdes, pensez à découper le travail en petites unités comportant des pauses pour éviter que le frame rate global ne chute dramatiquement !
  • Parfois Silverlight a du mal à charger des XAP trop gros… Il est important de concevoir son application de telle sorte que le XAP principal soit le plus petit possible. Utilisez MEF, utilisez du lazy loading, séparer les ressources de grandes tailles (images, fichiers) de votre XAP pour les télécharger à part, etc…
  • Un détail étonnant : Double.Tostring() est moins rapide que Double.ToString(CultureInfo.InvariantCulture) ! Si votre application doit stocker, traiter ou comparer des doubles transformés en string sans avoir à les afficher, spécifiez toujours la culture invariante, elle est optimisée pour la vitesse. Pour une présentation de données à l’utilisateur utilisez ToString() qui par défaut utilise la culture courante bien entendu (ou un convertisseur ou une chaîne de format Xaml).
  • Un autre détail intéressant : Si vous utilisez beaucoup d’images, placez leur mode Stretch à Fill. Cela peut paraître contre intuitif mais dans ce mode de nombreux calculs sont évités ce qui le rend plus rapide même que “None”. La différence n’est pas énorme mais lorsque beaucoup d’images sont traitées cela peut avoir un impact non négligeable.

Conclusion

Le sujet est vaste… et ce long billet le prouve ! Mais développer une application Silverlight ce n’est certainement pas reproduire les automatismes acquis sous Windows Forms, les MFC, Delphi ou Java ! Je vois beaucoup trop de développeurs qui abordent Silverlight comme un simple module d’affichage qu’on pluguerait  sur un code existant à la place de ASP.NET ou de Windows Forms… J’ai vu la même chose d’ailleurs en ASP.NET avec des applications conçues comme s’il s’agissait d’applications desktop, avec des résultats désastreux, forcément.

Silverlight est une technologie “légère”, surtout laissez toujours quelques neurones allumés dans un coin pour vous en souvenir ! "Légère" cela veut dire qu’elle se destine au Web, à l’intérieur d’un browser, qu’elle se destine aux smartphones (sous Phone 7), autant de contextes où il n’est pas question de donner dans le dantesque ou le goulu ! Si vous voulez faire du gros, du lourd, faites-le en WPF, une technologie robuste pour le desktop utilisant DirectX et tout le framework, toute la puissance machine.

Se tromper d’outil est parfois une erreur grave qui se paye cher. Silverlight est étudié pour faire “certaines choses”. Programmez-le en dehors de ce contexte et vous irez au mur tout en lui faisant une mauvaise publicité. Ce n’est pas parce que le Web c’est la mode et que Silverlight est super cool qu’il faut vouloir reprogrammer votre énorme soft de gestion sous Silverlight. Cela serait certainement une erreur.

En réalité les problèmes de performances les plus graves ne sont pas ceux que j’ai évoqués dans ce billet. Les plus graves prennent souvent racines dans un mauvais choix technologique à la base même d’un projet !

Soyez vous-mêmes performants et bien sûr … Stay Tuned !

blog comments powered by Disqus