Yoksel: 20071118БыстраяОтрисовкаGDI ...
SourceForge.net Logo

Home Page | Изменения / НовыеКомментарии / Справка / Помочь проекту | Вход:  Пароль:  

Блог Быстрая отрисовка при помощи GDI


Пока реализовывал поддержку рамок для Йокселя, кое-что накопал. Итак, самое главное требование для реализации быстрой отрисовки очень просто: минимум обращений к GDI. И все будет хорошо.


На практике это означает примерно следующее.

Использование перьев с пользовательскими стилями

У Мокселя есть пара стилей рамок, для которых в стандартном GDI нет предопределенных стилей. Первоначально отрисовку таких рамок я реализовал при помощи обычных «сплошных» (solid) перьев, отрисовывая каждый штрих самостоятельно. В результате на более-менее сложных таблицах тормоза возникали просто неимоверные. Количество вызовов GDI зашкаливало за десятки тысяч. Пришлось перейти на использование пользовательских стилей для перьев. Перо с пользовательским стилем создается через функцию Ext Create Pen?:

В качестве dwPenStyle передаем стиль PS_USERSTYLE, а в lpStyle – массив, определяющий стиль (длина штриха, длина промежутка и т.д.) Правда, PS_USERSTYLE поддерживается только начиная с Windows NT. В результате перехода на перья с пользовательскими стилями количество обращений к GDI сократилось в несколько раз.

Минимизация количества созданий/удалений GDI-объектов

В случае с Йокселем реализация проста. Есть функция Get Pen?, принимающая несколько параметров – свойств пера. Параметры складываются в некоторую простую структуру. Далее структура используется в качестве ключа в обычном std::map. Если элемент с таким ключом отсутствует – перо создается и добавляется в кеш. Если элемент есть – он просто сразу возвращается. Как правило, такой метод производительность повышает просто радикально.

Минимизация количества вызовов функций рисования

Возьмем такую таблицу
ManyBorders.png


Эта таблица легко и просто отрисовывается в Excel. При прокрутке не возникает вообще никаких тормозов. А вот в Йокселе подтормаживание было очень ощутимо. Все объяснялось тем, что Йоксель отрисовывал рамки для каждой ячейки отдельно. Т.е. для таблицы 10х10 ячеек – 100 ячеек – 100 * 4 рамки = 400 рамок отрисовывалось отдельными вызовами GDI. Для исправления ситуации алгоритм отрисовки рамок был существенно изменен. При перерисовке ячеек заполняются две матрицы с данными о рамках: горизонтальные рамки и вертикальные рамки. Далее эти матрицы просто обходятся и анализируются. При этом, если несколько соседних ячеек имеют одинаковый стиль рамки, то рамка для них всех будет отрисована за один вызов GDI. В случае вышеуказанной таблицы 10х10 ячеек понадобится всего 20 вызовов функций рисования. Итого получаем ускорение в 20 раз.


Более того, улучшается качество отрисовки. Рассмотрим пример:


BordersQuality.png


Здесь мы видим ряд ячеек, для каждой из которых установлен одинаковый стиль нижней рамки: пунктирная линия средней толщины. По этому рисунку четко видно, что Моксель рисует рамки индивидуально для каждой ячейки. Из-за этого на стыках ячеек можно видеть некоторые артефакты: удлиненные штрихи или укороченные промежутки. А вот для Йокселя стиль линии соблюдается четко по всей длине.


Собственно, использованный стиль практически единственный, на котором подобные артефакты хорошо заметны. На других стилях артефакты конечно тоже встречаются, но уже не так заметны. Поэтому для Мокселя подобный стиль рисования сходит с рук. Для Йокселя это уже становится важным, т.к. Йоксель теперь поддерживает и стили Excel, которые при моксельной отрисовке выглядят очень плохо.


 
Файлов нет. [Показать файлы/форму]
Комментариев нет. [Показать комментарии/форму]