2012-03-24 3 views
5

Мне нужно отобразить растровое изображение 1027 * 768 для окна клиента (такого же размера), и у меня нет более 10-15 мс для выполнения этой задачи. Я использую bufferedGraphics, выделенный из объекта bufferedGraphicsContect и по-прежнему замечает огромные проблемы с производительностью.Запись на буферную поверхность графики с помощью манипуляции с указателем

Я использую небезопасный код, чтобы выполнять свои операции копирования и обнаружили невероятные результаты. Я знаю, что объекты Graphics/BufferedGraphics должны иметь вид поверхности изображения в памяти. Мне было интересно, может ли кто-нибудь указать мне в правильном направлении, как писать на эту поверхность, используя маршал или какой-нибудь другой небезопасный метод низкого уровня.

Я в процессе портирования старого графического приложения C#. Я знаю, что C# не предназначен для тяжелой графики и что есть более эффективные инструменты, чем GDI +, к сожалению, у меня нет такой роскоши.

Это то, что я придумал до сих пор ... Любое понимание того, что так когда-либо сильно связано.

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:

забыл упомянуть, что я ищу альтернативу низкого уровня к Graphics.DrawImage(), предпочтительно писать на поверхности памяти графики, используя указатели? Еще раз спасибо

+0

Я отредактировал отступ кода и, похоже, в конце фигурки фигурного скобки. Если это было проблемой на моем конце, пожалуйста, откиньте мое редактирование – puk

+0

Спасибо за помощь, я думаю, что скобка тоже часть моего виновата, извините :) – OverMars

ответ

3

Обратите внимание на формат изображения растрового изображения. На стандартном 32-битном видео аппаратном обеспечении Format32bppPArgb работает в десять раз быстрее, чем любой другой. Потому что пикселам не нужен перевод. Формат 24bpp, который вы используете, теперь должен быть расширен до 32bpp, и это не приходит бесплатно. Не пропустите P из PArgb и не забудьте установить значение альфа-значения 255 в вашем коде.

Использование BufferedGraphics - это fishy btw. Вы всегда должны использовать тот, который вы получаете бесплатно в методе OnPaint. И вы, вероятно, не нуждаетесь в нем, так как вы так быстро бьете. Это автоматическое 2x ускорение.

+0

Это помогло больше, чем я ожидал, спасибо Я использую bufferedGraphics потому что после заполнения клиентского окна я добавляю еще несколько слоев растровых изображений! :(C# is sooo не предназначен для этого ... – OverMars

+0

Хм, не имеет ничего общего с языком. Вы используете менее идеальную графическую библиотеку. GDI + очень совместим, но если вы хотите перфорировать, вам нужно библиотеку, которая управляет видеопамяти. Например, у DirectX SlimDX есть управляемая оболочка. –

 Смежные вопросы

  • Нет связанных вопросов^_^