2012-03-24 17 views
5

Ich muss eine 1027 * 768 Bitmap zum Client-Fenster (gleiche Größe) und ich habe nicht mehr als 10-15 ms, um diese Aufgabe abzuschließen. Ich verwende BufferedGraphics zugewiesen von einem bufferedGraphicsContect Objekt und beachten Sie immer noch große Performance-Probleme.Schreiben auf gepufferte Grafikoberfläche über Zeigermanupilation

ich unsicheren Code bin mit meinen Kopiervorgänge und gefunden unglaubliche Ergebnisse durchzuführen. Ich weiß, dass die Graphics/BufferedGraphics Objekte eine Art von Zeichnungsoberfläche in Speicher haben sollten. Ich habe mich gefragt, ob mir jemand in die richtige Richtung zeigen könnte, wie man mit Marshal oder einer anderen unsicheren Low-Level-Methode auf diese Oberfläche schreibt.

Ich bin in den Prozess der eine ältere C# Grafikanwendung zu portieren. Ich weiß, dass C# nicht für schwere Grafiken ausgelegt ist und dass es bessere Werkzeuge als GDI + gibt, leider habe ich diesen Luxus nicht.

Dies ist, was ich mit so weit gekommen sind ... Jeder Einblick, was so überhaupt stark apperciated.

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:

vergessen Ich suche nach einem niedrigen Niveau Alternative zu Graphics.DrawImage() zu erwähnen, vorzugsweise auf Grafikoberfläche Speicher zu schreiben, mit Zeigern? Danke nochmal

+0

Ich habe den Codeeinzug bearbeitet und es scheint eine danging geschweifte Klammer am Ende zu haben. Wenn dies ein Problem auf meinem Ende ist, bitte meine bearbeiten – puk

+0

Danke für die Hilfe zurückrollen, ich denke, die Klammer Teil meiner Schraube ist auch nach oben, sorry :) – OverMars

Antwort

3

Achte auf das Pixelformat der Bitmap. Auf der 32-Bit-Standard-Videohardware rendert Format32bppPArgb zehn Mal schneller als alle anderen. Weil die Pixel keine Übersetzung benötigen. Das 24bpp-Format, das Sie jetzt verwenden, muss auf 32bpp erweitert werden, und das ist nicht kostenlos. Überspringen Sie nicht das P von PArgb und vergessen Sie nicht, den Alpha-Wert in Ihrem Code auf 255 zu setzen.

BufferedGraphics Verwendung ist btw fischig. Sie sollten immer diejenige verwenden, die Sie in der OnPaint-Methode kostenlos erhalten. Und du brauchst wahrscheinlich überhaupt keinen, da du so schnell blitzst. Das ist eine automatische 2x-Beschleunigung.

+0

dass mehr geholfen als ich erwartet hatte, dank ich die BufferedGraphics verwenden weil ich nach dem Füllen des Clientfensters mehrere andere Bitmap-Ebenen hinzufüge! :(C# ist dafür nicht gedacht ... – OverMars

+0

Hmm, hat nichts mit der Sprache zu tun. Du verwendest nur eine weniger als ideale Grafikbibliothek. GDI + ist sehr kompatibel, aber wenn du Perf brauchen willst, brauchst du eine Bibliothek, die den Videospeicher verwaltet: DirectX zum Beispiel hat SlimDX einen verwalteten Wrapper dafür. –