我有一些可视数据缓冲区,该缓冲区的变化很快。而且我需要以至少60fps的速度绘制它。
在我发现的所有其他类似问题中-建议使用Bitmap
作为临时缓冲区,如下所示:
public unsafe TimeSpan CopyToFormBuffer(float* buff)
{
var b = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
var bd = b.LockBits(this.ClientRectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
//this is more of a GPU work, but for simplicity i put it on CPU:
var hy = bd.Scan0;
for (int y = 0; y < this.ClientSize.Height; ++y, hy += bd.Stride)
{
var hx = hy;
for (int x = 0; x < this.ClientSize.Width; ++x, hx += 4, buff += 4)
{
var p = (byte*)hx;
p[3] = Convert.ToByte(buff[0] * 255);
p[2] = Convert.ToByte(buff[1] * 255);
p[1] = Convert.ToByte(buff[2] * 255);
p[0] = Convert.ToByte(buff[3] * 255);
}
}
b.UnlockBits(bd);
var sw = Stopwatch.StartNew();
this.CreateGraphics().DrawImage(b, 0, 0);
sw.Stop();
return sw.Elapsed;
}
private unsafe void Form1_Load(object sender, EventArgs e)
{
var buff = (float*)Marshal.AllocHGlobal(this.ClientSize.Width * this.ClientSize.Height * 4 * sizeof(float));
for (var i = 100; i > 0; i--)
MessageBox.Show(CopyToFormBuffer(buff).ToString());
}
但是这样,行:
this.CreateGraphics().DrawImage(b, 0, 0);
进行额外的复制操作,这太慢了(在全屏模式下,我的电脑上80-90ms)。
因此,有没有办法像我对Bitmap
的{{1}}那样直接绘制表单缓冲区?
注意,即使在示例数据中,视觉数据缓冲区只是4хFloat栅格颜色的数组,对于更复杂的格式,我也需要相同的颜色,因此无论如何都需要进行某种颜色转换。
答案 0 :(得分:0)
这里是您使用Forms Paint()事件尝试完成的实现。这比每帧分配一个屏幕缓冲区要快得多。您可以在表单中的任何位置修改“ buff”像素缓冲区,它将在表单中重新绘制。您只需要调用this.Invalidate()即可强制调用Paint。每当您更改buff时,请在表单本身上调用Invalidate。
public partial class Form1 : Form
{
private unsafe float* buff;
public unsafe Form1()
{
InitializeComponent();
buff = (float*)Marshal.AllocHGlobal(this.ClientSize.Width * this.ClientSize.Height * 4 * sizeof(float));
}
private unsafe void Form1_Paint(object sender, PaintEventArgs e)
{
var sw = Stopwatch.StartNew();
var b = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
var bd = b.LockBits(this.ClientRectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
//this is more of a GPU work, but for simplicity i put it on CPU:
var hy = bd.Scan0;
for (int y = 0; y < this.ClientSize.Height; ++y, hy += bd.Stride)
{
var hx = hy;
for (int x = 0; x < this.ClientSize.Width; ++x, hx += 4, buff += 4)
{
var p = (byte*)hx;
p[3] = Convert.ToByte(buff[0] * 255);
p[2] = Convert.ToByte(buff[1] * 255);
p[1] = Convert.ToByte(buff[2] * 255);
p[0] = Convert.ToByte(buff[3] * 255);
}
}
b.UnlockBits(bd);
e.Graphics.DrawImage(b, 0, 0);
sw.Stop();
Debug.WriteLine($"Frame took {sw.Elapsed}ms to draw");
}
}