2009-04-30 8 views
7

J'ai créé un contrôle WPF (héritant de FrameworkElement) qui affiche un graphique en mosaïque pouvant être mis en panoramique. Chaque mosaïque est de 256x256 pixels à 24bpp. J'ai remplacé OnRender. Là, je charge toutes les nouvelles tuiles (comme BitmapFrame), puis dessine toutes les tuiles visibles en utilisant drawingContext.DrawImage.Performances de rendu WPF avec BitmapSource

Maintenant, chaque fois qu'il y a plus d'une poignée de nouvelles tuiles par cycle de rendu, le framerate tombe de 60fps à zéro pendant environ une seconde. Ceci n'est pas dû au chargement des images (qui prend environ de l'ordre de la milliseconde), ni à DrawImage (qui ne prend pas de temps car il ne fait que remplir une structure de données de rendu intermédiaire). Je suppose que le thread de rendu se bloque à chaque fois qu'il reçoit un grand nombre (~ 20) de nouvelles instances de BitmapSource (c'est-à-dire celles qu'il n'a pas déjà mises en cache). Soit il passe beaucoup de temps à les convertir en un format compatible DirectX interne, soit il peut s'agir d'un problème de mise en cache. Il ne peut pas manquer de RAM vidéo; Perforateur montre des pics à moins de 60 Mo, j'ai 256 Mo. En outre, Perforator indique que toutes les cibles de rendu sont accélérées par le matériel, ce qui ne peut pas être le cas non plus.

Toute idée serait appréciée!

Merci à l'avance

Daniel

@RandomEngy:
BitmapScalingMode.LowQuality réduit le problème un peu, mais ne pas se débarrasser. Je charge déjà les dalles à la résolution voulue. Et ce ne peut pas être le pilote graphique, qui est à jour (Nvidia).
Je suis un peu surpris d'apprendre que la mise à l'échelle prend autant de temps. La façon dont je l'ai compris, une image bitmap (indépendamment de sa taille) est juste chargée comme une texture Direct3D, puis mise à l'échelle matérielle. En fait, une fois que le bitmap a été rendu pour la première fois, je peux changer sa rotation et son échelle sans aucun gel supplémentaire.

Répondre

3

Ce n'est pas seulement avec un grand nombre d'images. Une seule grande image suffit pour maintenir le rendu jusqu'à ce qu'il soit chargé, ce qui peut être assez visible lorsque les dimensions de votre image commencent à s'élever par milliers. Je suis d'accord avec vous sur le fait que c'est probablement le thread de rendu: j'ai fait un test et le thread de l'interface envoyait encore joyeusement des messages alors que le délai de rendu était en train d'afficher un BitmapImage entièrement pré-mis en cache.

Il doit faire une sorte de conversion ou de préparation sur l'image, comme vous spéculiez. J'ai essayé d'atténuer cela dans mon application en "rendant" mais en cachant l'image, puis en la révélant quand j'ai besoin de la montrer. Cependant, ce n'est pas idéal car le rendu se fige de toute façon.

(Edit)

Certains suivi: Après une discussion sur l'alias MS WPF J'ai trouvé ce qui était à l'origine des retards. Sur mon ordinateur Server 2008, il s'agissait d'une combinaison d'anciens pilotes vidéo ne prenant pas en charge le nouveau modèle de pilote WDDM et d'un délai de redimensionnement de l'image.

Si la taille de l'image source est différente de la taille de l'affichage, le fil de rendu sera retardé avant que l'image ne s'affiche. Par défaut, une image est définie sur la qualité la plus élevée, mais vous pouvez modifier les options de mise à l'échelle pour le rendu en appelant RenderOptions.SetBitmapScalingMode(uiImage, BitmapScalingMode.LowQuality);. Une fois que je l'ai fait, le gel mystérieux avant d'afficher une image est parti. Une alternative, si vous n'aimez pas la baisse de qualité dans la mise à l'échelle, est de charger le BitmapImage avec DecodePixelWidth/Height égal à la taille à laquelle il sera affiché. Ensuite, si vous chargez BitmapImage sur un thread d'arrière-plan, vous ne devriez pas avoir de délai pour l'afficher.

0

Essayez également ces;

/* ivis is declared in XAML <Image x:Name="iVis" UseLayoutRounding="True" SnapsToDevicePixels="True" /> */ 

iVis.Stretch = Stretch.None; 
RenderOptions.SetBitmapScalingMode(iVis, BitmapScalingMode.NearestNeighbor); 
RenderOptions.SetEdgeMode(iVis, EdgeMode.Aliased); 
VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor; 
iVis.Source = **** your bitmap source **** 

j'avais des problèmes avec des performances lors de l'utilisation d'une énorme quantité de « A » couleur de canal de, attendre jusqu'à ce que l'image avait rendu à l'échelle, il a travaillé beaucoup mieux pour moi.

En outre, comme vous avez dit votre aide d'un graphique en mosaïque?

Vous habituellement utiliser un TileBrush simplement défini comme le pinceau sur votre FrameworkElement. Si vous les animez ou en ajoutez de nouveaux dynamiquement, vous pouvez générer vos pinceaux puis les appliquer à votre objet comme vous le faites manuellement, assurez-vous de les geler si vous le pouvez. En outre, VisualBitmapScalingMode est une propriété de n'importe quel Visual.

Questions connexes