Вопрос не совсем обычный и касается "кишков" .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
Здравствуйте 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 ) у меня не работало — поэтому я делал
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
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
Здравствуйте 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
Здравствуйте Ursus, Вы писали:
U>Здравствуйте McSeem2, Вы писали:
U>
MS>>И вообще, возможно ли отображать большие битмапы значительно быстрее чем BitBlt, SetDIBitsToDevice и прочих низкоуровневых функций?
U>Возможно, смотри в направлении DirectX Для этого в какой то мере егои делали
Означает ли это, что .Net Framework включает в себя DirectX? Что-то слабо верится.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[5]: Double Buffering в System.Windows.Forms.Control
Здравствуйте 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
Здравствуйте McSeem2, Вы писали:
MS>Здравствуйте Joker3D, Вы писали: MS>А теперь делаем контрол в C#, включаем двойную буферизацию, в OnPaint рисуем ту же одинокую линию — быстрее значительно! Напомню, что речь идет только лишь об отображении буфера на экран — тормозность примитивов мы в данном случае не рассматриваем вообще.
Если хочется посмотреть, как winforms делает двойную буфферизацию — какие проблемы — берем anakrino или ildasm и смотрим System.Windows.Forms.GraphicsBufferManager.DibGraphicsBufferManager. И видим, что отрисовывает он себя BitBlt'ом.
Re: Double Buffering в System.Windows.Forms.Control