Double Buffering в System.Windows.Forms.Control
От: McSeem2 США http://www.antigrain.com
Дата: 22.10.02 19:04
Оценка:
Вопрос не совсем обычный и касается "кишков" .NET.

Я делаю свой контрол и включаю в SetStyle DoubleBuffer чтобы не мельтешило. Рисую простую и короткую линию и прямоугольник на все окно. При этом в OnPaint все перерисовывается по-новой.
Далее. Как известно, в C++-ном GDI+ (тот который в обычном C++, про managed не уверен, но в хелпе тоже ничего не нашел), единственный способ сделать двойную буферизацию — это сделать ее вучную. То есть, типа:

   Bitmap bmp(rect.right,rect.bottom);

   // Create a Graphics object that is associated with the image.
   Graphics* graphBmp = Graphics::FromImage(&bmp);
   
   //. . . Draw a line into graphBmp
   //. . . Draw a rectangle into graphBmp

   // Draw the altered image.
   graphics.DrawImage(&bmp, rect.left, rect.top, rect.right, rect.bottom);
   delete graph;


Так вот, контрол с двойным буфером рисует значительно быстрее, чем Graphics::DrawImage, и это касается только лишь вывода битмапа на экран, поскольку в данном случае рисование линии и прямоугольника — просто ничто. Можно в конце концов ничего не рисовать — результат тот же. Так вот, можно ли где-нибудь почерпнуть сокровенное знание, как он это делает? Ведь двойная буферизация присутствует и видеобуфер расположен явно в памяти, причем он очень похож на полноценный RGBA, то есть, 32 бита на пиксел. Такой вывод я сделал на основе наблюдений за поедаемой памятью с- и без двойной буферизации.

И вообще, возможно ли отображать большие битмапы значительно быстрее чем BitBlt, SetDIBitsToDevice и прочих низкоуровневых функций?

Меня бы даже устроил вариант получения raw-поинтера на этот буфер, чтобы я сам мог там резвиться. Просто GDI+ меня по некоторым причинам не устраивает (я сам умею ренденить гораздо быстрее и качественнее)

McSeem
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Double Buffering в System.Windows.Forms.Control
От: Joker3D Россия http://blog.trunin.com
Дата: 23.10.02 03:19
Оценка:
Здравствуйте McSeem2, Вы писали:

MS>Вопрос не совсем обычный и касается "кишков" .NET.


MS>Я делаю свой контрол и включаю в SetStyle DoubleBuffer чтобы не мельтешило. Рисую простую и короткую линию и прямоугольник на все окно. При этом в OnPaint все перерисовывается по-новой.

MS>Далее. Как известно, в C++-ном GDI+ (тот который в обычном C++, про managed не уверен, но в хелпе тоже ничего не нашел), единственный способ сделать двойную буферизацию — это сделать ее вучную. То есть, типа:

MS>
MS>   Bitmap bmp(rect.right,rect.bottom);

MS>   // Create a Graphics object that is associated with the image.
MS>   Graphics* graphBmp = Graphics::FromImage(&bmp);
MS>   
MS>   //. . . Draw a line into graphBmp
MS>   //. . . Draw a rectangle into graphBmp

MS>   // Draw the altered image.
MS>   graphics.DrawImage(&bmp, rect.left, rect.top, rect.right, rect.bottom);
MS>   delete graph;
MS>


MS>Так вот, контрол с двойным буфером рисует значительно быстрее, чем Graphics::DrawImage, и это касается только лишь вывода битмапа на экран, поскольку в данном случае рисование линии и прямоугольника — просто ничто. Можно в конце концов ничего не рисовать — результат тот же. Так вот, можно ли где-нибудь почерпнуть сокровенное знание, как он это делает? Ведь двойная буферизация присутствует и видеобуфер расположен явно в памяти, причем он очень похож на полноценный RGBA, то есть, 32 бита на пиксел. Такой вывод я сделал на основе наблюдений за поедаемой памятью с- и без двойной буферизации.


MS>И вообще, возможно ли отображать большие битмапы значительно быстрее чем BitBlt, SetDIBitsToDevice и прочих низкоуровневых функций?


