2009-11-06 6 views
2

Est-ce que quelqu'un connaît des livres/sites Web fiables (et, espérons-le, extensifs) qui traitent des performances de GDI + (au-delà de l'évidence)? Par exemple, j'ai récemment rencontré this excellent experiment. J'ai aussi récemment remarqué que Graphics.FillPath() est beaucoup plus rapide que Graphics.DrawPath(). J'aimerais savoir quels autres éléments vitaux d'information me manquent.Astuces de performance GDI +

bonne volonté, David

Répondre

17

Hmmm. Il n'y a aucun avantage à savoir que FillPath est plus rapide que DrawPath si vous avez besoin de dessiner le contour du chemin!

La meilleure façon d'optimiser GDI + est exactement la même que pour n'importe quel autre code: Tout d'abord, ne l'optimisez pas. Au lieu de cela:

  • Commencez par l'écrire pour que cela fonctionne simplement, puis décidez si c'est réellement trop lent.
  • Ensuite, examinez votre « algorithme »:
    • Simplifiez ce que vous dessinez (réduire le nombre de choses que vous dessinez) et il va aller plus vite (et dans la plupart des cas sera mieux d'avoir réduit l'encombrement).
    • Dessinez-vous l'intégralité de votre écran à chaque fois ou utilisez-vous le rectangle de découpe pour éviter de dessiner des parties de l'image qui n'ont pas besoin d'être mises à jour?
    • Examinez comment vous dessinez des choses. Créez-vous et détruisez-vous des ressources (par exemple des pinceaux et des stylos) pour chaque redessin? Cachez-les dans une variable membre. Dessinez-vous le même pixel plusieurs fois? (par exemple dessiner l'arrière-plan puis dessiner un bitmap sur le dessus puis dessiner un rectangle par-dessus cela - peut-être vous pouvez éviter certains de ces redraws). Dessinez-vous une courbe en utilisant 100 segments de polygone quand il semble assez bon avec seulement 10 segments? Lorsque la fenêtre défile, obtenez-vous le système d'exploitation pour déplacer l'image existante de sorte que vous avez seulement besoin de redessiner la bande nouvellement exposée, ou perdez-vous du temps à redessiner la fenêtre entière?
    • Utilisez-vous des transformations ou faites-vous de longs calculs de positionnement dans votre code?
    • Vérifiez toutes les boucles et assurez-vous d'en extraire le plus de code possible - précalculez les valeurs que vous utilisez dans la boucle, etc. Assurez-vous que vos boucles parcourent vos données dans une direction amicale cpu-cache .
    • Y a-t-il quelque chose dans vos données que vous traitez pendant le redessin? Peut-être que certains de ces éléments peuvent être précalculés ou organisés dans une forme plus optimale. par exemple. Un autre type de liste serait-il plus rapide pour énumérer vos données? Traitez-vous 1000 éléments de données pour trouver les 10 que vous devez dessiner?
    • Pouvez-vous obtenir le même look avec une approche différente? par exemple. Vous pouvez dessiner un échiquier en dessinant 64 carrés alternativement en noir et blanc. Il peut être plus rapide de dessiner 32 carrés noirs puis 32 blancs afin d'éviter les changements d'état entre les rects. Mais vous pouvez réellement le dessiner en utilisant un fond blanc clair, 4 rectangles noirs et 4 rectangles XOR (8 retours au lieu de 64 => algorithme beaucoup plus rapide).
  • Y a-t-il des parties de l'image qui ne changent pas souvent? Essayez de les mettre en cache dans un bitmap hors écran afin de minimiser la quantité à reconstruire pour chaque redessin. Souvenez-vous que vous pouvez toujours afficher les bitmap hors écran, puis superposer des primitives graphiques, de sorte que vous puissiez trouver beaucoup plus de zones d'image "statiques" que vous ne le pensez.
  • Êtes-vous en train de rendre des images bitmap?Essayez de les convertir au format de pixel de l'écran et cachez-les dans ce format "natif" plutôt que de les convertir en GDI + à chaque fois qu'ils sont dessinés.
  • Baissez les paramètres de qualité si vous êtes satisfait du compromis de qualité inférieure pour le rendu plus rapide

Une fois que vous avez fait toutes ces choses que vous pouvez commencer à chercher des livres sur l'optimisation du rendu. Si c'est encore trop lent, bien sûr. Exécutez un profileur pour savoir quelles parties du rendu sont les plus lentes. Essayez les différentes façons de rendre les choses (par exemple, il est probable que Graphics.Clear() sera beaucoup plus rapide que de remplir l'arrière-plan avec FillRectangle()), ou des ordres de rendu différents (dessinez toutes les choses d'une couleur en premier, dans le cas où les changements d'état vous coûteraient du temps - les opérations de traitement par lots sont souvent très importantes avec les cartes graphiques modernes.Un seul appel qui dessine plusieurs polygones est généralement plus rapide que de faire plusieurs appels polygonaux. tous vos polys dans un tampon de rendu différé et ensuite les commettre tous à la fin de votre passe de rendu?)

Après cela, vous devrez peut-être regarder en utilisant GDI ou DirectX pour se rapprocher du matériel.

+0

Salut Jason, merci pour la réponse complète. Permettez-moi de répondre aux points un à un, peut-être que cela clarifiera un peu où je suis coincé: –

+0

"Simplifiez ce que vous dessinez". Je suis, surtout. Mon GUI est en fait un ZUI, donc je simplifie déjà les choses lorsque je fais un zoom arrière. Cependant, je ne suis pas en train de prendre la décision de tirer ou non des choses en fonction du temps qu'il a fallu à la dernière image pour la dessiner. –

+0

"Dessinez-vous l'intégralité de votre écran à chaque fois". Non, je ne dessine pas d'objets qui ne sont pas dans la zone visible. –

10

Cela peut ne pas être la réponse que vous cherchez, mais ne pas utiliser GDI + du tout. J'ai dû récemment réécrire la pile de rendu d'une application 2D-CAM, et l'exigence la plus importante était d'obtenir rapidement de bonnes lignes anti-aliasées (l'anti-aliasing nous a incités à réécrire le rendu GDI existant).

Voici quelques résultats obtenus avec un rendu de 200 articles (chaque article est lui-même quelques lignes et de petits marqueurs de formes pleines). Ce sont les taux de trame (sur Windows 7), donc plus élevé est mieux:

200 articles: GDI = 51, GDI + = 20, D2D = 59, WPF = 33, GL = 59.

(D2D est Direct2D, GL est OpenGL). Déjà vous pouvez voir que GDI + est à la traîne. WPF est peut-être handicapé en tant qu'API en mode retenu, mais OpenGL est également double-bufferisé et a l'air tout aussi fluide.

à 1000 éléments, la différence est plus marquée:

GDI = 23, GDI + = 5, D2D = 17, WPF = 2, GL = 40.

C'est vrai, WPF est tombé à 2 FPS maintenant, et GDI + rampe à 5 FPS. Alors, pensez à D2D, ou tout simplement revenir à OpenGL. C'est ce que nous utilisons maintenant et 3 mois après la réécriture, je pense que nous avons fait le bon choix. Le modèle de programmation lui-même est beaucoup plus propre que D2D semble l'être. Notez que le rendu WPF que nous utilisons est hautement optimisé; pas de rappels, pas d'événements, pas de liaison. Nous obtenons juste un DrawingContext et dessinons tout sur chaque image en utilisant les primitives de plus bas niveau, donc il n'y a pas de surcharge d'événement.

Si vous êtes intéressé, faites le moi savoir, et je peux vous envoyer les suites de test que j'ai utilisées pour que vous puissiez jouer avec ça.

(Une des raisons pour lesquelles je ne pense pas à GDI + est qu'il est peu probable qu'il soit accéléré matériellement).

+0

Tarydon, ce n'est plus une option que j'ai peur. J'ai travaillé sur cette interface graphique pendant plus de 2 ans et une bonne partie de ce temps a passé à écrire du code GDI +. C'est assez rapide 95% du temps, bien que j'ai vu des cas où le framerate tombe en dessous de 10 fps. J'ai beaucoup profilé le code ces derniers temps et j'ai trouvé des goulots d'étranglement intéressants (c'est-à-dire inattendus), mais j'espérais que ce travail avait déjà été fait par quelqu'un d'autre. Encore, +1 pour essayer de m'aider. Merci. –

+1

Je suis confus à propos de Win7, je pensais que GDI est 100% logiciel sur cette plate-forme. Mais quand je vois que par vos chiffres même D2D est plus lent que GDI, je me demande quelle est la vérité au-delà des messages de marquage MSDN. Je n'utilise actuellement GDI que pour le chargement/enregistrement de l'image. – Lothar

+1

@Lothar évidemment, il n'utilisait pas correctement D2D. – johnathon