2013-10-20 4 views
7

Ich möchte Linien so schnell wie möglich zu zeichnen. Aus diesem Grund habe ich eine Methode mit InteropBitmap implementiert. Das funktioniert ganz gut. Der nächste Schritt war der Vergleich mit ShardDX. Grundsätzlich möchte ich folgendes tun: Ausführen des folgenden Codes in einem BackgroundWorker. Dies informiert das WPF über eine Aktualisierung von WIC. Ich fand heraus, dass dieser Code (alles, was für ShapeDX benötigt wird und die Linie zeichnet) etwa 10ms länger dauert als das Gleiche mit InteropBitmap.SharpDX Render in WPF

Meine Frage ist jetzt einfach, wie man das beschleunigt? Kann ich den Code irgendwie ändern, dass ich nur BeginDraw aufrufen muss, um Zeilen und EndDraw zu erstellen, nicht immer all diese Bildkodierungs-/Dekodierungs-Sachen? Oder gibt es einen besseren Ansatz?

var wicFactory = new ImagingFactory(); 
var d2dFactory = new SharpDX.Direct2D1.Factory(); 

const int width = 800; 
const int height = 200; 

var wicBitmap = new Bitmap(wicFactory, width, height, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad); 

var renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new PixelFormat(Format.Unknown, AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT); 

var d2dRenderTarget = new WicRenderTarget(d2dFactory, wicBitmap, renderTargetProperties); 

var solidColorBrush = new SharpDX.Direct2D1.SolidColorBrush(d2dRenderTarget, SharpDX.Color.White); 

d2dRenderTarget.BeginDraw(); 
//draw whatever you want 
d2dRenderTarget.EndDraw(); 

// Memorystream. 
MemoryStream ms = new MemoryStream(); 
var stream = new WICStream(wicFactory, ms); 
// JPEG encoder 
var encoder = new SharpDX.WIC.JpegBitmapEncoder(wicFactory); 
encoder.Initialize(stream); 

// Frame encoder 
var bitmapFrameEncode = new BitmapFrameEncode(encoder); 
bitmapFrameEncode.Initialize(); 
bitmapFrameEncode.SetSize(width, height); 
var pixelFormatGuid = SharpDX.WIC.PixelFormat.FormatDontCare; 
bitmapFrameEncode.SetPixelFormat(ref pixelFormatGuid); 
bitmapFrameEncode.WriteSource(wicBitmap); 

bitmapFrameEncode.Commit(); 
encoder.Commit(); 

ms.Seek(0, SeekOrigin.Begin); 

// JPEG decoder 
var decoder = new System.Windows.Media.Imaging.JpegBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); 
// Write to wpf image 
_WIC = decoder.Frames[0]; 
// Tell WPF to update 
RaisePropertyChanged("WIC"); 

bitmapFrameEncode.Dispose(); 
encoder.Dispose(); 
stream.Dispose(); 

mit:

System.Windows.Media.Imaging.BitmapFrame _WIC; 
    public System.Windows.Media.Imaging.BitmapSource WIC 
    { 
     get 
     { 
      return (System.Windows.Media.Imaging.BitmapSource)_WIC.GetAsFrozen(); 
     } 
    } 

Und:

<StackPanel> 
    <Image Name="huhu1" Source="{Binding WIC}" /> 
</StackPanel> 

Antwort

4

Das SharpDX-Toolkit unterstützt WPF über eine gemeinsame Direct3D11-zu-Direct3D9-Textur. Es ist in der SharpDXElement Klasse implementiert.

Sie können diese möglicherweise nicht so wiederverwenden, da Direct2D (das Sie zum Zeichnen verwenden) entweder Direct3D11.1 oder Direct3D10 verwenden kann und SharpDX Direct3D11 für WPF-Unterstützung verwendet. Daher müssen Sie die Lösung optimieren. A ein kleines bisschen.

Grundsätzlich müssen Sie Folgendes tun:

  • initialisieren Direct3D (10 oder 11.1).
  • Initialize Direct2D.
  • Erstellen Sie das D3D-Renderziel mit Direct2D-Unterstützung und dem Shared Flag (here ist, wie es in SharpDX getan wird).
  • Initialisieren Direct3D9.
  • Erstellen Sie die gemeinsame texture.
  • Binden Sie die Textur an eine D3DImage.

Vergessen Sie nicht, aufzurufen, wenn der Inhalt des Renderziels aktualisiert wird.

Aus dem von Ihnen bereitgestellten Code ist nicht klar, ob Sie alle Initialisierungen nur einmal durchführen oder nicht. Versuchen Sie daher, jeden Initialisierungscode nur einmal aufzurufen und das Renderziel wiederzuverwenden - löschen Sie es einfach am Anfang jedes Frames. Dies ist zwingend erforderlich, um eine ordentliche Leistung zu erzielen.

Aktualisierung: SharpDX.Toolkit ist veraltet und wird nicht mehr gepflegt. Es wird in ein separates Repository verschoben.

+0

Die Verbindung zu SharpDXElement ist unterbrochen. Bitte aktualisiere es. – BrainSlugs83

+0

@ BrainSlugs83 - Links wurden aktualisiert. –

+0

Ab 2017 sagen sie: 'Der aktuelle Code des Toolkits in diesem Repository funktioniert nicht mehr mit dem neuesten Zweig von SharpDX.' – vines

4

Wenn Sie eine DirectX-Oberfläche mit WPF teilen möchten, ist die beste Option, um einen WPF D3DImage verwenden. Es verspricht, ohne Kopieren zu arbeiten, wenn Sie das richtige Farbformat verwenden.

Ich habe es nur mit DirectX9 verwendet, aber es ist möglich, dass es mit Direct2D auch kompatibel ist, aber wenn es nicht D3d9 ist, kann auch Linien zeichnen.

Es gibt eine große codeproject article mit Beispielen. Aus verwaltetem Code, der slimdx oder sharpdx verwendet, besteht die einzige nicht zu beachtende Einschränkung darin, dass D3DImage eine Verweisanzahl für Ihre DirectX-Oberfläche beibehält. Daher müssen Sie den Rückpuffer explizit auf Null setzen, wenn Sie Ihr d3d-Gerät zurücksetzen möchten.

+0

Das klingt nach einem besseren Ansatz, vielleicht könnten Sie ein kleines Beispiel teilen? Anpassung an den obigen Code? Ich bin ziemlich neu in diesem DirectX-Kram. Ich habe schon angefangen zu suchen, aber vielleicht könntest du viel schneller helfen. – user2799180

+0

Danke für das Beispiel. Ich habe dieses Beispiel schon gesehen, aber es ist nicht so offensichtlich für mich. DirectX ist wirklich neu für mich, daher würde ich ein Beispiel ohne die Notwendigkeit einer C++ - Bibliothek bevorzugen, die vom DirectX-SDK abhängig ist. Leider kann ich nicht sehen, wie ich in diesem Beispiel sharpdx anwenden könnte. – user2799180