Quand une vue (ou un calque) nécessite-t-elle un rendu hors écran?

Bonjour
ce week-end j'ai commencé à regarder les videos de la WWDC 2011. J'ai trouvé des sujets vraiment intéressants sur iOS. Mes favoris portaient sur la performance et les graphismes, mais j'ai trouvé deux d'entre eux apparemment en contradiction. Bien sûr, il y a quelque chose que je n'ai pas eu. Les sessions dont je parle sont Understanding UIKit Rendering -121 et Polishing your -105.
Malheureusement, l'exemple de code de 2011 n'est toujours pas téléchargeable, il est donc assez difficile d'avoir une vue d'set. Dans une session, ils expliquent que la plupart du time le rendu hors écran doit être évité lors de la visualisation dans scrollview etc. Ils corrigent les problèmes de performance dans l'exemple de code en dessinant presque tout dans la méthode -drawRect. Dans l'autre session, le problème de performance (sur une vue de table) semble être dû à trop de code dans la méthode -drawRect des cellules de la table.
Le premier n'est pas clair quand un rendu OffScreen est requirejs par le système, j'ai vu dans la video que certaines fonctions à quartz telles que: cornerRadious, shadowOffset, shadowColor l'exigent, mais existe-t-il une règle générale?
Deuxièmement, je ne sais pas si j'ai bien compris, mais il semble que lorsqu'il n'y a pas de rendu hors écran, l'ajout de calques ou de vues est la solution. J'espère que quelqu'un pourrait apporter de la lumière à ce sujet ..
Merci,
Andrea

Je ne pense pas qu'il y ait une règle écrite nulle part, mais j'espère que cela aidera:

D'abord, clarifions quelques définitions. Je pense que le rendu hors écran vs à l'écran n'est pas la préoccupation principale la plupart du time, car le rendu hors écran peut être aussi rapide que sur l'écran. Le principal problème est de savoir si le rendu est fait dans le matériel ou le logiciel.

Il y a aussi très peu de différence pratique entre l'utilisation de calques et de vues. Les vues ne sont qu'une mince enveloppe autour de CALayer et n'introduisent pas de pénalité de performance significative la plupart du time. Vous pouvez replace le type de couche utilisé par une vue à l'aide de la méthode + layerClass si vous souhaitez que la vue soit protégée par une CAShapeLayer ou une CATileLayer, etc.

Généralement, sur iOS, les effets de pixels et le dessin Quartz / Core Graphics ne sont pas accélérés par le matériel, et la plupart des autres choses le sont.

