2009-04-30 5 views
7

Ho creato un controllo WPF (ereditato da FrameworkElement) che visualizza un'immagine piastrellata che può essere spostata. Ogni riquadro è 256x256 pixel a 24 bpp. Ho ignorato OnRender. Lì, carico le nuove tessere (come BitmapFrame), quindi disegno tutte le tessere visibili usando drawingContext.DrawImage.Prestazioni di rendering WPF con BitmapSource

Ora, ogni volta che ci sono più di una manciata di nuove tessere per ciclo di rendering, il framerate scende da 60 fps a zero per circa un secondo. Questo non è causato dal caricamento delle immagini (che richiede l'ordine di millisecondi), né da DrawImage (che non richiede assolutamente nulla, in quanto si limita a riempire una struttura di dati di rendering intermedi).

La mia ipotesi è che il thread di rendering si strozzi ogni volta che ottiene un numero elevato (~ 20) di nuove istanze BitmapSource (ovvero, quelle che non aveva già memorizzato nella cache). O impiega molto tempo a convertirli in un formato interno compatibile con DirectX o potrebbe trattarsi di un problema di memorizzazione nella cache. Non può essere a corto di RAM video; Perforator mostra picchi inferiori a 60 MB, ho 256 MB. Inoltre, Perforator afferma che tutti gli obiettivi di rendering sono accelerati dall'hardware, quindi non può essere neanche questo.

Qualsiasi approfondimento sarebbe apprezzato!

Grazie in anticipo

Daniel

@RandomEngy:
BitmapScalingMode.LowQuality ridotto il problema un po ', ma non sbarazzarsi di esso. Sto già caricando le tessere alla risoluzione prevista. E non può essere il driver grafico, che è aggiornato (Nvidia).
Sono un po 'sorpreso di sapere che il ridimensionamento richiede molto tempo. Il modo in cui l'ho capito, una bitmap (indipendentemente dalle sue dimensioni) viene appena caricata come trama Direct3D e quindi ridimensionata su hardware. In effetti, una volta che la bitmap è stata renderizzata per la prima volta, posso cambiarne la rotazione e la scala senza ulteriori blocchi.

risposta

3

Non è solo con un gran numero di immagini. Basta una sola immagine grande per contenere il rendering fino a quando non è stato caricato, e questo può essere abbastanza evidente quando le dimensioni dell'immagine iniziano ad aumentare di migliaia.

Sono d'accordo con te che probabilmente è il thread di rendering: ho fatto un test e il thread dell'interfaccia utente era ancora felicemente di inviare messaggi mentre questo ritardo di rendering stava avendo luogo nel tentativo di visualizzare un BitmapImage pre-memorizzato nella cache.

Deve fare una sorta di conversione o di preparazione sull'immagine, come si stava ipotizzando. Ho cercato di attenuare questo nella mia app "rendering" ma nascondendo l'immagine, quindi rivelando quando ho bisogno di mostrarlo. Tuttavia questo non è l'ideale perché i blocchi di rendering avvengono comunque.

(Edit)

Alcuni followup: Dopo una discussione sul alias MS WPF ho trovato quello che stava causando i ritardi. Sulla mia macchina Server 2008 era una combinazione di vecchi driver video che non supportano il nuovo modello di driver WDDM e un ritardo nel ridimensionamento dell'immagine.

Se la dimensione dell'immagine di origine è diversa dalla dimensione di visualizzazione, questo ritarderà il thread di rendering prima che l'immagine venga visualizzata. Per impostazione predefinita, un'immagine è impostata sulla massima qualità, ma è possibile modificare le opzioni di ridimensionamento per il rendering chiamando RenderOptions.SetBitmapScalingMode(uiImage, BitmapScalingMode.LowQuality);. Una volta fatto ciò, il blocco misterioso prima di visualizzare un'immagine scomparve. Un'alternativa, se non ti piace il calo della qualità nel ridimensionamento, è caricare BitmapImage con DecodePixelWidth/Height uguale alla dimensione in cui verrà visualizzato. Quindi se carichi BitmapImage su un thread in background, non dovresti avere alcun ritardo nel visualizzarlo.

0

Prova anche questi;

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

ho avuto qualche problema con le prestazioni quando si utilizza una quantità enorme di "A" il colore del canale di, attesa fino a dopo che l'immagine aveva reso in scala ha funzionato molto meglio per me.

Inoltre, come hai detto usando un'immagine piastrellata?

Di solito si utilizza TileBrush per impostare semplicemente il pennello su FrameworkElement. Se li stai animando o aggiungendone di nuovi dinamicamente, puoi generare i tuoi pennelli e quindi applicarli all'oggetto mentre vai manualmente, assicurati di bloccarli se puoi. Inoltre, VisualBitmapScalingMode è una proprietà di qualsiasi Visual.