LINUX.ORG.RU

[Qt] Производительность QGraphicsScene. 200,000 статичных итемов и 1 подвижный.

 


0

1

Вот ведь ёлки зелёные.

Итак, у меня в сцене 200000 неподвижных прямоугольничков. С ними проблем нету. Всё работает более-менее быстро.

Если я добавляю в сцену итем, следующий за курсором (позиция меняется через setPos), то сразу начинаются проблемы с производительностью: сцена пересчитывает индекс каждый раз при изменении позиции этого итема. Иногда это занимает довольно долго. Если отключить индексирование, то перемещение становится быстрым, но индексирование мне нужно.

Кто-нибудь с таким сталкивался? Боролся? Побеждал?

★★★★★

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

Obey-Kun ★★★★★
() автор топика

Пока было 2 идеи:

1) Класть этот двигающийся итем во вью. Но я ушёл от этого, т.к. было неудобно.

2) Класть этот двигающийся итем в foreground у сцены. Но это невозможно средствами кьюта, придётся писать хитрые классы ForegroundScene и ForegroundItem, как-то так.

Obey-Kun ★★★★★
() автор топика

Вот зачем тебе в сцене 200000 неподвижных прямоугольничков? Их просто нарисовать нельзя было?

zJes ★★
()
Ответ на: комментарий от Obey-Kun

Все равно это не объясняет наличия 200000 объектов на сцене. :)
Блоки ты можешь иметь и боком, делая отрисовку блока на бакграунде. Каждый блок имел бы просто привязку к координатам сцены. Что-то мне подсказывает, что это бы и работало намного быстрее.

zJes ★★
()
Ответ на: комментарий от zJes

Я активно использую фичи сцены, а именно itemAt и itemsAt. Они используют bsp-деревья сцены и всё такое. Переносить блоки из сцены точно не надо. А вот всё, кроме блоков (двигающиеся фигнюшки) — возможно.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Если блоки всегда располагаются по регулярной сетке, то зачем все эти премудрости с индексами и bsp-деревьями для них?

kamre ★★★
()
Ответ на: комментарий от kamre

Блоки не обязательно не располагаются по сетке.

Я так понимаю, ты к тому, что если бы располагались, то можно бы было отказаться от индексирования сцены?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

> Блоки не обязательно не располагаются по сетке.

не обязательно располагаются.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Блоки не обязательно располагаются по сетке.

На этом скриншоте как раз все по регулярной сетке. Как еще могут располагаться? Если эти блоки неподвижны, то для них лучше иметь специальный индекс, который не будет перестраиваться постоянно.

kamre ★★★
()
Ответ на: комментарий от Obey-Kun

Т.к. модель блоковая, а не сеточная, то это блоки в полном понимании этого слова.

Obey-Kun ★★★★★
() автор топика

Боженька, хоть тебя и нет, но, пожалуйста, как будет свободное время - убей всех программистов на Qt, особенно тех, которые используют его в качестве 3д-движка. Еще можешь убить всех программистов на PHP и HMTL, но это не обязательно.

anonymous
()

Так ли нужен этот подвижный элемент? Может просто подсвечивать статичный при прохождении курсора над ним?

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

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

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

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Devix

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

Devix
()
Ответ на: комментарий от Devix

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

это фишка Qt, нельзя (да и вряд ли возможно идеологически)

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от MikeDM

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

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Devix

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

QGraphicsGroup мне не подходит, ибо оно select и прочее попортит. Сделал иначе: все статичные итемы добавляю как детей одного итема.

Тормозит гораздо меньше теперь. Чуть-чуть подтормаживает при пересчёте индеса, но не так, как раньше. Кеширование не включал.

Спасибо!

p.s.: кстати, тормоза эти забавно проявляются. Пересчёт индекса заметен, только когда динамический итем входит в ту чутверть плоскости, где статичных итемов много.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Вместо того чтобы вызывать QGraphicsItem::paint каждый раз при перерисовке, изображение будет браться из кеша. Допустим ты хочешь сделать ChartItem который рисует график из миллиона точек, ты перегружаешь QGraphicsItem::paint и там обходишь все миллион точек и рисуешь график. После включения кеша, тяжелый ChartItem::paint вызовется один раз(или когда график изменится), а дальше при перерисовке график будет браться из кеша (QPixmapCache - через него кешируются изображения). Тоесть при включенном кеша, painter в функции ChartItem::paint(QPainter * -->painter<--, .....) рисует в QPixmap, который в дальнейшем кешируется, и этот же закешированный QPixmap в дальнейшем используется для рисование графика. Если же в данном случае не включить кеш, то при каждом чихе будет вызыватся тяжелый ChartItem::paint().

