Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 24.06.21 07:29
Оценка:
Приветствую!
Уже постил это на stackoverflow, но похоже что там мало специалистов по Qt, может тут кто подскажет)

Суть задачи: мне нужно быстро рисовать текст средствами Qt Widgets.

По сути, нужна функция, аналогичная функции WinAPI TabbedTextOut (то есть, не нужно переносить слова или считать высоту).

QPainter.drawText поразил медлительностью. Он в целом не очень быстр, но рендер некоторых символов Unicode
(смайликов) занимает вплоть до 500мс (на Ryzen 3900x)! Похоже, что там под капотом делается много чего ненужного.

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

Что я пробовал:
— Готовить отрендеренный текст заранее в рабочем потоке (в пуле потоков), в виде QImage.
Работает неплохо, но быстрая прокрутка тем не менее быстро исчерпывает кэш и приводит к затыкам.
Кроме того, кэш из QImage занимает много памяти.

— QML ListView. На самом деле это не намного быстрее, и со своими сложностями, так что я бы
предпочел решение только для виджетов.

— QStaticText. По-прежнему не решает проблему исчерпания кеша.
— QTextLayout. То же самое, кэш быстро заканчивается.

P.S. Qt 5.15 на Windows 10.

Спасибо!
Отредактировано 24.06.2021 8:06 A.J. . Предыдущая версия . Еще …
Отредактировано 24.06.2021 7:30 A.J. . Предыдущая версия .
Re: Быстрый рендер текста средствами Qt возможен?
От: Zhendos  
Дата: 24.06.21 09:31
Оценка: 6 (2)
Здравствуйте, A.J., Вы писали:

AJ>Приветствую!

AJ>Уже постил это на stackoverflow, но похоже что там мало специалистов по Qt, может тут кто подскажет)

AJ>Суть задачи: мне нужно быстро рисовать текст средствами Qt Widgets.



Ну по сути все делают одно и тоже. В терминах Qt делают большой QImage
в котором одновременно отрендеренны тысячи символов из текущего шрифта
и при отрисовке передают смешение в QImage в функцию рисования.

Если использовать QML то моно это еще ускорить. За счет того что реализовать
QSGTextureProvider и хранить все символы в текстуре вместо QImage,
то есть на стороне GPU.

Но по идее для QML Qt это и так делает.
Но возможно параметры кэша символов не подходит для вашего приложения
и будет выгоднее реализовать это самому.
Re: Быстрый рендер текста средствами Qt возможен?
От: Igore Россия  
Дата: 24.06.21 09:36
Оценка: 2 (1)
Здравствуйте, A.J., Вы писали:

AJ>Суть задачи: мне нужно быстро рисовать текст средствами Qt Widgets.


AJ>По сути, нужна функция, аналогичная функции WinAPI TabbedTextOut (то есть, не нужно переносить слова или считать высоту).


AJ>Не хочется прибегать к платформенно-зависимым решениям, по крайней мере до того, как смогу убедиться,

AJ>что ускорить вывода текста только средствами Qt невозможно.

AJ>- QML ListView. На самом деле это не намного быстрее, и со своими сложностями, так что я бы

AJ> предпочел решение только для виджетов.

AJ>- QStaticText. По-прежнему не решает проблему исчерпания кеша.

AJ>- QTextLayout. То же самое, кэш быстро заканчивается.

AJ>P.S. Qt 5.15 на Windows 10.

Я на 5.12 вроде похожие эксперименты проводил

С qml я так же пробовал
Text{ 
   renderType: Text.NativeRendering 
}
QQuickWindow* window = qobject_cast<QQuickWindow*>(engine.rootObjects().first());
window->setTextRenderType(QQuickWindow::TextRenderType::NativeTextRendering);

В итоге самым быстрым решением было всё таки QListWidget + QLabel, по идее надо пробовать QListView + custom delegate, а у него painter.drawText();
Или совсем в другую степь, QtWebEngine
Re[2]: Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 24.06.21 14:16
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Ну по сути все делают одно и тоже. В терминах Qt делают большой QImage

Z>в котором одновременно отрендеренны тысячи символов из текущего шрифта
Z>и при отрисовке передают смешение в QImage в функцию рисования.

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

Z>Если использовать QML то моно это еще ускорить. За счет того что реализовать

