Почему GUI-код так дорого вычисляется?

Все, что вам нужно,

Мне было интересно, почему GUI-код отвечает за сосание многих, многих циклов процессора. В принципе, графический рендеринг намного менее сложный, чем Doom (хотя большинство корпоративных графических интерфейсов предложат много оформления оформления). Слой обработки событий также, по-видимому, очень дорог, однако кажется, что хорошо написанная реализация должна эффективно переключаться между контекстами на современных процессорах с большим количеством памяти/кеша.

Если кто-то запустил профилировщик в своем большом приложении GUI или сам общий API, я заинтересован в том, где лежат узкие места.

Возможные объяснения (я думаю) могут быть:

  • Высокие уровни абстракции между аппаратным и прикладным интерфейсом
  • Множество уровней косвенности для правильного кода для выполнения
  • Низкий приоритет (по сравнению с другими процессами)
  • Неисправность приложений API для наводнения с помощью вызовов
  • Чрезмерная ориентация объекта?
  • Полный бедный выбор дизайна в API (не только проблемы, но и философия дизайна).

Некоторые графические интерфейсы намного лучше других, поэтому я хотел бы услышать разные перспективы. Например, система Unix/X11 сильно отличается от Windows и даже WinForms.

Изменить: Теперь сообщество wiki - подойдет для этого. У меня есть еще одна вещь, которую я хочу добавить: я парень-алгоритм в школе, и мне было бы интересно, если в коде GUI есть неэффективные алгоритмы и какие они есть. Опять же, это, вероятно, просто накладные расходы на реализацию.

Ответы

Ответ 1

Я вообще не знаю, но я хотел бы добавить еще один элемент в ваш список - рендеринг и вычисления шрифтов. Поиск векторных глифов в шрифте и преобразование их в растровые изображения с антиалиасингами - немалая задача. И часто это нужно делать дважды - сначала для вычисления ширины/высоты текста для позиционирования, а затем для фактического рисования текста в правильных координатах.

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

Добавлено:

В комментариях я нашел это:

Я тоже очень заинтересован в этом. Не может быть, что gui рендерится с использованием только процессора, потому что, если у вас нет правильных драйверов для вашей gfx-карты, графика на рабочем столе невероятно медленная. Если у вас есть gfx-drivers, однако desktop-gfx идет быстро, но не так быстро, как приложение directx/opengl.

Здесь сделка, как я ее понимаю: каждая графическая карта сегодня поддерживает общий интерфейс для рисования. Я не уверен, что он называется "VESA", "SVGA", или если это только старые имена из прошлого. Во всяком случае, этот интерфейс включает в себя все, что происходит через прерывания. Для каждого пикселя есть вызов прерывания. Или что-то типа того. Собственный драйвер VGA, однако, может использовать DMA и другие усовершенствования, которые делают весь процесс WAY менее интенсивным в работе процессора.

Добавлено 2: Ah, а для OpenGL/DirectX - еще одна особенность сегодняшних видеокарт. Они оптимизированы для 3D-операций в эксклюзивном режиме. Вот почему скорость. Обычный графический интерфейс просто использует базовые 2D-чертежные процедуры. Таким образом, он получает возможность отправлять содержимое всего экрана каждый раз, когда он хочет обновления. Однако 3D-приложения отправляют кучу текстур и определений треугольников в VRAM (видео-RAM), а затем просто повторно используют их для рисования. Они просто говорят что-то вроде "возьмите набор треугольников # 38 с набором текстур № 25 и нарисуйте их". Все эти вещи кэшируются в VRAM, так что это происходит быстрее.

Я не уверен, но я подозреваю, что современные 3D-ускоренные графические интерфейсы (Vista Aero, compiz на Linux и т.д.) также могут воспользоваться этим. Они могут отправлять общие растровые изображения в VGA спереди, а затем просто повторно использовать их непосредственно из VRAM. Тем не менее, любые приложенные к рисункам поверхности все равно должны отправляться напрямую каждый раз для обновлений.

Добавлено 3: Больше идей.:) Современный графический интерфейс для Windows, Linux и т.д. Ориентирован на виджеты (которые ориентированы на управление для динамиков Windows). Проблема заключается в том, что каждый виджет имеет свой собственный код чертежа и связанную с ним поверхность рисования (более или менее). Когда окно нужно перерисовать, он вызывает код чертежа для всех его дочерних виджетов, которые, в свою очередь, вызывают код чертежа для своих дочерних виджетов и т.д. Каждый виджет перерисовывает всю свою поверхность, хотя некоторые из них скрыты другими виджетами. С вышеупомянутыми методами отсечения часть этой нарисованной информации немедленно отбрасывается для уменьшения мерцания и других артефактов. Но все же у него много ручного чертежного кода, который включает в себя битовые блики, растяжки, перекосы, линии рисования, текст, заливку наводнения и т.д. И все это переводится в серию звонков с пулпикселями, которые фильтруются через отсекающие фильтры/маски и другие вещи. Ах, да, и альфа-смешивание также стало популярным сегодня для приятных эффектов, что означает еще большую работу. Итак... да, вы могли бы сказать, что это из-за большого количества абстракции и косвенности. Но... ты мог бы сделать это лучше? Я так не думаю. Только 3D-методы могут помочь, поскольку они используют GPU для альфа-вычислений и отсечения.

