Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 27.04.06 06:51
Оценка:
Есть приложение на C#, в котором создается поток рисующий битмапы,
необходимо максимально быстро проинформировать основной поток программы
что необходимо произвести перерисовку, при этом не задерживая исполнение
потока до завершения отрисовки. Если на момент обновления не завершена
предыдущая отрисовка, то отрисовку не делать.
Приложение почти рилтайм частота перерисовки формы >= 50 раз в секунду.
Требуется максимальная скорость. Как это можно сделать?

вызов Invalidate у формы приводит к остановке выполнения до окончания отрисовки...
семафоры и другие эвенты лучше не использовать — сильно тормозят выполнение программы...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Как сделать перерисовку формы максимально быстрой
От: Andrbig  
Дата: 27.04.06 07:30
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>Есть приложение на C#, в котором создается поток рисующий битмапы,

Рабочий поток не должен заниматься рисованием, его задача — сгенерить данные.

S>Приложение почти рилтайм частота перерисовки формы >= 50 раз в секунду.

S>Требуется максимальная скорость. Как это можно сделать?

При таком раскладе не надо никому ничего сообщать. Заведи таймер, срабатывающий так часто, как тебе надо. Таймер возьмет последние данные от рабочего потока и их отрисует. Все, не надо никаких усложнений.
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 27.04.06 07:51
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>При таком раскладе не надо никому ничего сообщать. Заведи таймер, срабатывающий так часто, как тебе надо. Таймер возьмет последние данные от рабочего потока и их отрисует. Все, не надо никаких усложнений.


ха

я так и делал вначале, поставил таймер на 20 мс и по нему делал Invalidate, но
по какимто причинам таймер срабатывает не раз в 20 мс, а как ему вздумается —
то раз в 3 секунды, то раз в секунду, короче обновление получается в среднем
раз в несколько секунд. В чем дело не знаю... поэтому стал делать Invalidate из
потока отрисовки, но это стало заметно тормозить поток отрисовки, а его тормозить нельзя
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Andrbig  
Дата: 27.04.06 08:06
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>Здравствуйте, Andrbig, Вы писали:


A>>При таком раскладе не надо никому ничего сообщать. Заведи таймер, срабатывающий так часто, как тебе надо. Таймер возьмет последние данные от рабочего потока и их отрисует. Все, не надо никаких усложнений.


S>ха


S>я так и делал вначале, поставил таймер на 20 мс и по нему делал Invalidate, но

S>по какимто причинам таймер срабатывает не раз в 20 мс, а как ему вздумается -
S>то раз в 3 секунды, то раз в секунду, короче обновление получается в среднем
S>раз в несколько секунд. В чем дело не знаю... поэтому стал делать Invalidate из
S>потока отрисовки, но это стало заметно тормозить поток отрисовки, а его тормозить нельзя

ха

Сравни то что ты делал с тем что я предложил. Ты каждые 20мс бросал invalidate, а отрисовка видимо шла дольше 20 мс — в результате очередь сообщений забивалась этими Invalidate-ми под завязку. А поскольку таймер — в той же очереди, то неудивительно, что он стал работать с перерывами. Ты сам его и затормозил.

Я же предлагаю делать Paint в таймере, а в OnPaint контрола ничего не делать — все равно таймер работает часто.

Хотя сам бы я делал по другому: я в конце OnPaint запускал бы серверный таймер на 20 мс, который бы бросил Invalidate.
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 27.04.06 08:18
Оценка: +1
Здравствуйте, Andrbig, Вы писали:

A> Рабочий поток не должен заниматься рисованием, его задача — сгенерить данные.


сорри за неточную формулировку поток занимается не "рисованием", а "генерацией" битмапов, которые должны быть отрисованы в окне, битмапы это данные которые он генерит
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 27.04.06 08:41
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Сравни то что ты делал с тем что я предложил. Ты каждые 20мс бросал invalidate, а отрисовка видимо шла дольше 20 мс — в результате очередь сообщений забивалась этими Invalidate-ми под завязку. А поскольку таймер — в той же очереди, то неудивительно, что он стал работать с перерывами. Ты сам его и затормозил.


скорее всего так и есть

A>Я же предлагаю делать Paint в таймере, а в OnPaint контрола ничего не делать — все равно таймер работает часто.

A>Хотя сам бы я делал по другому: я в конце OnPaint запускал бы серверный таймер на 20 мс, который бы бросил Invalidate.

попробую последний вариант... спасибо
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Кремер Евгений Германия  
Дата: 27.04.06 16:27
Оценка:
Здравствуйте,

>При таком раскладе не надо никому ничего сообщать. Заведи таймер, срабатывающий так часто, как тебе надо. Таймер возьмет последние данные от рабочего потока и их отрисует. Все, не надо никаких усложнений.


