2012-04-23 18 views
8

Sono parte di un team che ha creato uno strumento per visualizzare e interagire con grafici molto grandi e fortemente interconnessi in C#/WPF. La visualizzazione e l'interazione con il grafico avviene attraverso un controllo personalizzato che acquisisce un set di DrawingVisuals e li visualizza su una tela. I nodi nel grafico potrebbero avere una forma personalizzata creata con il nostro editor. Il controllo attuale funziona molto bene ed è abbastanza accoppiato con il nostro programma, ma ci sono preoccupazioni legittime riguardo alle prestazioni quando si considerano grafici molto più grandi (oltre 20.000 nodi e molta connessione).Prestazioni di disegno 2D (GDI + vs SlimDX)

Dopo aver fatto un po 'di ricerca sembra che i due approcci sono:

  • A GDI + percorso dove la grafica sono attratti da un WriteableBitmap o InteropBitmap.
  • SlimDX o variante DirectX (ospitato in un D3DImage)


Alla luce di questi due approcci estremamente diversi quale strada sarebbe meglio prendere in considerazione:

  • Interagire con il grafico deve essere veloce anche durante la visualizzazione dell'intero grafico.
  • L'aggiornamento delle immagini deve essere veloce (cambio di colore o dimensione)
  • Il test di hit deve essere veloce (punto e rettangolo).
  • Lo sviluppo deve essere completato in modo tempestivo.

Quale metodo utilizzeresti e perché?

MODIFICA:
Sembra un similar question è stato chiesto ma non ha risposto.

+0

GDI + lento. GDI veloce ma brutto. D2D è migliore ma lento. SlimDX è un'enorme dipendenza e una grande curva di apprendimento astratto. Terza opzione, usando DX9 o (DX11 via DXGI) mentre si stringe con l'interfaccia D3DImage di WPF. Concessa una curva di apprendimento, ma più manutenibile per creare un dispositivo 3DX, contesto, buffer, shader e ottenere il rendering dell'app tramite Direct3D. La documentazione è terribile e ci vorrà qualche ricerca e un errore di prova, ma non è così male come sembra. Vedi qui per un piccolo mondo reale [18 meg demo download] (http://www.gigasoft.com) include WPF WinForm e MFC, e la maggior parte dei dati WAV e GIS. – Robert

risposta

1

Consentitemi di elencare i pro e i contro di ciascun approccio, che forse vi darà un'idea su quale utilizzare.

GDI Pro

  • facile disegnare forme vettoriali con
  • Non c'è bisogno di includere librerie extra

GDI Contro

  • Più lento di DX
  • necessità di limitare disegno "fantasia" (gradienti e simili) o m ight rallentare le cose
  • Se lo schema deve essere interattivo - potrebbe non essere una grande opzione

SlimDX Pro

  • può fare qualche disegno di fantasia pur essendo più veloce di GDI
  • Se il il disegno è interattivo - questo approccio sarà MOLTO meglio
  • Poiché disegni i primitivi puoi controllare la qualità a ogni livello di zoom

SlimDX Contro

  • non molto facile da disegnare forme semplici con - avrete bisogno di scrivere i propri astrazioni o utilizzare una libreria che consente di disegnare forme
  • non è così semplice da usare un GDI soprattutto se non lo hai usato prima

E forse più ho dimenticato di mettere qui, ma forse questi lo faranno per i principianti?

-A.

+0

Grazie per la risposta! Hai esperienza con SlimDX (integrazione wpf)? C'è un limite superiore alla quantità di cose che può rendere? Sto cercando di valutare la curva di apprendimento di SlimDX con i vantaggi prestazionali che offre rispetto alla rotta GDI. – CBent

+0

