2009-04-30 6 views
7

Ich habe ein WPF-Steuerelement erstellt (erbt von FrameworkElement), das eine gekachelte Grafik anzeigt, die geschwenkt werden kann. Jede Kachel ist 256 x 256 Pixel bei 24 bpp. Ich habe OnRender überschrieben. Dort lade ich neue Kacheln (als BitmapFrame) und zeichne dann alle sichtbaren Kacheln mit drawingContext.DrawImage.WPF-Renderleistung mit BitmapSource

Jetzt, wenn es mehr als eine Handvoll neue Kacheln pro Renderzyklus gibt, fällt die Framerate für etwa eine Sekunde von 60 fps auf Null. Dies wird nicht durch das Laden der Bilder verursacht (was in der Größenordnung von Millisekunden liegt), noch durch DrawImage (das braucht überhaupt keine Zeit, da es nur einige Zwischen-Render-Datenstrukturen füllt).

Meine Vermutung ist, dass der Render-Thread selbst erstickt, wenn er eine große Anzahl (~ 20) neuer BitmapSource-Instanzen erhält (also solche, die er nicht bereits zwischengespeichert hatte). Entweder wird viel Zeit für die Konvertierung in ein internes DirectX-kompatibles Format benötigt oder es wird ein Caching-Problem verursacht. Es kann nicht aus dem Video-RAM gehen; Perforator zeigt Peaks bei unter 60 MB, ich habe 256 MB. Perforator sagt außerdem, dass alle Renderziele hardwarebeschleunigt sind, also kann es auch nicht sein.

Alle Einblicke würden geschätzt werden!

Vielen Dank im Voraus

Daniel

@RandomEngy:
BitmapScalingMode.LowQuality das Problem ein wenig verringert, aber nicht von ihr bekam befreien. Ich lade bereits Kacheln mit der gewünschten Auflösung ein. Und es kann nicht der Grafiktreiber sein, der aktuell ist (Nvidia).
Ich bin ein wenig überrascht zu erfahren, dass die Skalierung so lange dauert. So wie ich es verstanden habe, wird eine Bitmap (unabhängig von ihrer Größe) einfach als Direct3D-Textur geladen und dann hardware-skaliert. Sobald die Bitmap zum ersten Mal gerendert wurde, kann ich ihre Rotation und Skalierung ohne weitere Einfrierungen ändern.

Antwort

3

Es ist nicht nur mit einer großen Anzahl von Bildern. Nur ein großes Bild reicht aus, um das Rendern zu ermöglichen, bis es geladen wurde. Dies kann sehr deutlich sein, wenn Ihre Bildmaße zu Tausenden auftauchen.

Ich stimme Ihnen zu, dass es wahrscheinlich der Render-Thread ist: Ich habe einen Test gemacht und der UI-Thread war immer noch glücklich Nachrichten zu versenden, während diese Render-Verzögerung von einem vollständig im Cache gespeicherten BitmapImage angezeigt wurde.

Es muss eine Art von Umwandlung oder Vorbereitung auf das Bild tun, wie Sie spekuliert haben. Ich habe versucht, dies in meiner App durch "Rendering" zu mildern, aber das Bild zu verstecken und es dann zu enthüllen, wenn ich es zeigen muss. Dies ist jedoch weniger als ideal, da das Rendering-Freeze sowieso auftritt.

(Edit)

Einige Followup: Nach einer Diskussion über die MS WPF alias fand ich, was die Verzögerungen verursacht wurde. Auf meinem Computer mit Server 2008 war es eine Kombination aus alten Grafiktreibern, die das neue WDDM-Treibermodell nicht unterstützen, und einer Verzögerung bei der Größenänderung des Bilds.

Wenn sich die Quellbildgröße von der Anzeigegröße unterscheidet, wird der Render-Thread verzögert, bevor das Bild angezeigt wird. Standardmäßig wird ein Bild auf die höchste Qualität eingestellt, aber Sie können die Skalierungsoptionen für das Rendern ändern, indem Sie RenderOptions.SetBitmapScalingMode(uiImage, BitmapScalingMode.LowQuality); aufrufen. Sobald ich das getan hatte, verschwand der mysteriöse Freeze, bevor ein Bild angezeigt wurde. Eine Alternative, wenn Sie die Qualitätseinbuße bei der Skalierung nicht mögen, ist das Laden der BitmapImage mit DecodePixelWidth/Height gleich der Größe, unter der sie angezeigt wird. Wenn Sie BitmapImage dann in einem Hintergrundthread laden, sollten Sie keine Verzögerung bei der Anzeige haben.

0

Versuchen Sie auch diese;

/* 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 **** 

Ich habe einige Probleme mit Leistung, wenn eine große Menge an „A“ Kanalfarbe verwendet wird, zu warten, bis, nachdem das Bild gemacht hatte es für mich viel besser zu skalieren gearbeitet.

Auch, wie Sie sagten, verwenden Sie eine gekachelte Grafik?

Sie würden normalerweise TileBrush verwenden, um einfach den Pinsel auf Ihrem FrameworkElement zu setzen. Wenn Sie sie animieren oder dynamisch neue hinzufügen, können Sie Ihre Pinsel generieren und sie dann auf Ihr Objekt anwenden, wenn Sie auch manuell arbeiten. Stellen Sie sicher, dass Sie sie fixieren, wenn Sie können. Außerdem ist VisualBitmapScalingMode eine Eigenschaft von Visual.