MS>Меня бы даже устроил вариант получения raw-поинтера на этот буфер, чтобы я сам мог там резвиться. Просто GDI+ меня по некоторым причинам не устраивает (я сам умею ренденить гораздо быстрее и качественнее)


MS>McSeem


не могу точно сказать насчет "кишков" .NET, но могу только высказать предпаоложение:
1. контролы могут не ипользовать GDI+ а юзать обычный GDI — это на порядок быстрее.
2. и самое главное — тебе не стоит каждый раз при отрисовке СОЗДАВАТЬ битмапу — т.к. именно ее создание и занимает у тебя почти все время. создавай ее только в первый раз после изменения размеров области отрисовки. т.к. заведи ключик m_bBitmapValid и сбрасывай его на Resize. а в отрисовке проверяй его и если от не валидный то только тогда пересоздавай битмапу. —
..........и не забывай еще клипить битмапный графикс! кстати, тут почему то newGraphics.SetClip( &oldGraphics ) у меня не работало — поэтому я делал
    Gdiplus::Region clipRegion;
    oldGraphics->GetClip( &clipRegion );
    newGraphics.SetClip( &clipRegion );
Konstantin Trunin
http://blog.trunin.com — эффективное управление людьми, проектами, собой
Re[2]: Double Buffering в System.Windows.Forms.Control
От: McSeem2 США http://www.antigrain.com
Дата: 23.10.02 03:59
Оценка:
JD>не могу точно сказать насчет "кишков" .NET, но могу только высказать предпаоложение:
JD>1. контролы могут не ипользовать GDI+ а юзать обычный GDI — это на порядок быстрее.
JD>2. и самое главное — тебе не стоит каждый раз при отрисовке СОЗДАВАТЬ битмапу — т.к. именно ее создание и занимает у тебя почти все время. создавай ее только в первый раз после изменения размеров области отрисовки...

Не катит. Во-первых, речь идет только лишь о выводе битмапа на экран, безо всяких там альфа-блендов даже. GDI+ и GDI в этом смысле ничем по скорости не отличаюся. Во-вторых, если речь идет о битмапе значительного размера, то создание его — ничто по сравнению с CopyDIBitsToDevice (CopyDIBitsToDevice, кстати, работает чуть быстрее, чем BitBlt). В-третьих, в реальности я именно так и делаю, как ты предлагаешь, то есть, пересоздаю только по мере необходимости. Тем не менее, .Net-контролу размером с экран удается выводить себя гораздо быстрее, чем происходит BitBlt. Может они там DirectDraw какой-нибудь задействовали?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: Double Buffering в System.Windows.Forms.Control
От: Joker3D Россия http://blog.trunin.com
Дата: 23.10.02 06:00
Оценка:
Здравствуйте McSeem2, Вы писали:


JD>>не могу точно сказать насчет "кишков" .NET, но могу только высказать предпаоложение:

JD>>1. контролы могут не ипользовать GDI+ а юзать обычный GDI — это на порядок быстрее.
JD>>2. и самое главное — тебе не стоит каждый раз при отрисовке СОЗДАВАТЬ битмапу — т.к. именно ее создание и занимает у тебя почти все время. создавай ее только в первый раз после изменения размеров области отрисовки...

MS>Не катит. Во-первых, речь идет только лишь о выводе битмапа на экран, безо всяких там альфа-блендов даже. GDI+ и GDI в этом смысле ничем по скорости не отличаюся.

отличаются и очеь даже сильно! у меня есть 2 свои проекта-контрола: один старый — использует GDI и рисует через битмапу, другой новый — рисует через Gdiplus::Bitmap (CachedBitmap я тоже пробовал — по скорости выигрыш оказался совсем незначительный, что кстати овольно странно... ) — разница заметна на глаз!!! и это простая отрисока битмапы!!!
(а уж если рисовать без битмапы то тут вообще GDI+ тормозит офигительно — но я предполагаю что это это из-за синхронизации с лучем, которую вроде можно как-то и отключать.. но все равно тогда будет мелькание...)

MS>Во-вторых, если речь идет о битмапе значительного размера, то создание его — ничто по сравнению с CopyDIBitsToDevice (CopyDIBitsToDevice, кстати, работает чуть быстрее, чем BitBlt).