Credo che SlimDX abbia un campione di interoperabilità WPF (http://code.google.com/p/slimdx/source/browse/trunk/samples/Direct3D10/WpfSample10/). Inoltre, anche se non esiste un limite superiore di per sé a quello che SlimDX/DirectX è in grado di eseguire, ricorda che le prestazioni dipendono solo dalla potenza della scheda grafica e dall'efficienza di rendering, in realtà ciò vale sia per GDI che per DX. Suggerirei di seguire prima la rotta GDI e prendere il ricorso a SlimDX se le prestazioni non corrispondono alle tue esigenze. – Ani

+0

Sono curioso di sapere perché si consiglia il modo "GDI" di fare cose su SlimDX. La curva di apprendimento di SlimDX è così alta?Vi è la preoccupazione che l'implementazione della modalità GDI (rendering, selezione spaziale rapida e integrazione) solo per scoprire che è troppo lento sarebbe un "spreco" di tempo quando andare con la rotta accelerata GPU in primo luogo risolverebbe il problema . Ancora una volta, grazie per la risposta. – CBent

7

Uso GDI per il mio cartographic application. Mentre GDI + è più lento di, per esempio, DirectX, trovo che ci sono molte cose e trucchi che possono essere usati per velocizzare le cose. Un sacco di CPU viene utilizzato per preparare i dati prima di disegnarli da sé, quindi GDI non dovrebbe essere l'unico collo di bottiglia lì.

cose da guardare fuori per (e questi sono sufficienti per applicare ad altri motori grafici in generale, troppo):

  1. Prima di tutto: misura. Utilizzare un profiler per vedere qual è il vero collo di bottiglia nel codice.
  2. Riutilizzo primitive GDI. Questo è vitale. Se devi disegnare 100.000 oggetti grafici che sembrano uguali o simili, usa lo stesso Pen, Brush ecc. Creare questi primitivi è costoso.
  3. Cache i dati di rendering - ad esempio: non ricalcolare le posizioni dell'elemento gfx se non è necessario.
  4. Quando si esegue la panoramica/zoomata, disegnare la scena con qualità GDI + inferiore (e senza costose operazioni GDI). Esistono numerose impostazioni dell'oggetto Graphics per ridurre la qualità. Dopo che l'utente interrompe il panning, disegna la scena con l'alta qualità.
  5. Un sacco di piccole cose che migliorano le prestazioni. Ho sviluppato questa app per 2-3 anni (o è già 4 hmm?) Ora e trovo ancora dei modi per migliorare le cose :). Questo è il motivo per cui la profilazione è importante: il codice cambia e questo può influire sulle prestazioni, quindi è necessario profilare il nuovo codice.

Un'altra cosa: non ho usato SlimDX, ma ho provato Direct2D (mi riferisco a Microsoft.WindowsAPICodePack.DirectX.Direct2D1). Nel mio caso la performance è stata notevolmente più veloce di GDI +, ma ho avuto alcuni problemi con il rendering delle bitmap e non ho mai avuto il tempo di trovare la soluzione adeguata.

+0

Il capo del progetto è cauto nell'affrontare la rotta GDI +/Bitmap a causa della sua esperienza passata di rallentamento (potrebbe essere giusto o sbagliato). Desidera una soluzione basata sulle prestazioni e si è bloccato nella sua testa che DirectX è la soluzione. Pensi che GDI + sarà abbastanza veloce per 30 fps e interattivo con oggetti da 100k? – CBent

+0

