Есть ли способ ускорить/уменьшить использование ЦП при рисовании с помощью Cairo?

Я написал приложение, которое использует Cairo для рисования объектов на экране (точнее, на Gtk::DrawingArea). Приходится часто все перерисовывать. Оказывается, несмотря на то, что рисунки очень простые, X-сервер использует МНОГО ресурсов ЦП при перерисовке, а приложения работают ужасно медленно. Есть ли способ ускорить это? Или, может быть, мне не следует использовать DrawingArea и какой-то другой виджет?

То, что я рисую, представляет собой набор прямоугольников, которые пользователь может перемещать, перетаскивая их мышью. Весь рисунок выполняется с помощью on_expose_event, но когда указатель мыши перемещается (с нажатой кнопкой), я вызываю queue_draw() для обновления рисунка.


person rafalcieslak    schedule 31.07.2011    source источник
comment
Описание того, что вы рисуете и как вы рисуете, вероятно, принесло бы больше инсайтов.   -  person Artyom    schedule 31.07.2011
comment
Пожалуйста, добавьте несколько цифр. Просто небольшой счетчик в событии экспозиции для измерения частоты кадров. Возможно, речь идет о большом количестве обновлений, а не о медленной прорисовке. Лазерная мышь с высоким разрешением может производить множество событий движения мыши.   -  person Lothar    schedule 01.08.2011


Ответы (4)


Просто пару вещей, чтобы проверить:

Вы рисуете во время показа?

Нарисуйте свое изображение на поверхности Cairo, а затем в событии показа просто скопируйте его с этой поверхности на поверхность виджета.

Вы вырезаете и рисуете только необходимую область?

Событие expose дает вам X, Y, width, height области, которую необходимо перерисовать. В cairo создайте на поверхности прямоугольник с этими размерами и вызовите clip, чтобы не тратить время на перерисовку того, что не нужно.

person John Ledbetter    schedule 31.07.2011
comment
Отредактировал вопрос, чтобы включить подробности. - person rafalcieslak; 31.07.2011
comment
Вероятно, первое ваше предложение может сработать. Как я могу это сделать? Какой тип поверхности следует использовать, как получить контекст для рисования на ней и, наконец, как выполнить быстрое копирование? - person rafalcieslak; 18.08.2011

Рисование дорого, особенно рисование текста стало самой ресурсоемкой задачей графического интерфейса.

Единственный способ ускорить это — уменьшить количество отрисовываемых элементов. Проверьте, действительно ли вы рисуете только те элементы, которые необходимы. Событие разоблачения дает вам прямоугольник. Обновите только эту часть виджета.

Возможно, кешировать элементы в растровом изображении.

Например, для плавной прокрутки это может помочь отрисовать содержимое в растровое изображение, которое, например, на 500 пикселей больше, так что в большинстве случаев вам просто нужно скопировать изображение и вообще ничего не рисовать (обычно вы получаете открытые прямоугольники, которые всего от 5 до 10 пикселей в высоту во время прокрутки).

Но вам нужно предоставить нам больше информации о том, что вы рисуете и какова нагрузка на систему, чтобы получить лучший ответ.

person Lothar    schedule 31.07.2011
comment
Отредактировал вопрос, чтобы включить подробности. - person rafalcieslak; 31.07.2011
comment
Попробуйте использовать queue_draw_area вместо queue_draw и ограничьте область рисования. Если вы используете queue_draw, то отрисовывается весь виджет и передается много данных. - person Lothar; 01.08.2011

Я нашел эту статью о рисовании резьбы в каире, чтобы решить проблему скорости, может быть, это поможет:

http://cairographics.org/threaded_animation_with_cairo/

О высокой загрузке ЦП:

У вас установлены надлежащие драйверы с аппаратным ускорением для X?

person Community    schedule 31.07.2011
comment
Конечно! Никакое другое приложение не заставляет X так сильно использовать ЦП. А за статью спасибо, посмотрю. - person rafalcieslak; 31.07.2011
comment
О, хотя трюк в этой статье действительно классный, и я им воспользуюсь, это не решит проблему, потому что ускоряет работу, если рисунок сложный. У меня не просто несколько прямоугольников. - person rafalcieslak; 31.07.2011
comment
Мне жаль, что это не помогло - person ; 31.07.2011
comment
Реализация gdk_threads_enter/gdk_threads_leave непригодна для повышения производительности, это полный блок основного цикла GTK, поэтому вы никогда не получите лучшего результата, чем одно ядро ​​ЦП. Основная причина этого хака с многопоточностью состоит в том, чтобы упростить связь из фоновых потоков с виджетами. Есть много задокументированных проблем GTK с этим подходом и в Windows, поэтому лучше не использовать его. (Вот почему я проголосовал против) - person Lothar; 31.07.2011
comment
Чистое рисование в фоновом потоке должно быть возможно с Cairo, к сожалению, когда вы используете рисование текста, используется Pango, а Pango все еще не является потокобезопасным (некоторые люди начали работать над ним в мае этого года - да, после 10 лет невежества). - person Lothar; 31.07.2011
comment
Хотя статья не помогла, я думаю, что здесь была искренняя попытка помочь. Я не думаю, что людей следует наказывать за попытку помочь. - person James Hurford; 02.08.2011

Я, наконец, заставил использовать максимально 25 кадров в секунду, используя флаг блокировки.

bool lock = 0;
bool needs_redraw = 0;

void Redraw(){
    if(lock){
        needs_redraw = 1;
        return;
    }

    //draw image to a surface

    needs_redraw = 0;
    lock = 1;
    Glib::signal_timeout().connect(Unlock, 20);

    queue_draw();
}

bool Unlock(){
    lock = 0;
    if(needs_redraw) Redraw();
    return false;
}

void on_expose_event(something){
    //copy image from surface to widget's context
}

Это пример кода, но это идея. Это не позволит выполнять перерисовку чаще, чем раз в 20 мс.

person rafalcieslak    schedule 19.08.2011