Z>QSGTextureProvider и хранить все символы в текстуре вместо QImage,
Z>то есть на стороне GPU.

Думаю что так далеко я не пойду, мне будет достаточно просто если будет скролиться без лагов.

Z>Но возможно параметры кэша символов не подходит для вашего приложения

Z>и будет выгоднее реализовать это самому.

Да нет, вроде как раз подойдет. Правда, т.к. текст еще и может быть с форматированием
(жирный, курсив, моноширинный), придется делать несколько таких огромных QImage —
на каждый вариант шрифта и форматирования.
Re[2]: Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 24.06.21 14:19
Оценка:
Здравствуйте, Igore, Вы писали:

I>В итоге самым быстрым решением было всё таки QListWidget + QLabel, по идее надо пробовать QListView + custom delegate, а у него painter.drawText();

I>Или совсем в другую степь, QtWebEngine

Я в итоге остановился на QTableView + custom delegate, QListView очень плохо подходит для огромных списков из элементов разной высоты,
т.к. почему-то начинает дергать sizeHint для всех элементов, а не только видимых — как оказалось, это баг, зарепорченный еще в 2011 году!
Re[3]: Быстрый рендер текста средствами Qt возможен?
От: B0FEE664  
Дата: 21.07.21 08:43
Оценка:
Здравствуйте, A.J., Вы писали:

AJ>Я в итоге остановился на QTableView + custom delegate, QListView очень плохо подходит для огромных списков из элементов разной высоты,

AJ>т.к. почему-то начинает дергать sizeHint для всех элементов, а не только видимых — как оказалось, это баг, зарепорченный еще в 2011 году!

Если есть список из элементов разной высоты, то как для него подсчитать позицию скроллбара без вычисления общей высоты всего списка? Это нетривиальная задача, особенно если высота некоторых элементов больше высоты окна. Не думаю, что в Qt это кто-то осилил.
И каждый день — без права на ошибку...
Re[4]: Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 21.07.21 09:29
Оценка:
BFE>Если есть список из элементов разной высоты, то как для него подсчитать позицию скроллбара без вычисления общей высоты всего списка? Это нетривиальная задача, особенно если высота некоторых элементов больше высоты окна. Не думаю, что в Qt это кто-то осилил.

При большом количестве элементов точность скролбара уже не так важна, по крайней мере в моем случае ей точно можно пожертвовать в угоду скорости.
Re[5]: Быстрый рендер текста средствами Qt возможен?
От: B0FEE664  
Дата: 21.07.21 10:06
Оценка:
Здравствуйте, A.J., Вы писали:

AJ>При большом количестве элементов точность скролбара уже не так важна,

Если точность не важна, то может сложится ситуация, когда, например, не получится "домотать" до конца списка.

AJ>по крайней мере в моем случае ей точно можно пожертвовать в угоду скорости.

Может быть и так, вот только скорость и Qt — не друзья.

PS Если ещё актуально: попробуйте отключить вертикальный скролбар и посмотреть — будет ли запрашиваться высота. (никаких гарантий)
И каждый день — без права на ошибку...
Re[6]: Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 26.07.21 08:42
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Если точность не важна, то может сложится ситуация, когда, например, не получится "домотать" до конца списка.

Да, может быть такое, но несложно написать код, это поправляющий.

AJ>>по крайней мере в моем случае ей точно можно пожертвовать в угоду скорости.

BFE>Может быть и так, вот только скорость и Qt — не друзья.

А есть ли более быстрый кроссплатформенный ГУИ-фреймворк для С++, сравнимый с Qt по фукнционалу?
Я конечно понимаю, что есть вещи вроде SFML и ImGui, но оно больше для игр, там слишком многое нужно будет реализовывать самому.

BFE>PS Если ещё актуально: попробуйте отключить вертикальный скролбар и посмотреть — будет ли запрашиваться высота. (никаких гарантий)

Попробую, спасибо.
Re[6]: Быстрый рендер текста средствами Qt возможен?
От: A.J. Россия CintaNotes
Дата: 05.08.21 11:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>PS Если ещё актуально: попробуйте отключить вертикальный скролбар и посмотреть — будет ли запрашиваться высота. (никаких гарантий)


Попробовал — все равно запрашивает
Отключал через listView.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Пока остаюсь на QTableView.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.