2012-03-24 6 views
5

Necesito renderizar un mapa de bits 1027 * 768 en la ventana del cliente (mismo tamaño) y no tengo más de 10-15 ms para completar esta tarea. Estoy usando con bufferGraphics asignado desde un objeto buffertaficsContect y todavía noto grandes problemas de rendimiento.Escribir en la superficie de gráficos almacenados en el medio de la manupulación del puntero

estoy usando código no seguro para realizar mis operaciones de copia y encontrado resultados increíbles. Sé que los objetos Graphics/BufferedGraphics deberían tener algún tipo de superficie de dibujo en la memoria. Me preguntaba si alguien podría señalarme en la dirección correcta sobre cómo escribir en esta superficie usando Marshal o algún otro método inseguro de bajo nivel.

Estoy en el proceso de portar una aplicación de gráficos C# anterior. Sé que C# no está diseñado para gráficos pesados ​​y que hay mejores herramientas que GDI + disponible, lamentablemente no tengo esos lujos.

Esto es lo que he encontrado hasta ahora ... Cualquier idea de lo que siempre está muy apercinada.

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:

se olvidó de mencionar que estoy buscando una alternativa de bajo nivel a Graphics.DrawImage(), preferiblemente por escrito a la memoria de gráficos de superficie, el uso de punteros? Gracias de nuevo

+0

He editado la sangría del código y parece tener una llave al final. Si esto fue un problema de mi parte, por favor invierta mi edición – puk

+0

Gracias por la ayuda, creo que el corsé es parte de mi error también, lo siento :) – OverMars

Respuesta

3

Preste atención al formato de píxel del mapa de bits. En hardware de video estándar de 32 ppp, Format32bppPArgb rinde diez veces más rápido que cualquiera de los otros. Porque los píxeles no necesitan ninguna traducción. El formato 24bpp que usa ahora necesita ampliarse a 32bpp y eso no se obtiene de forma gratuita. No omita el P de PArgb y no se olvide de establecer el valor alfa en 255 en su código.

Usar BufferedGraphics es fishy por cierto. Siempre debe usar el que obtiene de forma gratuita en el método OnPaint. Y probablemente no necesites uno ya que estás disminuyendo así de rápido. Eso es una aceleración automática de 2x.

+0

Eso ayudó más de lo que esperaba, gracias Uso el bufferGraphics porque después de llenar la ventana del cliente, agrego varias otras capas de mapas de bits. :(C# no está destinado para esto ... – OverMars

+0

Hmm, no tiene nada que ver con el idioma. Estás usando una biblioteca de gráficos menos que ideal. GDI + es muy compatible, pero si quieres perf entonces necesitas una biblioteca que gestiona la memoria de video. DirectX, por ejemplo, SlimDX tiene un contenedor administrado para ella. –

Cuestiones relacionadas