Bitmap-Performance-Optimierung-Muster
Fand ich mehrere Muster, die für die Optimierung der Umgang mit Bitmaps in WPF. Ich nicht, jedoch verstehen, wenn die Verwendung der einzelnen Muster. So ich denke das ist ein Allgemeines problem, ich habe zusammengefasst, was ich verstehe und was ich denke, und bitte um Eure Hilfe. Wenn Sie hinzufügen Muster, erklären wie Sie sich unterscheiden, zu erklären, wenn Sie verwenden die CPU oder die GPU und lehren jede und , wie Sie zu kombinieren, wäre es eine enorme Hilfe!
Kontext – die Bilder "Grid" - Szenario:
Meine Anwendung zeigt viele bitmap-Bilder. Die Bilder werden auf dem Bildschirm angezeigt, die in einem Zeilen-und-Spalten-grid-like-Organisation (nicht unbedingt die Grid UniformGrid oder Klassen, denke Window Media Player die Album-Ansicht). Bilder würden den Wechsel zwischen verschiedenen grid-Zellen. Einige Bilder an beliebigen Zellen können ersetzt werden durch andere. Die Bilder sollten anklickbar, sollte ein Kontext-Menü, wählbar sein müssen, ziehen Sie-in der Lage usw. In anderen Worten, "kombinieren Sie die kleinen Kerle in eine große bitmap" ist nicht zutreffend, zumindest nicht naiv.
Muster 0: Der Hack
Kombinieren die kleinen Kerle in eine bitmap (wie? Zeichnung Kontext?), und verwenden Sie diese als hintergrund. Überlagern diese mit Bildern mit leerem Inhalt behandelt die trifft, Kontext-Menüs, events, usw..
Der Vorteil ist, dass wir nur das sprechen über zwei bitmaps hier: Die gerade angezeigt wird, und die, sollten Sie es ersetzen. Sollte dies wirklich schnell. Jedoch, meiner langjährigen Erfahrung heben die rote fahne der Gefahr. Ihre Kommentare?
Muster 1: Reduzieren Der Bildgröße
Dies ist ein no-brainer, wenn Sie im Voraus wissen, die Größe des Bildes, um die Größe zu, und wenn Sie bereit sind zu verlieren details (Farbe), Leistung:
- Reduzieren Sie die bitmap-Größe mit BitmapImage.DecodePixelWidth
- Reduzieren Sie die Farbe, die Informationen mit FormatConvertedBitmap.DestinationFormat
- Gesetzt, die Kontrolle der Skalierung Einstellung Bild.Dehnen und Strecken.Keine
- Legen Sie die SetBitmapScalingMode für das Bild LowQuality.
- Einfrieren der Kerl
Siehe code hier.
Muster 2: Hintergrund-pre-fetch
Dieses Muster ist anwendbar, wenn Sie denken, Sie können nutzen die Anwender den Blick auf die Bilder auf dem Bildschirm, und bereitet vor die nächsten Bilder anzuzeigen. Die Nachteile für Ihr Projekt, zusätzlich zu den Speicher-overhead, ist, dass es zu unterstützen .Net Framework 4 als Ziel und nicht nur das client-Profil, so könnte es eine Gebühr für die installation auf dem client ist. Sie selbst haben leiden, die die asynchrone Programmierung Schmerzen.
In diesem Muster erstellen Sie genau die erforderliche Anzahl von Bild-Steuerelemente. Wenn bitmaps werden müssen, Hinzugefügt, verschoben oder gelöscht werden Sie nur ändern Sie die Bild-Steuerelemente' BitmapSource(s). Ein BackgroundWorker Aufgabe ist verantwortlich für die pre-fetching die BitmapSource(s) (evtl. mit der "Verringern Sie die Bildgröße" - Muster oben) und einfügen in MemoryCache.
Damit dies funktioniert, müssen Sie die BitmapImage die CacheOption OnLoad, so dass die Arbeit ist off-loaded, um die hintergrund-Arbeiter.
Muster 3: Zeichnung Rahmen
Dieser schlug Sheldon Ziao vom Microsoft-Support auf der MSDN-WPF-forum hier. Siehe Seite 494 Kapitel 15 "2D-Grafiken", die in Adam Nathan ' s WPF 4 Unleashed für eine Beschreibung der DrawingContext. Ich kann nicht sagen, dass ich es verstehe. Nach der Antwort hier, würde ich davon ausgehen, dies würde die Verbesserung der Handhabung von Geometrie-Zeichnungen, bitmaps nicht. Nächsten, ich glaube nicht, dass dies unterstützt die Fokussierung und Veranstaltungen Anforderungen für die Bilder (meine schlecht für nicht zu erklären, den Anforderungen besser im forum) Darüber hinaus, ich bin besorgt über das Buch eine Zusammenfassung Satz: “Beachten Sie, dass die Verwendung von DrawingContext ändert nichts an der Tatsache, dass Sie in Betrieb sind, innerhalb einer retained-mode-system. Die angegebene Zeichnung nicht sofort geschehen; die Befehle gespeichert werden, die von WPF, bis Sie gebraucht werden." Dies bedeutet, dass, wenn unser selbst-handler wieder können wir nicht nehmen Vorteil der Parallelität wie in "Hintergrund" pre-fetch".
Muster 4: Schreibbare Bitmaps
In der MSDN-Dokumentation hier beschreibt es als ein dual-Puffer-system: Ihre UI-thread aktualisiert den Puffer; der WPF-render-thread bewegt sich diese video-Speicher.
Des bestimmungsgemäßen Gebrauchs (siehe hier) wird für bitmaps, die viele änderungen wie in einem video-Film, wie auch display. Ich bin mir nicht sicher, aber möglich könnte dies werden gehackt und mit dem Hintergrund kombiniert Pre-fetch-pattern und in der grid-Szenario.
Muster 5: Zwischengespeicherte Bitmap
Nicht viel info auf der MSDN-Website (hier). Auf der WPF-forum-Archiv (hier) es erklärte, dass “Der BitmapCache-API wurde entwickelt, um cache-Inhalte (beim Rendern in hardware) im video-Speicher, was bedeutet, es bleibt resident auf deine GPU. Dies erspart Ihnen die Kosten für die re-Rendern, dass der Inhalt bei der Zeichnung auf dem Bildschirm." Dies scheint wie eine gute Idee. Ich bin mir nicht sicher, aber, was sind die Fallstricke und wie man es benutzt.
Muster 6: RenderTargetBitmap
Das RenderTargetBitmap wandelt eine Visuelle, um eine bitmap. Ich bin mir nicht sicher, ob es relevant ist, hier. Sehen hier.
Bearbeiten: Über Paul Hoenecke Frage: ich habe geschrieben, dass "Meine Bewerbung hat zu viele bitmap-iages". Ich konnte nicht erwähnt, dass ich die Anzeige über 800 Bilder gleichzeitig.
Kann man Lesen über die performance-Probleme auf meine Fragen WPF-Bitmap-Leistung und Wie kann ich die Anzeige der Bilder auf WPF mehr "bissig"?
Habe ich geändert, die Beschreibung der Muster 1 zu markieren, das Konzept, dass die Bild-Steuerelemente werden nicht erstellt oder gelöscht werden (es sei denn, wir wollen, zeigt ein größeres oder kleineres raster). Nur Ihre Quellen festgelegt sind, auf anderen, neuen oder null BitmapSources.
Bearbeiten: Diese Frage gepostet, auf die WPF-support-forum, mit einigen Antworten von Frau Personal.
- Wie viele Bilder werden Sie antizipieren? Habe ich eine app, die zeigt, ein Netz von tausenden von Bildern vor. Wir verwendet eine virtuelle-Modus listbox, wie der Benutzer scrollt, die Bilder werden im hintergrund geladen, eingefroren und auf die Quelle des Bildes. Klar, Sie haben eine Menge Gedanken in diese... aber, vielleicht wissen Sie mehr über genau das, was Sie erreichen wollen, besser werden würde. Zum Beispiel, welche Probleme Sie hatten, dass machen die Optimierung so wichtig?
- Hallo Paul, danke für deine Antwort. Die virtuelle Sammlungen helfen, wenn Sie anzeigen möchten, die eine kleine Anzahl von Elementen aus einer großen Sammlung. Hier möchte ich die Anzeige über 1K Elemente gleichzeitig. Außerdem, ich bin mir nicht sicher, es gibt eine Virtualisierung grid. Schließlich, das Muster 1 wird im wesentlichen durch die Virtualisierung - werde ich hinzufügen, en Bearbeiten.
- Avi, deine Frage scheint unangemessen für das beschriebene problem. Sie können verbessern wollen, Kompression Verhältnis für einige Grund, aber dann müssen Sie genau wissen, welche Art der Bilder, die Sie anzeigen. Oder, auf der anderen Seite, möchten Sie vielleicht geben Sie dem Benutzer einen Eindruck von allen die Bilder zur Verfügung, dann könnten Sie definieren, einige sets und miniaturen oder ähnliches. Aber beide Dinge haben nicht zwingend miteinander zu tun. Vielleicht möchten Sie so etwas wie eine ähnlichkeit Metrik zu definieren, die Sätze ähneln sich die Bilder?
- Sorry, habe ich nicht verstanden, Ihre Kommentare. Ich möchte für die Anzeige einer Menge von bitmaps auf dem Bildschirm, und ich möchte die Anzeige in einem raster, nicht an beliebige Bildschirm-Positionen. Und es ist nicht schnell genug, so ich will, dass es schneller angezeigt werden.
- Gibt es einen Grund, nicht zur Verwendung bestehender algorithmen, z.B. ein JPEG mit niedriger Qualitätseinstellung? Es hängt davon ab, die Bilder, die Sie komprimieren möchten, natürlich, aber wenn Sie Bilder wie Diagramme, könnten Sie versuchen, mit PNG und dort mit einem der nummerierten algorithmen. Es macht keinen Sinn zu diskutieren, wie man shuffle mit den binären Daten im Speicher, wenn Sie nicht wissen, was Sie tun möchten. Wahrscheinlich server-caching ist dein kleinste problem, da der Flaschenhals sein wird, auf der client-Seite oder in der übertragung.
- Ich glaube, ich undertand, wo das Missverständnis liegt. Ich spreche nicht über einen web-server senario. Ich spreche von WPF. Es gibt keine übertragung von Bildern, Sie sind alle auf dem lokalen computer. Und die Anzeige ist langsam. Bitte Lesen Sie nochmals die interoduction und der Kontext, in Abschnitten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich bin nicht in der Lage zu finden, eine spezielle Frage in deinem post, andere als die Fragen für die Kommentare auf die Ansätze unten. Ich will nicht behaupten, alles zu wissen, aber ich werde Ihnen sagen, was ich weiß, nachdem er für eine Weile die Entwicklung von high-performance user Interfaces mit WPF und Silverlight.
Ich würde das vermeiden, wenn möglich. Es klingt wie Sie anzeigen möchten, zu einem großen wrap-panel aus tausenden von kleinen Bildern. Jedes Bild ist daher ein thumbnail (so kann man die Anzeige 1000 von großen Bildern auf einmal). Als Ergebnis, würde ich befürworten-caching/Bildgröße über die Kombination.
Wenn Sie die Anzeige von 1000 Bildern auf dem Bildschirm auf einmal, betrachten Sie den Bildschirm real-estate. Die Durchschnittliche monitor ist 1280 x 1024 Pixel, oder einfach nur über 1,3 MPixel. 1000 Bilder vermuten Sie eine maximale Größe von 1300 Pixel pro Bild, oder 36*36. Können sagen, Ihre Bilder sind 32*32 in der Größe. Sollten Sie auf jeden Fall sein, erstellen Sie eine Miniaturansicht des Bildes Größe zu Rendern auf dem Bildschirm, dann auf klicken (oder andere Aktion) zeigen Sie das Bild in voller Größe.
Auch prüfen, nicht nur die render-Aufwand zum ändern der Größe eines großen Bildes, aber der Versand ein großes Bild an der GPU zu ändern. Diese Daten benötigt Bandbreite zu senden. Ein großes Bild kann einige Megabyte in der Erwägung, dass ein thumbnail der Größe 32*32 könnte ein paar Kilobyte.
Wenn Sie erfordern dynamische Größenanpassung, gut, aber Sie brauchen, zu Experimentieren mit dem erstellen von mehreren Miniaturansichten oder generieren Sie on the fly.
Dies ist eine Technik, die ich habe nicht davon gehört, aber es scheint plausibel. Was ist der overhead in Ihrer Anwendung? ist es die Aktualisierung des Bildes.Source-Eigenschaft oder erstellen Sie ein neues Bild, parkettierung, Durchführung von Layout und senden der Informationen an das Rendern auf die GPU?
Alle der oben genannten auftreten, an der CPU, außer für das endgültige Rendern. Durch die Reduzierung der overhead auf der CPU-Seite und Aktualisierung der Quelle könnten Sie etwas sein. Kombinieren Sie dies mit WriteableBitmap-Objekt als Quelle und man könnte weiter gewinnen einer performance-Verbesserung (siehe unten).
Ok, all das erlaubt Ihnen, eine Warteschlange beibehalten-Modus zeichnen die Anrufe über eine "OnPaint" - Stil-syntax, die nichts, wie die alten GDI-OnPaint. In meiner Erfahrung OnRender nicht die Leistung zu verbessern, aber es erlaubt für feinkörnige Flexibilität über das, was gezeichnet wird und Wann. OnRender liefert Ihnen ein Kontext, der eine Methode DrawImage-Funktion, so dass eine BitmapSource gezogen werden, um die rendering-pipeline, ohne die Notwendigkeit für ein Image-Steuerelement. Das ist gut, wie es entfernt einige overhead, jedoch stellt ähnliche Probleme, wie gesehen, in Pattern0 (verlieren Sie layout und zur Berechnung der position aller Ihrer Bilder). Wenn Sie dies tun, Sie könnte genauso gut invoke-Muster 0, die ich von denen abgeraten wird.
WriteableBitmaps sind ein wenig benutzt und außerordentlich leistungsfähiges subsystem innerhalb von WPF. Ich benutze Sie, um große Wirkung zu schaffen, eine charting-Komponente in der Lage rendering großer Mengen von Daten in Echtzeit. Ich würde vorschlagen, Check-out die WriteableBitmapEx codeplex-Projekt Offenlegung habe ich dazu beigetragen haben, diese einmal und sehen, wenn Sie können kombinieren Sie es mit anderen mustern. Speziell die Blit-Funktion, die lassen würde Sie schreiben eine zwischengespeicherte bitmap in eine bitmap-Quelle auf ein Bild.
Beispielsweise eine gute Technik sein könnte-Muster 1 + 2 + 4.
Könnten Sie haben ein raster von N-Bild-Steuerelemente auf dem Bildschirm an festgelegten Orten in einem grid-Steuerelement. Jede dieser statisch ist und nicht gescrollt außer Sicht, so gibt es keine erstellen/löschen geht. Jetzt, am Anfang dieser, die Größe Ihrer Bild-und Schreibzugriff auf ein WriteableBitmap-Objekt, das gesetzt ist als die Source-Eigenschaft auf jedem Bild. Blättern Sie erhalten den nächsten/vorherigen Thumbnail und Aktualisierung der Quellen mit WriteableBitmapEx.Blit -. Pow! virtualisierte, Cache, multi-threaded-imaging Güte.
Dies ist ein Versuch von microsoft zu tun 1+2+4 wie ich oben besprochen. Was es versucht zu tun, ist nach layout (CPU-Seite), tessellation (CPU-Seite), senden retained mode render-Anweisungen, um die GPU (CPU-Seite) und rendering (GPU-Seite) speichert es ein raster-Bild der gerenderten element, welches wieder verwendet werden auf dem nächsten rendering-pass. Ja eine wenig bekannte Tatsache über WPF ist die wunderbare GPU-powered engine ist furchtbar langsam, wie es die meisten seiner Arbeit auf die CPU 😛
Ich würde Experimentieren mit den BitmapCache und sehen, wie er ausführt. Gibt es Einschränkungen, und Sie sind, wenn Sie aktualisieren Sie Ihre UIElement es hat wieder den cache für statische Elemente ausgeführt werden wird, weit besser als die dynamische. Auch ich habe nicht gesehen, eine deutliche Verbesserung in der Leistung aus der Nutzung dieser in der Erwägung, dass WriteableBitmap-Stil-Techniken geben kann, um eine Größenordnung verbessern.
Diese Letzte Technik, die können machen Sie ein UIElement, um eine bitmap - Sie wissen das - aber was ist interessant ist, dies kann eine schlechte mans thumbnail-generator (oder die Größe). Zum Beispiel, ein Bild mit BitmapSource von Ihrem Bild in voller Größe. Jetzt legen Sie die Größe des Steuerelements Bild auf 32*32 und Rendern in Bitmaps. Voila! Sie haben Ihre BitmapSource-Miniaturansicht zur Verwendung in Verbindung mit einigen swapping (Muster 2) und/oder schreibbar sind bitmaps.
Ok, schließlich, wollte nur sagen, dass die Anforderung, die Sie haben, drücken WPF an seine Grenzen, aber es gibt Möglichkeiten, um es zu erfüllen. Wie ich schon sagte, ich habe build-Systemen gerendert Tausende oder Millionen von Elementen auf dem Bildschirm auf einmal, indem Sie mit der wunderbaren workaround, das WriteableBitmap-Objekt. Geht man die standard-WPF-route wird dazu führen, dass Leistung der Hölle, so dass Sie wird zu tun haben, etwas exotisches, diese zu lösen.
Wie gesagt meine Empfehlung ist 1+2+4. Sie müssen die Größe einer Miniaturansicht, habe ich keine Zweifel. Die Idee mit einem statischen raster von Bild-Steuerelemente und das aktualisieren der Quellen ist sehr gut. Die Idee, mit WriteableBitmap (speziell WriteableBitmapEx blit-Funktion) für das aktualisieren der Quellen ist auch eine Erkundung Wert.
Glück!