PS: Вроде ничего не напутал.

Devix
()
Ответ на: комментарий от Devix

Спасибо за пояснение. Но нарисовать прямоугольник быстрее, чем подгрузить и нарисовать битмап кеша, разве нет?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Что касается скорости рисования, то тут такая проблема и не стоит. Всё рисуется очень быстро, если использовать -graphycssystem raster. А вот индексы сцены иногда мешаются.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Короче, вот так сделаю:

1) статичные итемы надо делать дочками некого итема-контейнера. Не знаю, почему, но это заметно повышает производительность не только setPos у динамичного итема, но и скорость работы индексов сцены вообще.

2) динамичный итем выношу во вью... ну то есть считать его позицию всё так же будет сцена, но отрисовываться он будет во вью.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

>Спасибо за пояснение. Но нарисовать прямоугольник быстрее, чем подгрузить и нарисовать битмап кеша, разве нет?

Сейчас посмотрел исходники QGraphicsItemGroup, и действительно включение кеша у QGraphicsItemGroup, похоже ничего бы не дало. Я думал что QGraphicsItemGroup::paint обходит все элементы группы, и у каждого вызывает функцию paint, но это не так.

Вот выдрал важный момент:
QGraphicsItemGroup::addToGroup(QGraphicsItem * item)
{
....
item->setParentItem(this)
....
}

Devix
()
Ответ на: комментарий от Obey-Kun

статичные итемы надо делать дочками некого итема-контейнера

  (DynItem                        CollectItem) <- BspTree_1
  /   |   \                      /    |     \
(It1  It2  It3) <- BspTree_2   (It1  It2   It3) <- BspTree_3
                                     /  \
                                   (It1  It2) <- BspTree_4

Короче для каждго уровня итемов (в иерархии итемов) создается отдельное Bsp дерево. А так как на верху иерархии у тебя всего лишь 2 итема то при перемещщении DynItem и дерево пересчитывается быстро. Раньше на одном уровне иерархии у тебя было очень много итемов.

Devix
()
Ответ на: комментарий от Devix

То есть если я 100000 итемов разобью на 10 итемов-контейнеров, то оно должно ещё шустрее быть?

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

>То есть если я 100000 итемов разобью на 10 итемов-контейнеров, то оно должно ещё шустрее быть?

Если ты прямоугольники один раз добавляешь а потом их не трогаешь, то скорее всего смысла нет(надо смотреть алгоритм вызова пересчета дерева).

Devix
()
Ответ на: комментарий от Devix

Да тут всё фиг знает :(. Как правило, прямоугольники добавляются большими порциями, часть из них может удаляться-добавляться чуть меньшими порциями. Порядок действий может меняться.

Я сейчас так сделал: добавил в сцену addItems(const QList<QGraphicsItem*>& items) и аналогичный метод для удаления итемов порциями. При добавлении создаётся пустой итем, все итемы в списке делаются его дочками, после чего этот итем добавляется в сцену. При удалении аналогично. Так как удаление-добавление итемов всегда происходит большими порциями, то несколько контейнеров появляется «автоматически».

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Obey-Kun

Наверное, надо будет поэкспериментировать с addItems, возможно надо будет создавать несколько контейнеров, разбивая входной список на несколько частей с лимитом размера. Чтобы сбалансировать bsp-деревья.

Obey-Kun ★★★★★
() автор топика
Ответ на: комментарий от Devix

> а дальше при перерисовке график будет браться из кеша

Сделали zoom и/или rotate для view и нужно или опять обновлять кэш, или рисовать картинку с zoom/rotate с ухудшением качества. Т.е. фактически такое кэширование работает только для translate view, и только на целое число пикселей (для долей пикселя нужно пересчитывать antialiasing).

kamre ★★★
()
Ответ на: комментарий от kamre

Если стандартное кеширование не подходит, то можно в своем Item-e сделать более умное кеширование.

Devix
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.