и тут я тоже не согласен. сначала когда я начал работать с GDI+ я создавал битмапу каждый раз при отрисовке (ну просто чтобы быстрее написать) и был сильно поражен его (GDI+) тормозами, а потом немного довел до ума и стал создавать только при первой отрисовке после изменения размера — тогда стало работать раза в 2 быстрее.
.... прямо сейчас проверил еще раз (в свой алгоритм добавил удаление битмапы: m_pBmp.Free() в конце draw) — разница заметна на глаз!!! (у меня просто размер битмапы = 1280x1024x4байта = 5 магабайт надо переработать каждый раз — а это накладно)

MS>В-третьих, в реальности я именно так и делаю, как ты предлагаешь, то есть, пересоздаю только по мере необходимости. Тем не менее, .Net-контролу размером с экран удается выводить себя гораздо быстрее, чем происходит BitBlt. Может они там DirectDraw какой-нибудь задействовали?

они там GDI-обычный задействовали


PS. и вобще я замерял профайлером (DevPartner Profiler) — основные тормоза у меня сейчас идут не на мой алгорим а на GDI+:
1. DrawBitmap
2. FillRectangle
3. DrawRectangle
... и другие GDI+ функции....
поэтому при работе с GDI+ надо очень сильно все оптимизировать, не забывать клипить и рисовать только то, что действительно нужно, не пересоздавая при этому по многу раз битмапы если есть такая возможность.
Konstantin Trunin
http://blog.trunin.com — эффективное управление людьми, проектами, собой
Re: Double Buffering в System.Windows.Forms.Control
От: Ursus Россия  
Дата: 23.10.02 07:05
Оценка:
Здравствуйте McSeem2, Вы писали:



MS>И вообще, возможно ли отображать большие битмапы значительно быстрее чем BitBlt, SetDIBitsToDevice и прочих низкоуровневых функций?


Возможно, смотри в направлении DirectX Для этого в какой то мере егои делали
Да пребудет с тобой Великий Джа
Re[4]: Double Buffering в System.Windows.Forms.Control
От: McSeem2 США http://www.antigrain.com
Дата: 23.10.02 15:40
Оценка:
Здравствуйте Joker3D, Вы писали:

JD>отличаются и очеь даже сильно! у меня есть 2 свои проекта-контрола: один старый — использует GDI и рисует через битмапу, другой новый — рисует через Gdiplus::Bitmap (CachedBitmap я тоже пробовал — по скорости выигрыш оказался совсем незначительный, что кстати овольно странно... ) — разница заметна на глаз!!! и это простая отрисока битмапы!!!


Ладно, колюсь
На самом деле я сравнивал не с GDI+ а с простым BitBlt или CopyDIBitsToDevice. GDI+ я привел только в качестве примера, поскольку народ здесь собрался .Net-ный
Так вот. Время рисования примитивов роли не играет, поскольку примитив-то собственно один — линия (прямоугольник я убрал). Уж одну-то линию он может нарисовать . Код именно тот, что я привел в исходном постинге.
Я специально сравнил с простым GDI, так вот, нет никакой разницы в скорости, что и понятно, поскольку DrawImage вызывает ту же BitBlt, по сравнению с которой накладные расходы на кишки GDI+ — мизер.

А теперь делаем контрол в C#, включаем двойную буферизацию, в OnPaint рисуем ту же одинокую линию — быстрее значительно! Напомню, что речь идет только лишь об отображении буфера на экран — тормозность примитивов мы в данном случае не рассматриваем вообще.
Конфигурация: Dell Inspiron-8100, P3-1.3, GeForce2, Win2K, DevStudio V7.0.9466, .NetFramework V1.0.3705

McSeem
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[2]: Double Buffering в System.Windows.Forms.Control
От: McSeem2 США http://www.antigrain.com
Дата: 23.10.02 15:42
Оценка:
Здравствуйте Ursus, Вы писали:

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


U>


MS>>И вообще, возможно ли отображать большие битмапы значительно быстрее чем BitBlt, SetDIBitsToDevice и прочих низкоуровневых функций?


U>Возможно, смотри в направлении DirectX Для этого в какой то мере егои делали


