Как напрямую рисовать в буфере формы (используя указатели) - PullRequest
0 голосов
/ 19 апреля 2019

У меня есть некоторый буфер визуальных данных, который изменяется довольно быстро.И мне нужно нарисовать его, чтобы сформировать, по крайней мере, с 60 кадрами в секунду.

Во всех других похожих вопросах, которые я нашел - было рекомендовано использовать 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-90 мс на моем ПК в полноэкранном режиме).

Итак,Есть ли способ рисовать непосредственно в буфере формы, как я делаю с Bitmap s Scan0?

Обратите внимание, хотя в примере буфер визуальных данных является просто массив растровых 4хFloat цветов, мне нужното же самое для более сложных форматов, так что в любом случае нужно будет выполнить какое-то преобразование цвета.

1 Ответ

0 голосов
/ 19 апреля 2019

Вот реализация того, что вы пытаетесь выполнить с помощью события Forms Paint (). Это будет намного быстрее, чем выделение экранного буфера для каждого кадра. Вы можете изменить «буферный» пиксельный буфер в любом месте вашей формы, и он будет перекрашен в форме. Вам просто нужно вызвать this.Invalidate (), чтобы вызвать Paint. Каждый раз, когда вы меняете бафф, вызывайте 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");
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...