2012-03-24 4 views
5

Ho bisogno di rendere un bitmap 1027 * 768 alla finestra client (stessa dimensione) e non ho più di 10-15 ms per completare questa attività. Sto usando bufferedGraphics allocati da un oggetto bufferedGraphicsContect e notiamo comunque enormi problemi di prestazioni.Scrittura su superficie grafica bufferizzata tramite manupilazione puntatore

Sto usando il codice non sicuro per eseguire i miei operazioni di copia erisultati incredibili trovate. So che gli oggetti Graphics/BufferedGraphics dovrebbero avere una sorta di superficie di disegno nella memoria. Mi stavo chiedendo se qualcuno potesse indicarmi la giusta direzione su come scrivere su questa superficie usando Marshal o qualche altro metodo a basso livello non sicuro.

Sono in procinto di eseguire il porting di un'applicazione grafica C# precedente. So che C# non è progettato per la grafica pesante e che ci sono strumenti migliori di GDI + disponibili, purtroppo non ho quei lussi.

Questo è quello che ho inventato finora ... Qualsiasi intuizione che sia così fortemente appannata.

byte[] _argbs = null; 
static readonly Bitmap _bmUnderlay = Properties.Resources.bg; 
static Bitmap _bmpRender = new Bitmap(1024, 768, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
int bmpHeight = Properties.Resources.bg.Height; 
int bmpWidth = Properties.Resources.bg.Width; 
static BufferedGraphicsContext _bgc = new BufferedGraphicsContext(); 

internal unsafe void FillBackBuffer(Point cameraPos) 
{ 
     // lock up the parts of the original image to read (parts of it) 
     System.Drawing.Imaging.BitmapData bmd = _bmUnderlay.LockBits(
      new Rectangle(cameraPos.X, cameraPos.Y, 1024, 768), 
      System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
     // get the address of the first line. 
     IntPtr ptr = bmd.Scan0; 

     //if (_argbs == null || _argbs.Length != bmd.Stride * bmd.Height) 
     // _argbs = new byte[bmd.Stride * bmd.Height]; 
     if (_argbs == null || _argbs.Length != 1024 * 3 * 768) 
      _argbs = new byte[1024 * 3 * 768]; 

     // copy data out to a buffer 
     Marshal.Copy(ptr, _argbs, 0, 1024 * 3 * 768); 

     _bmUnderlay.UnlockBits(bmd); 

     // lock the new image to write to (all of it) 
     System.Drawing.Imaging.BitmapData bmdNew = _bmpRender.LockBits(
      new Rectangle(0, 0, 1024, 768), 
      System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 
     // copy data to new bitmap 
     Marshal.Copy(_argbs, 0, bmdNew.Scan0, 1024 * 3 * 768); 
     _bmpRender.UnlockBits(bmdNew); 
} 

private unsafe void _btnGo_Click(object sender, EventArgs e) 
{ 
    // less than 2 ms to complete!!!!!!!! 
    FillBackBuffer(new Point()); 

    using (BufferedGraphics bg = _bgc.Allocate(CreateGraphics(), ClientRectangle)) 
    { 
     System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); 
     sw.Start(); 
     ///// 
     /// 
     // This method takes over 17 ms to complete 
     bg.Graphics.DrawImageUnscaled(_bmpRender, new Point()); 
     // 
     /// 
     ///// 
     sw.Start(); 
     this.Text = sw.Elapsed.TotalMilliseconds.ToString(); 

     bg.Render(); 
    } 
} 

EDIT:

dimenticato di dire che sto cercando un basso livello alternativa al Graphics.DrawImage(), preferibilmente scrivendo a Memoria grafica di superficie, utilizzando i puntatori? Grazie ancora

+0

Ho modificato il rientro del codice e alla fine sembra avere un tutore arricciato. Se questo è stato un problema per la mia parte, per favore restituisci la mia modifica – puk

+0

Grazie per l'aiuto, penso che il tutore sia anche parte del mio vizio, mi dispiace :) – OverMars

risposta

3

Prestare attenzione al formato pixel della bitmap. Su hardware video 32bpp standard, Format32bppPArgb viene eseguito dieci volte più velocemente di tutti gli altri. Perché i pixel non hanno bisogno di alcuna traduzione. Il formato 24bpp che usi ora deve essere ampliato a 32bpp e non è gratis. Non saltare il P di PArgb e non dimenticare di impostare il valore alfa su 255 nel codice.

Utilizzo di BufferedGraphics è fishy btw. Si dovrebbe sempre usare quello che si ottiene gratuitamente nel metodo OnPaint. E probabilmente non ne hai affatto bisogno visto che stai facendo un salto veloce. Questo è un aumento automatico 2x.

+0

Questo ha aiutato più di quanto mi aspettassi, grazie Io uso il bufferedGraphics perché dopo aver riempito la finestra del client, aggiungo diversi altri livelli di bitmap! :(C# non è pensata per questo ... – OverMars

+0

Hmm, non ha nulla a che fare con il linguaggio, stai usando solo una libreria grafica meno che ideale GDI + è molto compatibile ma se vuoi essere perfetto allora hai bisogno di un libreria che gestisce la memoria video. DirectX ad esempio, SlimDX ha un wrapper gestito per esso. –

Problemi correlati