Ответ 2

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

Среди библиотек писать библиотеку инструментов GUI - это очень сложная проблема. Это связано с тем, что программы, которые используют библиотеки графического интерфейса, варьируются в самых разных областях с очень разными потребностями. Mr Why и Martin DeMollo несколько лет назад обсудили требования, предъявляемые к библиотекам графического интерфейса.

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

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

Ответ 3

Эм, это довольно много.

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

Чтобы установить прямолинейные вычисления при загрузке на GPU, не обязательно будут возникать проблемы. Графический процессор точно так же, как и процессор, за исключением того, что он не имеет общего назначения и более параллельный процессор данных. Он может делать графические вычисления исключительно хорошо. Независимо от того, какая комбинация графических API/ОС и драйверов у вас на самом деле не так важна... ОК, с Vista в качестве примера они изменили механизм компоновки рабочего стола. Этот движок намного лучше компостирует только то, что изменилось, и поскольку перфорация бутылки номер один для приложений с графическим интерфейсом является перерисовкой, это аккуратная стратегия оптимизации. Эта идея виртуализации ваших вычислительных потребностей и каждый раз обновлять самые маленькие изменения.

Win32 отправляет сообщения WM_PAINT в окна, когда их нужно перерисовать, это может быть результатом окон, перекрывающих друг друга. Однако это до самого окна, чтобы выяснить, что на самом деле изменилось. Более того, ничего не изменилось или изменения, которые были сделаны, были достаточно тривиальными, так что он мог быть только что сформирован поверх того, что было на самом верхнем уровне, которое у вас было.

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

Что-то, что делает Windows Presentation Foundation (WPF), который, по моему мнению, намного превосходит большинство других API GUI, заключается в том, что он разбивает обновления макета и рендеринг обновлений на два отдельных прохода. И хотя управляемым кодом WPF является механизм рендеринга. Что происходит с рендерингом, так это то, что управляемый механизм рендеринга WPF создает очередь команд (это то, что делает DirectX и OpenGL), которое затем передается собственному механизму рендеринга. Что еще более элегантно, так это то, что WPF попытается сохранить любые вычисления, которые не изменили бы визуальное состояние. Трюк, если вы можете, где вы избегаете дорогостоящего рендеринга, требует вещей, которые не нужно визуализировать (виртуализация).

В отличие от WM_PAINT, который сообщает Win32-окну, чтобы перерисовать себя, приложение WPF проверит, какие части этого окна требуют перекраски и только перерисовывают наименьшее изменение.

Теперь WPF не является высшим, это надежное усилие от Microsoft, но это еще не святой Грааль... код, который запускает конвейер, все еще может быть улучшен, а объем памяти любого управляемого приложения еще больше, чем я хотел бы, Но я надеюсь, что это тот ответ, который вы ищете.

WPF способен сделать некоторые вещи асинхронно довольно приличными, что очень важно, если вы хотите создать действительно отзывчивый интерфейс с низкой задержкой/низким уровнем производительности. Асинхронные операции - это больше, чем работа при загрузке в другом потоке.

Подводя итоги медленному и дорогостоящему графическому интерфейсу, это означает слишком много перекраски и вид переиздания, который очень дорог, т.е. вся площадь поверхности.

Ответ 4

В какой-то степени я зависеть от языка. Возможно, вы заметили, что приложения Java и RealBasic являются справедливыми бит медленнее, чем их C-based (С++, С#, Objective-C) аналоги.

Однако приложения GUI намного сложнее, чем приложения в командной строке. Окно терминала нужно просто нарисовать простое окно, которое не поддерживает кнопки.

Существует также несколько циклов для дополнительных входов и функций.

Ответ 5

Я думаю, что вы можете найти интересные мысли по этой теме в разделе "Дизайн оконной системы: если бы мне пришлось это делать снова в 2002 году" Джеймса Гослинга (Java-парень, также известный своей работой над оконным окном до X11 системы). Доступно через Интернет здесь [pdf].

В статье рассматривается положительная сторона (как сделать ее быстро), а не на отрицательной стороне (что делает ее медленной), но она по-прежнему хорошо читается в этой теме.