Возможно это не вызывает никаких усложнений для программиста, а для процессора всё же.
Обязательная перерисовка формы, не зависимо от того обновились ли данные или нет, теряем драгоценные такты рабочего потока!
Я попробовал только что и не смог уловить синхронность invalidate();. Я перед вызовом этой функции установил breakpoint в onpaint(), вызвал её и никакого перехода в onpaint() не произошло, только после завершения текущей процедуры произошёл переход в onpaint(), что говорит об асинхронности. Я бы выбрал вариант с invalidate.
Если нет надобности в рисовании всех изображений, а только в их производстве, напрашивается вопрос "а зачем они тогда?".

А как Вы рисуете, А где (метод) рисуете, А что Вам вдействительности важно рисовать или производить?
Posted via RSDN NNTP Server 2.0
Re: Как сделать перерисовку формы максимально быстрой
От: WolfHound  
Дата: 27.04.06 18:32
Оценка: 2 (1)
Здравствуйте, Streamer1, Вы писали:

Ну както так:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace TMDraw
{
    public static class Program
    {
        public class Generator
        {
            object m_Lock = new object();
            List<Bitmap> m_Ready = new List<Bitmap>();
            List<Bitmap> m_Ret = new List<Bitmap>();
            Font m_Font = new Font(FontFamily.GenericMonospace, 15, FontStyle.Bold);

            public Generator()
            {
                for (int i = 0; i < 3; ++i)
                {
                    Bitmap bm = new Bitmap(100, 100);
                    Draw(bm);
                    m_Ready.Add(bm);
                }
            }

            public void Work()
            {
                while (true)
                {
                    Bitmap bm;
                    lock (m_Lock)
                    {
                        if (m_Ret.Count > 0)
                        {
                            bm = m_Ret[0];
                            m_Ret.RemoveAt(0);
                        }
                        else
                        {
                            bm = m_Ready[0];
                            m_Ready.RemoveAt(0);
                        }
                    }
                    Draw(bm);
                    lock (m_Lock)
                    {
                        m_Ready.Add(bm);
                    }
                }
            }

            public Bitmap GetBitmap()
            {
                lock (m_Lock)
                {
                    Bitmap bm;
                    if (m_Ready.Count > 0)
                    {
                        bm = m_Ready[m_Ready.Count - 1];
                        m_Ready.RemoveAt(m_Ready.Count - 1);
                    }
                    else
                    {
                        bm = m_Ret[m_Ret.Count - 1];
                        m_Ret.RemoveAt(m_Ret.Count - 1);
                    }
                    return bm;
                }
            }

            public void ReturnBitmap(Bitmap bm)
            {
                lock (m_Lock)
                {
                    m_Ret.Add(bm);
                }
            }

            int frames = 0;
            float f = 0;
            void Draw(Bitmap bm1)
            {
                frames++;
                f += 0.01f;
                if (f > 100)
                    f = 0;
                using (Graphics g = Graphics.FromImage(bm1))
                {
                    g.Clear(Color.Gold);
                    g.DrawLine(Pens.Red, 0, 0, f, f);
                    g.DrawString(frames.ToString(), m_Font, Brushes.Black, 0, 0);
                }
            }
        }

        static void Main()
        {
            Generator g = new Generator();
            Thread t = new Thread(g.Work);
            try
            {
                t.Start();

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1(g));
            }
            finally
            {
                t.Abort();
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace TMDraw
{
    public partial class Form1 : Form
    {
        Program.Generator g;
        public Form1(Program.Generator g)
        {
            this.g = g;
            InitializeComponent();
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            //base.OnPaintBackground(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Bitmap bm = g.GetBitmap();
            e.Graphics.DrawImage(bm, 0, 0, Width, Height);
            g.ReturnBitmap(bm);
            Invalidate();
            Thread.Sleep(1);//Это важно иначе этот поток будет глушить генерирующий поток
        }
    }
}
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 27.04.06 22:39
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>Приложение почти рилтайм частота перерисовки формы >= 50 раз в секунду.


А смысл ? Свыше 24 кадров всё одно человек не увидит Так что требование понижаем до 30 раз — уже легче.

Ну а если всё-таки надо свыше 50 fps — смотрим в сторону DirectX/OpenGL и не напрягаем бедный процессор
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 07:05
Оценка:
Здравствуйте, <Аноним>, Вы писали:

S>>Приложение почти рилтайм частота перерисовки формы >= 50 раз в секунду.


А>А смысл ? Свыше 24 кадров всё одно человек не увидит Так что требование понижаем до 30 раз — уже легче.


очень даже большой смысл, достаточно уменьшить частоту с 50 Гц до 49 и все, конец света бегущая строка уже будет дергатся, а ты говоришь "всё одно человек не увидит", еще как увидит!

А>Ну а если всё-таки надо свыше 50 fps — смотрим в сторону DirectX/OpenGL и не напрягаем бедный процессор


c Managed DirectX еще не разобрался, DirectDraw зачемто выкинули (деприцировали так сказать ), надо через Direct3D делать...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 07:14
Оценка:
Здравствуйте, Кремер Евгений, Вы писали:

КЕ>Здравствуйте,


>>При таком раскладе не надо никому ничего сообщать. Заведи таймер, срабатывающий так часто, как тебе надо. Таймер возьмет последние данные от рабочего потока и их отрисует. Все, не надо никаких усложнений.


КЕ>Возможно это не вызывает никаких усложнений для программиста, а для процессора всё же.

КЕ>Обязательная перерисовка формы, не зависимо от того обновились ли данные или нет, теряем драгоценные такты рабочего потока!
КЕ>Я попробовал только что и не смог уловить синхронность invalidate();. Я перед вызовом этой функции установил breakpoint в onpaint(), вызвал её и никакого перехода в onpaint() не произошло, только после завершения текущей процедуры произошёл переход в onpaint(), что говорит об асинхронности. Я бы выбрал вариант с invalidate.

на счет асинхронности я бы так не говорил, может по брейкпоинту этого и не видно, но Invalidate реально управление возвращает только тогда когда отрисовка уже произойдет... что сильно замедляет генерирующий поток, т.к. вызов Invalidate вызывается в нем...


КЕ>Если нет надобности в рисовании всех изображений, а только в их производстве, напрашивается вопрос "а зачем они тогда?".


КЕ>А как Вы рисуете, А где (метод) рисуете, А что Вам вдействительности важно рисовать или производить?


надобность есть в рисовании всех изображений, но при растягивании окна на отрисовку всех изображений скорости не хватает, а генерирующий битмапы поток жестко привязан ко времени и его задержки приводят к дестабилизации скорости. Генерирующий поток кроме битмапов генерирует в рилтайме звук и синхронизация его скорости производится именно по звуку. В таком контексте задержка потока вызовет треск в динамиках и резкое замедление программы.
Поэтому в отрисовке, при нехватке производительности, можно пожертвовать одним кадром — на медленных машинах редкое выпадание одного кадра в глаза бросаться не будет.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Кремер Евгений Германия  
Дата: 28.04.06 08:21
Оценка:
>на счет асинхронности я бы так не говорил, может по брейкпоинту этого и не видно, но Invalidate реально управление возвращает только тогда когда отрисовка уже произойдет... что сильно замедляет генерирующий поток, т.к. вызов Invalidate вызывается в нем...

а как вы вызываете invalidate() из другого потока (invoke, begininvoke ...)? я правда ничего не нашел в справке сдк о необходимости синхронизировать этот вызов из другого потока, но увидел подтверждение его асинхронности, а для синхронного рисования там рекомендуется Update. Как конечно МС это реализовало спорить не берусь.

>надобность есть в рисовании всех изображений...


Тогда можно было бы попробовать PostMessage c WM_USER+n, а в обработчике проверять флаг был ли битмап уже прорисован, на случай если в очереди стояли сразу 2 сообщения и первое рисовало последний битмап, а не то для которого оно было отправлено. За асинхронность не отвечаю, но лишнее рисование избежать точно можно.
Posted via RSDN NNTP Server 2.0
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Дмитрий Наумов  
Дата: 28.04.06 08:51
Оценка:
Здравствуйте, Andrbig, Вы писали:

A>Сравни то что ты делал с тем что я предложил. Ты каждые 20мс бросал invalidate, а отрисовка видимо шла дольше 20 мс — в результате очередь сообщений забивалась этими Invalidate-ми под завязку. А поскольку таймер — в той же очереди, то неудивительно, что он стал работать с перерывами. Ты сам его и затормозил.


A>Я же предлагаю делать Paint в таймере, а в OnPaint контрола ничего не делать — все равно таймер работает часто.


A>Хотя сам бы я делал по другому: я в конце OnPaint запускал бы серверный таймер на 20 мс, который бы бросил Invalidate.


Маленькое уточнение: очередь забивается WM_PAINT'ами, которые "появляются" в результате вызова Invalidate. В очереди, не помню точно то ли подряд, то ли вообще, два WM_PAINT'а "не живут", они "сокращаются"
Сообщение WM_TIMER "ставится" в очередь очень хитро и там есть некоторые условия, одно из которых, например, если в очереди есть WM_PAINT, то WM_TIMER "ставится" не будет, пока не обработается WM_PAINT. Из этого следует:
1. Генерить прямо или косвенно сообщения WM_PAINT из обработчика WM_TIMER рискованно.
2. Расчитывать на точность WM_TIMER наивно
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 17:11
Оценка:
Здравствуйте, Кремер Евгений, Вы писали:

>>на счет асинхронности я бы так не говорил, может по брейкпоинту этого и не видно, но Invalidate реально управление возвращает только тогда когда отрисовка уже произойдет... что сильно замедляет генерирующий поток, т.к. вызов Invalidate вызывается в нем...


КЕ>а как вы вызываете invalidate() из другого потока (invoke, begininvoke ...)? я правда ничего не нашел в справке сдк о необходимости синхронизировать этот вызов из другого потока, но увидел подтверждение его асинхронности, а для синхронного рисования там рекомендуется Update. Как конечно МС это реализовало спорить не берусь.


вначале вызывался просто mainForm.Invalidate(), сейчас через BeginInvoke, но не помогло...
возможно конечно проблема гдето в другом месте, сейчас алгоритм точно не помню нужно глянуть...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 18:32
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

ДН>Маленькое уточнение: очередь забивается WM_PAINT'ами, которые "появляются" в результате вызова Invalidate. В очереди, не помню точно то ли подряд, то ли вообще, два WM_PAINT'а "не живут", они "сокращаются"

ДН>Сообщение WM_TIMER "ставится" в очередь очень хитро и там есть некоторые условия, одно из которых, например, если в очереди есть WM_PAINT, то WM_TIMER "ставится" не будет, пока не обработается WM_PAINT. Из этого следует:
ДН>1. Генерить прямо или косвенно сообщения WM_PAINT из обработчика WM_TIMER рискованно.
ДН>2. Расчитывать на точность WM_TIMER наивно

Хм, похоже дело именно в связи WM_PAINT и WM_TIMER, а как же быть?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Как сделать перерисовку формы максимально быстрой
От: WolfHound  
Дата: 28.04.06 20:53
Оценка:
Здравствуйте, Streamer1, Вы писали:

А чем тебе мое решение не нравится?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 23:20
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>А чем тебе мое решение не нравится?


спасибо

я еще просто не разбирался в чем там смысл...
в runtime и при беглом осмотре сырцов выглядит заманчиво, но еще не понял насколько подходит под мою задачу, у меня задача не столько в генерации битмапа , сколько в быстрой асинхронной отрисовке его, отрисовке инициируемой генерирующим потоком. Цель минимальное время на вызов функции которая запустит в основном потоке программы отрисовку.

сейчас делается так:

в паралельном потоке крутится куча всякой всячины с отрисовкой битмапа, есть метод который рисует доступный в данный момент для рисования битмап:

      public override void DrawScreen(Graphics g, Rectangle rect)
      {
         ScreensSemaphore.WaitOne();
         g.DrawImage(Screens[CurrentScreen ^ 1], rect);
         ScreensSemaphore.Release();
      }


текущий битмап меняется генерирующим потоком:

      private unsafe void DrawUpdate()                               // dynamic update screen
      {
         if (pBase != null)
         {
            ScreensSemaphore.WaitOne();
            Screens[CurrentScreen].UnlockBits(bd);
            CurrentScreen ^= 1;
            ScreensSemaphore.Release();
         }
         if (UpdateSCR != null)
            UpdateSCR();
         Rectangle rect = new Rectangle(0, 0, ScreenWidth, ScreenHeight);
         bd = Screens[CurrentScreen].LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
         pBase = (Int32*)bd.Scan0.ToPointer();
      }


в промежутках между вызовами DrawUpdate производится создание битмапа используя указатель pBase

вот собственно код делегата UpdateSCR, который находится в основной форме:

      private void UpdateSCR()
      {
         Interlocked.Increment(ref FrameCount);
         ProcessInvalidateForm pif = new ProcessInvalidateForm();
         InvalidatingAsyncDelegate id = new InvalidatingAsyncDelegate(pif.InvalidateForm);
         id.BeginInvoke(this, null, null);
      }
....
   public delegate void InvalidatingAsyncDelegate(Form form);
   public class ProcessInvalidateForm
   {
      public void InvalidateForm(Form form)
      {
         form.Invalidate();
      }
   }


пока просматривал код заметил что DrawScreen может заблокировать поток через семафор...
наверно с этим и связано торможение потока...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 28.04.06 23:26
Оценка:
Здравствуйте, Streamer1, Вы писали:

саму прогу можно посмотреть скачав ZXMAK.NET с сайта http://zx.da.ru (раздел эмуляторы) в рефлекторе можно код порассматривать, а то если все сюда запостить то ругаться будут, там 380 кб кода...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Как сделать перерисовку формы максимально быстрой
От: WolfHound  
Дата: 29.04.06 08:53
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>я еще просто не разбирался в чем там смысл...

Там все дело в том что заводим 3 битмапа в один генерируем новое изображение, из другого рисуем на экран, а третий для того чтобы потоки друг друга не ждали. Хранение битмапов организовано так что на экран выводят всегда самый новый битмап, а рисуют всегда в самый старый.
S>в runtime и при беглом осмотре сырцов выглядит заманчиво, но еще не понял насколько подходит под мою задачу, у меня задача не столько в генерации битмапа , сколько в быстрой асинхронной отрисовке его, отрисовке инициируемой генерирующим потоком. Цель минимальное время на вызов функции которая запустит в основном потоке программы отрисовку.
Если тебе нужно чтобы именно генерирующий поток инициировал отрисовку на экран то тогда так
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace TMDraw
{
    public static class Program
    {
        public class Generator
        {
            object m_Lock = new object();
            List<Bitmap> m_Ready = new List<Bitmap>();
            Font m_Font = new Font(FontFamily.GenericMonospace, 15, FontStyle.Bold);

            public delegate void StartUpdate();
            StartUpdate m_StartUpdate;

            public Generator()
            {
                for (int i = 0; i < 3; ++i)
                {
                    Bitmap bm = new Bitmap(100, 100);
                    Draw(bm);
                    m_Ready.Add(bm);
                }
            }

            public void Init(StartUpdate startUpdate)
            {
                m_StartUpdate = startUpdate;
            }

            public void Work()
            {
                while (true)
                {
                    Bitmap bm;
                    lock (m_Lock)
                    {
                        bm = m_Ready[0];
                        m_Ready.RemoveAt(0);
                    }
                    Draw(bm);
                    lock (m_Lock)
                    {
                        m_Ready.Add(bm);
                    }
                    m_StartUpdate();
                }
            }

            public Bitmap GetBitmap()
            {
                lock (m_Lock)
                {
                    Bitmap bm = m_Ready[m_Ready.Count - 1];
                    m_Ready.RemoveAt(m_Ready.Count - 1);
                    return bm;
                }
            }

            public void ReturnBitmap(Bitmap bm)
            {
                lock (m_Lock)
                {
                    m_Ready.Insert(0, bm);
                }
            }

            int frames = 0;
            float f = 0;
            void Draw(Bitmap bm1)
            {
                frames++;
                f += 0.01f;
                if (f > 100)
                    f = 0;
                using (Graphics g = Graphics.FromImage(bm1))
                {
                    g.Clear(Color.Gold);
                    g.DrawLine(Pens.Red, 0, 0, f, f);
                    g.DrawString(frames.ToString(), m_Font, Brushes.Black, 0, 0);
                }
            }
        }

        static void Main()
        {
            try
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                Generator g = new Generator();
                Form1 form = new Form1();
                g.Init(delegate()
                {
                    form.BeginInvoke((Generator.StartUpdate)delegate()
                    {
                        if (!form.IsDisposed)
                            form.Update(g);
                    });
                });
                Thread t = new Thread(g.Work);
                try
                {
                    t.Start();
                    Application.Run(form);
                }
                finally
                {
                    t.Abort();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace TMDraw
{
    public partial class Form1 : Form
    {
        Program.Generator m_Generator = null;
        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (m_Generator != null)
            {
                Bitmap bm = m_Generator.GetBitmap();
                e.Graphics.DrawImage(bm, ClientRectangle);
                m_Generator.ReturnBitmap(bm);
                m_Generator = null;
            }
        }

        internal void Update(Program.Generator g)
        {
            if (m_Generator == null)
            {
                m_Generator = g;
                Invalidate();
            }
        }
    }
}
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Как сделать перерисовку формы максимально быстрой
От: FR  
Дата: 29.04.06 16:51
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>Здравствуйте, Streamer1, Вы писали:


S>саму прогу можно посмотреть скачав ZXMAK.NET с сайта http://zx.da.ru (раздел эмуляторы) в рефлекторе можно код порассматривать, а то если все сюда запостить то ругаться будут, там 380 кб кода...


А тебе зачем все делать именно в отдельном потоке?
Эмулятор как я понимаю вещь близкая к играм, может лучше и сделать как в большинстве игр, все расчеты в основном цикле, и без остановки на ожидание сообщений. Как это сделать для C# можно посмотреть например тут http://rsdn.ru/forum/Message.aspx?mid=1837856&amp;only=1
Автор: mukhomor
Дата: 07.04.06
(второй способ)
Re[10]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 29.04.06 16:55
Оценка:
Здравствуйте, FR, Вы писали:


FR>А тебе зачем все делать именно в отдельном потоке?

FR>Эмулятор как я понимаю вещь близкая к играм, может лучше и сделать как в большинстве игр, все расчеты в основном цикле, и без остановки на ожидание сообщений. Как это сделать для C# можно посмотреть например тут http://rsdn.ru/forum/Message.aspx?mid=1837856&amp;only=1
Автор: mukhomor
Дата: 07.04.06
(второй способ)


а как же оконный интерфейс? если мессаджи не обрабатывать будет не очень удобно...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[11]: Как сделать перерисовку формы максимально быстрой
От: FR  
Дата: 29.04.06 17:03
Оценка: 1 (1)
Здравствуйте, Streamer1, Вы писали:

S>Здравствуйте, FR, Вы писали:



FR>>А тебе зачем все делать именно в отдельном потоке?

FR>>Эмулятор как я понимаю вещь близкая к играм, может лучше и сделать как в большинстве игр, все расчеты в основном цикле, и без остановки на ожидание сообщений. Как это сделать для C# можно посмотреть например тут http://rsdn.ru/forum/Message.aspx?mid=1837856&amp;only=1
Автор: mukhomor
Дата: 07.04.06
(второй способ)


S>а как же оконный интерфейс? если мессаджи не обрабатывать будет не очень удобно...


Там все нормально обрабатывается.
Re[12]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 29.04.06 17:11
Оценка:
Здравствуйте, FR, Вы писали:

FR>>>тут http://rsdn.ru/forum/Message.aspx?mid=1837856&amp;only=1
Автор: mukhomor
Дата: 07.04.06
(второй способ)


S>>а как же оконный интерфейс? если мессаджи не обрабатывать будет не очень удобно...


FR>Там все нормально обрабатывается.


интерересная ветка, спасибо за ссылку
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Как сделать перерисовку формы максимально быстрой
От: 4erniyPlasch Россия  
Дата: 02.05.06 11:09
Оценка:
Здравствуйте, Дмитрий Наумов, Вы писали:

ДН>Маленькое уточнение: очередь забивается WM_PAINT'ами, которые "появляются" в результате вызова Invalidate. В очереди, не помню точно то ли подряд, то ли вообще, два WM_PAINT'а "не живут", они "сокращаются"

ДН>Сообщение WM_TIMER "ставится" в очередь очень хитро и там есть некоторые условия, одно из которых, например, если в очереди есть WM_PAINT, то WM_TIMER "ставится" не будет, пока не обработается WM_PAINT. Из этого следует:
ДН>1. Генерить прямо или косвенно сообщения WM_PAINT из обработчика WM_TIMER рискованно.
ДН>2. Расчитывать на точность WM_TIMER наивно

Откуда информация. Можно ссылку — интересно почитать.
Спасибо.
Re: Как сделать перерисовку формы максимально быстрой
От: KindDog Россия  
Дата: 02.05.06 13:23
Оценка:
Привет!
а ты не пробовал при входе в процедуру таймера тормознуть его вызов, а по выходу из нее запустить таймер снова?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Как сделать перерисовку формы максимально быстрой
От: Дмитрий Наумов  
Дата: 02.05.06 15:15
Оценка:
Здравствуйте, 4erniyPlasch, Вы писали:

P>Откуда информация. Можно ссылку — интересно почитать.

P>Спасибо.

Из головы, MSDN и блог Old New Thing
Re: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 27.04.06 23:53
Оценка:
Не люблю рсдновские флуды, но ладно. Сам сегодня (хммм, скорее вчера) похожей ерундой занимался.

Так вот. Ответ оказался элементарен — а никак не получится через GDI/GDI+. Даже с супербыстрыми битмапами. Даже с насильной двойной буферизацией. Кадров 5-10 получишь, дальше никак. Про показ в большом разрешении можно забыть сразу.

Попробуй включить у формы (если дотнеть вторая) двойную буферизацию (свойство есть такое у формы, если вдруг не в курсе).

Я делал свой PictureBox со стилем DoubleBuffer=true.

Конечно быстрее рисует, но не настолько, насколько нужно было.

Короче это только через DirectX/OpenGL можно сделать. На это меня уже не хватило. Может сегодня попробую.

The speed of processors doubles every 18 months" -- Moore's law
"The speed of software halves every 18 months" -- Gates' law .


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 28.04.06 07:54
Оценка: -1
>>очень даже большой смысл, достаточно уменьшить частоту с 50 Гц до 49 и все, конец света бегущая строка уже будет дергатся,

А ты знаешь, почему так происходит?

Да просто потому, что твое чудо даже 25 кадров в секунду не дает! хорошо, если 5 реально. Человек действительно не видит больше 25 кадров, так же как и не различает даже 64К цветов. Все FPSы в тестах — маркетинговая фигня для "меренья, у кого больше".

Поставь для начала частоту развертки монитор на 85 герц, как минимум. Простые люди не в курсе, что ее можно менять. Много раз убеждался.Так несчастные и работают на 50-60 герцах, гробя свое зрение и получая головную боль по вечерам.
The speed of processors doubles every 18 months" -- Moore's law
"The speed of software halves every 18 months" -- Gates' law .


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 28.04.06 07:59
Оценка:
>>Invalidate реально управление возвращает только тогда когда отрисовка уже произойдет... что сильно замедляет генерирующий поток, т.к. вызов Invalidate вызывается в нем...


Уууу, как всё запущено-то... Зачемже ты его вызываешь там? Так он там и выполняется! Про BeginInvoke слышал? Твой генератор должен только СООБЩИТЬ форме, что генерация закончена и надо перерисоваться. Но никак не вызывать саму прорисовку.

ЗЫ: Ты двойную буфферизацию контролов включил?

The speed of processors doubles every 18 months" -- Moore's law
"The speed of software halves every 18 months" -- Gates' law .


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 28.04.06 08:13
Оценка:
оО народ вы чё. С GDI можно сделайть прорисовку.
во первых ф-ия SetDIBitsToDevice. Во вторых убрать обработку wm_erasebackground (WndPrc). И DoubleBuffer ни в коем случае не включать. Тогда прорисовка будет быстрой.

А насчет метода Invalidate — он не обвновляет окно при частом вызове. Чтобы окно точно обновилось в нужный момент — вызывайте Refresh().

Кстати BlackTigerAP ты видел хоть раз анимацию с 25fps? И вообще действительно, зачем же надо больше 30фпс то? *ушёл думать*


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[6]: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 03.05.06 03:01
Оценка:
Увеличением FPS уменьшения мерцания не добиться.
Попробуй поизвращаться с чем-то типа:
  class Canvas: Panel
  {
    private Bitmap bmpCanvas;
    public Canvas()
    {

      this.SetStyle(ControlStyles.UserPaint, true);
      this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
      this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      this.SetStyle(ControlStyles.ResizeRedraw, true);
      bmpCanvas = new Bitmap(this.Width, this.Height);
    }
    protected override void OnSizeChanged(EventArgs e)
    {
      base.OnSizeChanged(e);
      bmpCanvas = new Bitmap(bmpCanvas, Size.Width, Size.Height);
    }
    public Bitmap CanvasBitmap { get { return bmpCanvas; } }
    public Graphics CanvasGraphics { get { return Graphics.FromImage(bmpCanvas); } }
    protected override void OnPaint(PaintEventArgs e)
    {
      e.Graphics.FillRectangle(new SolidBrush(BackColor), e.ClipRectangle);
      e.Graphics.DrawImage(bmpCanvas, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
      #if DEBUG
      e.Graphics.DrawString(DateTime.Now.ToString("HH:mm:ss.ff"), Font, Brushes.Red, PointF.Empty);
      #endif
      base.OnPaint(e);
    }
  }


Набросал сейчас, надо только доработать OnSizeChanged, сейчас при ресайзе изображение очищается — фича

Эмпирическое изучение граблей высоких энергий несколько затруднено…


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 07:53
Оценка: +1
Здравствуйте, BlackTigerAP, Вы писали:

BTA>Да просто потому, что твое чудо даже 25 кадров в секунду не дает! хорошо, если 5 реально. Человек действительно не видит больше 25 кадров, так же как и не различает даже 64К цветов. Все FPSы в тестах — маркетинговая фигня для "меренья, у кого больше".


правда? может не 25, а 25.00000000002 ?

я бы на твоем месте не стал раскидыватся такими высказываниями, потому что:

1. Сам глаз вполне справляется с частотами 200 и более гц, но мозг так устроен что сознательно мы плохо различаем (это не значит что совсем не различаем!) таких частот, т.к. справлятся с таким потоком информации на уровне сознания мозг не способен... Впрочем мозгу это вполне посилам на подсознательном уровне...

2. нет четкой границы в 25 или 50 Гц, чем выше частота тем меньше мелькающих деталей различает глаз, однако это не значит что он совсем перестает все замечать, глаз способен различить мерцание даже с частотой 100-150 Гц... я например очень даже вижу мерцание дисплея с частотой обновления 100 Гц

3. Различные области сечатки глаза имеют различную чувствительность к частотам, центральная область (основное зрение) довольно четко различает мерцание в 70-80 Гц, а вот периферическое зрение очень даже неплохо справляется с частотами >150 Гц... Это связано с тем что на периферическое зрение возлагается несколько инные задачи (детектирование каких либо изменений), а на основное — получение информации...

4. Следует учитывать что люминофор в дисплеях имеет некоторое послесвечение, что следует учитывать, т.к. при частоте 150 Гц пикселы уже не гаснут, а только меняятеся (в определенной степени) яркость их свечения, а у глаза есть еще чувствительность к разности изменения яркости в зависимости от частоты...

5. О количестве различаемых цветов стоит говорить обозначив о каких цветах речь — излучаемых или отражаемых?
Человеческое зрение в среднем различает порядка 16 млн цветов для излученного света и порядка 30-60 млн цветов (!) для отраженного света... а вы говорите 64к цветов
Кстати при 32bit цвете, если присмотрется, то можно заметить границы переходов цветов на самом плавном градиенте...

ну и кроме того, параметры глаза у каждого человека разные, я говорил о среднестатистических...

BTA>Поставь для начала частоту развертки монитор на 85 герц, как минимум. Простые люди не в курсе, что ее можно менять. Много раз убеждался.Так несчастные и работают на 50-60 герцах, гробя свое зрение и получая головную боль по вечерам.


Ты недавно узнал что есть такая штука как частота обновления дисплея? К сожалению моя видеокарта не поддерживает частоту 50 Гц...

А вообще частота выбирается не от балды и не по максимуму, а в зависимости от нужд... Несоответствие частоты обновления источника и частоты обновления дисплея приведет к ОЧЕНЬ ЗАМЕТНЫМ (!) биениям, даже при частоте обновления 150 Гц, т.к. в этой ситуации мозгу достаточно не идентифицировать объекты, а лишь детектировать нарушения в порядке следования деталей изображения, на что большой скорости обработки не нужно...

Никогда не задумывался, почему фильмы переписанные из формата NTSC 60Гц в формат PAL 50Гц (и обратно!) выглядят как дерганные при движениях объектов изображения?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 07:53
Оценка:
Здравствуйте, BlackTigerAP, Вы писали:

>>>Invalidate реально управление возвращает только тогда когда отрисовка уже произойдет... что сильно замедляет генерирующий поток, т.к. вызов Invalidate вызывается в нем...



BTA>Уууу, как всё запущено-то... Зачемже ты его вызываешь там? Так он там и выполняется! Про BeginInvoke слышал? Твой генератор должен только СООБЩИТЬ форме, что генерация закончена и надо перерисоваться. Но никак не вызывать саму прорисовку.


ты угадал, у меня используется BeginInvoke

BTA>ЗЫ: Ты двойную буфферизацию контролов включил?


да, двойная буферизация контролов + двойная буферизация при выводе итого буферизация можно считать 4x
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 07:53
Оценка:
Здравствуйте, McCulic, Вы писали:

MC>оО народ вы чё. С GDI можно сделайть прорисовку.

MC>во первых ф-ия SetDIBitsToDevice. Во вторых убрать обработку wm_erasebackground (WndPrc). И DoubleBuffer ни в коем случае не включать. Тогда прорисовка будет быстрой.

про DoubleBuffer это зависит от реализации (точнее прямоты рук ), у меня его включение на скорость никак не уменьшает...

MC>А насчет метода Invalidate — он не обвновляет окно при частом вызове. Чтобы окно точно обновилось в нужный момент — вызывайте Refresh().


да? а у меня почемуто Invalidate отлично все обновляет с частотами до 120 Гц... кадры не теряются...
а с рефрешем будут дикие тормоза... т.к. Invalidate это почти прямой вызов API, а refresh это куча всякой фигни в библиотеках + Invalidate

MC>Кстати BlackTigerAP ты видел хоть раз анимацию с 25fps? И вообще действительно, зачем же надо больше 30фпс то? *ушёл думать*


для видео
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 07:55
Оценка:
Здравствуйте, BlackTigerAP, Вы писали:

BTA>Так вот. Ответ оказался элементарен — а никак не получится через GDI/GDI+. Даже с супербыстрыми битмапами. Даже с насильной двойной буферизацией. Кадров 5-10 получишь, дальше никак. Про показ в большом разрешении можно забыть сразу.


зачем же так сразу посмотри ZXMAK.NET — вся графика на чистом C#, а спокойно дает до 100 Гц (там частота насильно ограничивается до 50)...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 07:57
Оценка:
Здравствуйте, KindDog, Вы писали:

KD>а ты не пробовал при входе в процедуру таймера тормознуть его вызов, а по выходу из нее запустить таймер снова?


пробовал — не помогло...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Как сделать перерисовку формы максимально быстрой
От: Аноним  
Дата: 04.05.06 12:29
Оценка:
Здравствуйте, Streamer1, Вы писали:

S>зачем же так сразу посмотри ZXMAK.NET — вся графика на чистом C#, а спокойно дает до 100 Гц (там частота насильно ограничивается до 50)...


А думаешь зачем ограничивается частота насильно ?

Вообще проблема мерцания изображения даже при двойной буферизации заключается как раз в том, что при отрисовке формы Windows похоже чихать хотел на вертикальную синхронизацию. Для OpenGL/DirectX приложений существует опция (в свойствах драйвера видеокарты), при включении которой она включается. Естественно она понижает fps до частоты обновления монитора.(у меня это 85 Гц= 85 fps MAX) Так как её смысл это синхронизация записи в видеопамять с отрисовкой на экране, т.е. пока кадр не отобразится на мониторе полностью изменять видеопамять запрещено, чтобы избежать эффекта мерцания. Сейчас вот запустил NFS MW с включенной wait for vblank и без неё, разница заметна налицо.

з.ы. Неужели ты на глаз способен отличить видео 24 и 30 fps (PAL и NTSC) ?
Re[4]: Как сделать перерисовку формы максимально быстрой
От: Streamer1 Украина  
Дата: 04.05.06 13:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:


А>А думаешь зачем ограничивается частота насильно ?


Прикольно когда объясняют почему я ограничил частоту...
все довольно просто — спектрум подключается к телевизору, у телевизора 50 Гц, если частота отрисовки будет другая, то будут наблюдатся непрятные биения на различных скроллерах которых там полно...
Идеальная частота обновления дисплея там будет 100 Гц (50*2)...
Биения там и так есть (50 Гц недостаточно надо делать и ресамплинг под частоту дисплея, если она не кратна 50) но они не так заметны как при отличной от 50 Гц... Ну и кроме того просто удобно именно до 50 Гц ограничивать а не до 49, т.к. 50 Гц не влечет проблем с ускорением/замедлением программ...

А>з.ы. Неужели ты на глаз способен отличить видео 24 и 30 fps (PAL и NTSC) ?


отличить 24 и 30 сложно, т.к. и то и то мерцает, а разница мерцания отличается несильно. Хорошо заметно если PAL в NTSC перевести или обратно...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.