@CBent: Difficile dirlo, dipende molto dalla natura di ciò che si sta disegnando (e dall'hardware, ovviamente). Ma ecco qualcosa che mi sono appena imbattuto in me stesso e sperimenterò definitivamente per la mia applicazione: http://code.google.com/p/sharpdx/. Afferma di essere la libreria DirectX più veloce gestita: se è più veloce di WindowsAPICodePack, allora è veramente veloce! –

+0

@CBent: e oh sì, DirectX è di solito la strada da percorrere quando hai bisogno di una grafica veloce, quindi credo che il pensiero del tuo capo progetto sia giusto. Sono andato con la rotta GDI + perché era Mono-portatile - Ho utenti che eseguono la mia app su Linux e Mac. –

3

Ho recentemente portato un po 'di codice di disegno su DirectX e sono stato molto soddisfatto dei risultati. Stavamo principalmente rendendo bitmap usando bit-bashing e vediamo tempi di rendering che potevano essere misurati in minuti ridotti a circa 1-2 secondi.

Questo non può essere confrontato direttamente a voi l'utilizzo, come siamo passati da po-colpire in C++ per Direct3D in C# utilizzando SlimDX, ma immagino si vedrà benefici delle prestazioni, anche se non sono gli ordini di magnitudine stiamo vedendo.

Consiglierei di dare un'occhiata all'utilizzo di Direct2D con SlimDX. È necessario utilizzare DirectX 10.1 poiché Direct2D non è compatibile con DirectX 11 per qualche motivo. Se hai utilizzato l'API di disegno in WPF, avrai già familiarità con Direct2D poiché la sua API si basa sull'API di disegno WPF per quanto ne so. I problemi principali con Direct2D sono la mancanza di documentazione e il fatto che funziona solo in Vista in poi.

non ho sperimentato con DirectX 10/WPF interoperabilità, ma credo che sia possibile (http://stackoverflow.com/questions/1252780/d3dimage-using-dx10)

EDIT: ho pensato che Ti do un paragone dal nostro codice per disegnare un semplice poligono. In primo luogo la versione WPF:

 StreamGeometry geometry = new StreamGeometry(); 

     using (StreamGeometryContext ctx = geometry.Open()) 
     { 
      foreach (Polygon polygon in mask.Polygons) 
      { 
       bool first = true; 

       foreach (Vector2 p in polygon.Points) 
       { 
        Point point = new Point(p.X, p.Y); 

        if (first) 
        { 
         ctx.BeginFigure(point, true, true); 
         first = false; 
        } 
        else 
        { 
         ctx.LineTo(point, false, false); 
        } 
       } 
      } 
     } 

Ora la versione Direct2D:

 Texture2D maskTexture = helper.CreateRenderTexture(width, height); 

     RenderTargetProperties props = new RenderTargetProperties 
     { 
      HorizontalDpi = 96, 
      PixelFormat = new PixelFormat(SlimDX.DXGI.Format.Unknown, AlphaMode.Premultiplied), 
      Type = RenderTargetType.Default, 
      Usage = RenderTargetUsage.None, 
      VerticalDpi = 96, 
     }; 

     using (SlimDX.Direct2D.Factory factory = new SlimDX.Direct2D.Factory()) 
     using (SlimDX.DXGI.Surface surface = maskTexture.AsSurface()) 
     using (RenderTarget target = RenderTarget.FromDXGI(factory, surface, props)) 
     using (SlimDX.Direct2D.Brush brush = new SolidColorBrush(target, new SlimDX.Color4(System.Drawing.Color.Red))) 
     using (PathGeometry geometry = new PathGeometry(factory)) 
     using (SimplifiedGeometrySink sink = geometry.Open()) 
     { 
      foreach (Polygon polygon in mask.Polygons) 
      { 
       PointF[] points = new PointF[polygon.Points.Count()]; 
       int i = 0; 

       foreach (Vector2 p in polygon.Points) 
       { 
        points[i++] = new PointF(p.X * width, p.Y * height); 
       } 

       sink.BeginFigure(points[0], FigureBegin.Filled); 
       sink.AddLines(points); 
       sink.EndFigure(FigureEnd.Closed); 
      } 

      sink.Close(); 
      target.BeginDraw(); 
      target.FillGeometry(geometry, brush); 
      target.EndDraw(); 
     } 

Come si può vedere, la versione Direct2D è leggermente più lavoro (e si basa su alcune funzioni di aiuto che ho scritto), ma in realtà è molto simile.

+0

Spero che andando a una variante DirectX (attualmente guardando SharpDX) il rendering della nostra applicazione migliorerà quanto il tuo. Stiamo disegnando linee semplici e poligoni 2D (ma così tanti di loro che WPF inizia a soffocare). Quali risorse hai usato per la ricerca SlimDX? – CBent

+0

Ho paura che ciò sia stato fatto circa un anno fa, quindi non ricordo le risorse esatte che ho usato. SlimDX rimane abbastanza vicino all'API COM Direct2D, quindi qualsiasi esempio in C++ può essere convertito in C#/SlimDX abbastanza facilmente, che è quello che credo di aver fatto. – Grokys

+0

Wow! Ho appena ricevuto il tuo post modificato con il codice incluso. Sono molto simili davvero. Hai dovuto modificare uno qualsiasi dei tuoi formati poligono per renderli compatibili per SlimDX? La tua applicazione è un'applicazione a schermo intero, una singola superficie DX o hai molte superfici visualizzate contemporaneamente? – CBent