Означает ли это, что .Net Framework включает в себя DirectX? Что-то слабо верится.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: Double Buffering в System.Windows.Forms.Control
От: Joker3D Россия http://blog.trunin.com
Дата: 23.10.02 16:42
Оценка:
Здравствуйте McSeem2, Вы писали:

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


JD>>отличаются и очеь даже сильно! у меня есть 2 свои проекта-контрола: один старый — использует GDI и рисует через битмапу, другой новый — рисует через Gdiplus::Bitmap (CachedBitmap я тоже пробовал — по скорости выигрыш оказался совсем незначительный, что кстати овольно странно... ) — разница заметна на глаз!!! и это простая отрисока битмапы!!!


MS>Ладно, колюсь

MS>На самом деле я сравнивал не с GDI+ а с простым BitBlt или CopyDIBitsToDevice. GDI+ я привел только в качестве примера, поскольку народ здесь собрался .Net-ный
MS>Так вот. Время рисования примитивов роли не играет, поскольку примитив-то собственно один — линия (прямоугольник я убрал). Уж одну-то линию он может нарисовать . Код именно тот, что я привел в исходном постинге.

повторюсь еще раз: поправь свой код? чтобы не пересоздавать битмапу каждый раз заново. если надо могу запостить пример...

MS>Я специально сравнил с простым GDI, так вот, нет никакой разницы в скорости, что и понятно, поскольку DrawImage вызывает ту же BitBlt, по

"DrawImage вызывает ту же BitBlt" — это неверно!!!! DrawImage гораздо сложнее, умеет пользоваться альфа каналом, стретчить картинку со сглаживанием,
и если передать ImageAttributes то может вообще творить чудеса!
MS>сравнению с которой накладные расходы на кишки GDI+ — мизер.
вовсе и не мизер — у меня в проекте именно DrawImage жрет больше всего процессора!


MS>А теперь делаем контрол в C#, включаем двойную буферизацию, в OnPaint рисуем ту же одинокую линию — быстрее значительно! Напомню, что речь идет только лишь об отображении буфера на экран — тормозность примитивов мы в данном случае не рассматриваем вообще.

да, еще, размер контрола на экране можно узнать — т.к. все тормоза у тебя (имхо) в создании битмапы, то это критично.

плюс еще можно все-таки попробовать использовать Gdiplus::CachedBitmap — вдруг я сделал скорополительные выводы о его тормознутости (вернее скорости сравнимой с Gdiplus::Bitmap) ??

MS>Конфигурация: Dell Inspiron-8100, P3-1.3, GeForce2, Win2K, DevStudio V7.0.9466, .NetFramework V1.0.3705


MS>McSeem


MS>
Konstantin Trunin
http://blog.trunin.com — эффективное управление людьми, проектами, собой
Re[5]: Double Buffering в System.Windows.Forms.Control
От: MaxMP Россия  
Дата: 23.10.02 16:47
Оценка:
Здравствуйте McSeem2, Вы писали:

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

MS>А теперь делаем контрол в C#, включаем двойную буферизацию, в OnPaint рисуем ту же одинокую линию — быстрее значительно! Напомню, что речь идет только лишь об отображении буфера на экран — тормозность примитивов мы в данном случае не рассматриваем вообще.

Если хочется посмотреть, как winforms делает двойную буфферизацию — какие проблемы — берем anakrino или ildasm и смотрим System.Windows.Forms.GraphicsBufferManager.DibGraphicsBufferManager. И видим, что отрисовывает он себя BitBlt'ом.
Re: Double Buffering в System.Windows.Forms.Control
От: Kluge  
Дата: 25.11.02 15:44
Оценка:
Hi McSeem2!

this.SetStyle(ControlStyles.AllPaintingInWmPaint,
          | ControlStyles.ResizeRedraw,
              | ControlStyles.Opaque, true);    
...
protected override void OnPaint(PaintEventArgs pea)
{
    base.OnPaint(pea);
    pea.Graphics.DrawImage(this.iCanvas,
                           pea.ClipRectangle,
                           pea.ClipRectangle,
                           GraphicsUnit.Pixel);
}


Такой вариант у меня отрисовываеться быстрее всего.
Лоботомию в массы! (с)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.