Les choses suivantes ne sont pas accélérées matériellement, ce qui signifie qu'elles doivent être effectuées dans un logiciel (hors écran):

  1. Tout ce qui est fait dans un drawRect. Si votre vue a un drawRect, même vide, le dessin n'est pas fait dans le matériel, et il y a une pénalité de performance.

  2. Tout calque dont la propriété shouldRasterize est définie sur YES.

  3. Toute couche avec un masque ou une ombre scope.

  4. Texte (n'importe quel type, y compris UILabels, CATextLayers, text de base, etc.).

  5. Tout dessin que vous faites vous-même (à l'écran ou hors écran) en utilisant un CGContext.

La plupart des autres choses sont accélérées par le matériel, elles sont donc beaucoup plus rapides. Cependant, cela peut ne pas vouloir dire ce que vous pensez qu'il fait.

Tous les types de dessin ci-dessus sont lents par rapport au dessin accéléré par le matériel, mais ils ne ralentissent pas forcément votre application car ils n'ont pas besoin d'être générés à chaque image. Par exemple, dessiner une ombre scope sur une vue est lent la première fois, mais une fois dessinée, elle est caching et redessinée uniquement si la vue change de taille ou de forme.

Il en va de même pour les vues ou les vues pixellisées avec un drawRect personnalisé: la vue n'est généralement pas redessinée à chaque image, elle est dessinée une fois puis caching, de sorte que la performance après la création de la vue n'est pas pire, sauf si les limites changent ou vous appelez setNeedsDisplay dessus.

Pour de bonnes performances, l'astuce consiste à éviter d'utiliser le dessin logiciel pour les vues qui changent à chaque image. Par exemple, si vous avez besoin d'une forme vectorielle animée, vous obtiendrez de meilleures performances avec CAShapeLayer ou OpenGL qu'avec drawRect et Core Graphics. Mais si vous dessinez une forme une fois et que vous n'avez pas besoin de la changer, cela ne changera pas grand-chose.

De même, ne placez pas d'ombre scope sur une vue animée car cela ralentira votre fréquence d'images. Mais une ombre sur une vue qui ne change pas d'image en image n'aura pas beaucoup d'impact négatif.

Une autre chose à surveiller est de ralentir le time d'installation de la vue. Par exemple, supposons que vous ayez une page de text avec des ombres scopes sur tout le text; cela prendra beaucoup de time pour dessiner d'abord puisque le text et les ombres doivent tous être rendus dans le logiciel, mais une fois dessinés, ce sera rapide. Vous devez donc configurer cette vue à l'avance lorsque votre application est chargée, et conserver une copy de celle-ci en memory afin que l'user n'ait pas à attendre l'affichage de la vue lors de sa première apparition à l'écran.

C'est probablement la raison de la contradiction apparente dans les videos de la WWDC. Pour les grandes vues complexes qui ne changent pas chaque image, les dessiner une fois dans le logiciel (après quoi elles sont mises en cache et n'ont pas besoin d'être redessinées) donneront de meilleures performances que si le matériel les recomposait à chaque image, même si ce sera plus lent de dessiner la première fois.

Mais pour les vues qui doivent être redessinées constamment, comme les cellules de tableau (les cellules sont recykeyes, elles doivent être redessinées chaque fois qu'une cellule défile hors de l'écran et est réutilisée lorsqu'elle revient de l'autre côté comme une ligne différente). ralentir beaucoup les choses.

Offscreen-rendu est l'un des sujets les less bien définis dans le rendu iOS, aujourd'hui. Lorsque les ingénieurs UIKit d'Apple se réfèrent au rendu hors écran, cela a une signification très spécifique et une tonne de blogs de développeurs iOS tiers se trompent.

Lorsque vous surchargez "drawRect:", vous dessinez via le processeur et crachez un bitmap. Le bitmap est empackageé et envoyé à un process distinct qui réside dans iOS, le server de rendu. Idéalement, le server de rendu affiche simplement datatables à l'écran.

Si vous sortingpotez les propriétés sur CALayer, comme si vous activiez les ombres scopes, le GPU effectuera un dessin supplémentaire. Ce travail supplémentaire est ce que les ingénieurs UIKit veulent dire quand ils disent "rendu hors écran". Ceci est toujours effectué avec du matériel.

Le problème avec le dessin hors écran n'est pas nécessairement le dessin. La passe hors écran nécessite un changement de context, car le GPU bascule sa destination de dessin. Pendant ce commutateur, le GPU est inactif.

Bien que je ne connaisse pas la list complète des propriétés qui triggersnt un passage hors écran, vous pouvez le diagnostiquer avec la bascule "Couleur de l'écran hors écran rendu" de l'instrument d'animation de base. Je suppose que toute propriété autre que l'alpha est effectuée via une passe hors écran.

Avec le matériel iOS, il était raisonnable de dire "tout faire dans drawRect". De nos jours, les GPU sont meilleurs, et UIKit a des fonctionnalités comme shouldRasterize. Aujourd'hui, c'est un acte d'équilibre entre le time passé à drawRect, le nombre de passes hors écran et la quantité de blending. Pour plus de détails, visionnez la session 419 de la WWDC 2014 intitulée «Advanced Graphics and Animation for iOS Apps».

Tout cela dit, il est bon de comprendre ce qui se passe dans les coulisses, et de le garder à l'arrière de la tête afin de ne rien faire de fou, mais vous devriez partir de la solution la plus simple. Ensuite, testez-le sur le matériel le plus lent que vous supportez. Si vous ne frappez pas 60FPS, utilisez des instruments pour mesurer les choses et le comprendre. Il y a quelques goulots d'étranglement possibles, et si vous n'utilisez pas de données pour diagnostiquer les choses, vous ne faites que deviner.

Rendu hors écran / Rendu sur le processeur

Les plus gros goulots d'étranglement pour les performances charts sont le rendu et le fondu hors écran: ils peuvent se produire pour chaque image de l'animation et provoquer un défilement saccadé.

Le rendu hors écran (rendu logiciel) se produit lorsqu'il est nécessaire de faire le dessin dans le logiciel (hors écran) avant de pouvoir le remettre au GPU. Le matériel ne gère pas le rendu de text et les compositions avancées avec masques et ombres.

Les éléments suivants vont triggersr le rendu hors écran:

  • Toute couche avec un masque ( layer.mask )

  • Tout calque avec layer.masksToBounds / view.clipsToBounds étant vrai

  • Toute couche avec layer.allowsGroupOpacity définie sur YES et layer.opacity est inférieure à 1.0
    Quand une vue (ou un calque) nécessite-t-elle un rendu hors écran?

  • Tout calque avec une ombre scope ( layer.shadow* ).
    Conseils pour résoudre ce problème: https://markpospesel.wordpress.com/tag/performance/

  • Tout calque avec layer.shouldRasterize étant vrai

  • Toute couche avec layer.cornerRadius , layer.edgeAntialiasingMask , layer.allowsEdgeAntialiasing

  • Tout calque avec layer.borderWith et layer.borderColor ?
    Référence manquante / preuve

  • Texte (tout type, y compris UILabel , CATextLayer , Core Text , etc).

  • La plupart des dessins que vous faites avec CGContext dans drawRect: Même une implémentation vide sera rendue hors écran.


Ce post couvre le blending et d'autres choses qui affectent la performance: Qu'est – ce qui triggers le rendu hors écran, le blending et layoutSubviews dans iOS?