2013-10-20 14 views
7

Chcę rysować linie tak szybko, jak to możliwe. Z tego powodu zaimplementowałem metodę wykorzystującą InteropBitmap. Działa to całkiem dobrze. Kolejnym krokiem było porównanie z ShardDX. Zasadniczo, co chcę zrobić, to: Uruchomienie następującego kodu w BackgroundWorker. To informuje WPF o aktualizacji WIC. Dowiedziałem się, że ten kod (tworząc wszystkie potrzebne dla ShapeDX i linii rysowania) trwa około 10ms dłużej niż robi to samo przy użyciu InteropBitmap.Renderowanie SharpDX w WPF

Moje pytanie brzmi teraz, jak przyspieszyć? Czy mogę zmienić kod w jakiś sposób, że muszę tylko wywołać BeginDraw, tworzyć linie i EndDraw, nie zawsze robiąc całe to kodowanie/dekodowanie obrazu? Czy istnieje lepsze podejście?

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(); 

Z:

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

oraz:

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

Odpowiedz

4

SharpDX Toolkit obsługuje obsługę WPF za pośrednictwem struktury współdzielonej Direct3D11-Direct3D9. Jest on zaimplementowany w klasie SharpDXElement.

Możesz nie być w stanie ponownie użyć tego, ponieważ Direct2D (który używasz do rysowania) może współdziałać z Direct3D11.1 lub Direct3D10, a SharpDX używa Direct3D11 do obsługi WPF, więc będziesz musiał dostosować rozwiązanie trochę.

Zasadniczo należy wykonać następujące czynności:

  • Initialize Direct3D (10 lub 11.1).
  • Zainicjuj Direct2D.
  • Utwórz cel renderowania D3D z obsługą Direct2D i flagą Shared (here, jak to zrobić w SharpDX).
  • Inicjalizuj Direct3D9.
  • Utwórz udostępniony texture.
  • Powiąż teksturę z D3DImage.

Nie zapomnij zadzwonić pod numer D3DImage.AddDirtyRect, gdy zawartość docelowej renderowania zostanie zaktualizowana.

Z podanego kodu nie jest jasne, czy wykonujesz wszystkie inicjalizacje tylko raz, czy nie, dlatego spróbuj wywołać kod inicjalizacyjny tylko raz i ponownie użyj celu renderowania - po prostu wyczyść go na początku każdej klatki. Jest to obowiązkowe, aby uzyskać przyzwoitą wydajność.

Aktualizacja: SharpDX.Toolkit został przestarzały i nie jest już utrzymywany. Zostaje przeniesiony do osobnego repozytorium.

+0

Link do SharpDXElement jest uszkodzony. Zaktualizuj to. – BrainSlugs83

+0

@ BrainSlugs83 - linki zostały zaktualizowane. –

+0

Od 2017 roku mówią: 'Aktualny kod zestawu narzędzi w tym repozytorium przestał działać z najnowszą gałęzią SharpDX. – vines

4

Jeśli chcesz podzielić powierzchnię directx z WPF, najlepszym rozwiązaniem jest użycie WPF D3DImage. Obiecuje pracować bez kopiowania, jeśli używasz odpowiedniego formatu kolorów.

Używałem go tylko z Directx9, ale możliwe, że jest on kompatybilny z Direct2D, ale jeśli nie jest to D3d9, może rysować również linie.

Oto przykład codeproject article. Z kodu zarządzanego za pomocą slimdx lub sharpdx jedynym nieoczywistym zastrzeżeniem jest to, że D3DImage zachowuje liczbę referencyjną do swojej powierzchni DirectX, więc musisz zerwać backbuffer, gdy chcesz zresetować urządzenie d3d.

+0

To brzmi jak lepsze podejście, może mógłbyś podzielić się małym przykładem? Dopasowanie do powyższego kodu? Jestem całkiem nowy w tym wydaniu DirectX. Już zacząłem szukać, ale może mógłbyś pomóc znacznie szybciej. – user2799180

+0

Dzięki za przykład. Widziałem już ten przykład, ale nie jest to dla mnie oczywiste. DirectX jest dla mnie naprawdę nowy, więc wolałbym przykład bez biblioteki C++, w zależności od pakietu DirectX SDK. Niestety, nie widzę, w jaki sposób mogę zastosować sharpdx na tym przykładzie. – user2799180