Когда вид (или слой) требует рендеринга вне экрана? - PullRequest
45 голосов
/ 18 июля 2011

Здравствуйте,
в эти выходные я начал смотреть видео WWDC 2011 года. Я нашел действительно интересные темы об iOS. Мои любимые были о производительности и графике, но я нашел два из них, очевидно, в противоречии. Конечно, есть кое-что, чего я не получил. Сессии, о которых я говорю, - это понимание рендеринга UIKit -121 и полировка вашего приложения -105.
К сожалению, образец кода 2011 года по-прежнему недоступен для загрузки, поэтому довольно сложно получить общее представление. В одном сеансе они объясняют, что в большинстве случаев следует избегать рендеринга за пределами экрана во время визуализации в scrollview и т. Д. Они устраняют проблемы с производительностью в примере кода, почти рисуя все внутри метода -drawRect. В другом сеансе проблема производительности (в табличном представлении), по-видимому, связана со слишком большим количеством кода в методе -drawRect ячеек таблицы.
Во-первых, мне непонятно, когда система требует рендеринга вне экрана, я видел в видео, что некоторые функции кварца, такие как: cornerRadious, shadowOffset, shadowColor, требуют этого, но существует ли общее правило?
Во-вторых, я не знаю, правильно ли я понял, но кажется, что когда нет закадрового рендеринга, добавление слоев или представлений - это путь. Я надеюсь, что кто-то может пролить свет на это ..
Спасибо,
Andrea

Ответы [ 3 ]

134 голосов
/ 27 февраля 2012

Не думаю, что где-то записано правило, но, надеюсь, это поможет:

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

Существует также очень небольшая практическая разница между использованием слоев и представлений. Представления являются лишь тонкой оболочкой для CALayer, и большую часть времени они не приводят к значительному снижению производительности. Вы можете переопределить тип слоя, используемого представлением, используя метод + layerClass, если вы хотите, чтобы представление поддерживалось CAShapeLayer или CATileLayer и т. Д.

Как правило, в iOS пиксельные эффекты и графика Quartz / Core Graphics не ускоряются аппаратно, как и большинство других.

Следующие вещи не ускоряются аппаратно, а это значит, что их нужно делать программно (за кадром):

  1. Все, что сделано в drawRect. Если у вашего вида есть drawRect, даже пустой, рисование не выполняется аппаратно, и снижается производительность.

  2. Любой слой со свойством shouldRasterize, установленным в YES.

  3. Любой слой с маской или тенью.

  4. Текст (любой вид, включая UILabels, CATextLayers, Core Text и т. Д.).

  5. Любой рисунок, который вы делаете самостоятельно (на экране или вне экрана) с использованием CGContext.

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

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

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

Для хорошей производительности хитрость заключается в том, чтобы не использовать программный чертеж для видов, которые меняют каждый кадр. Например, если вам нужна анимированная векторная фигура, вы получите лучшую производительность, используя CAShapeLayer или OpenGL, чем drawRect и Core Graphics. Но если вы нарисуете фигуру один раз, а затем ее менять не нужно, это не будет иметь большого значения.

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

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

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

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

21 голосов
/ 20 августа 2015

Offscreen-рендеринг - одна из худших тем в рендеринге iOS на сегодняшний день.Когда инженеры Apple UIKit ссылаются на внеэкранный рендеринг, он имеет очень специфическое значение, и тонна сторонних блогов разработчиков iOS ошибается.

Когда вы переопределяете «drawRect:», вы рисуетечерез процессор и выплевывая растровое изображение.Растровое изображение упаковывается и отправляется в отдельный процесс, который живет в iOS, сервер рендеринга.В идеале сервер рендеринга просто отображает данные на экране.

Если вы возитесь со свойствами CALayer, такими как включение теней, графический процессор будет выполнять дополнительное рисование.Эту дополнительную работу имеют в виду инженеры UIKit, когда говорят «закадровый рендеринг».Это всегда выполняется с помощью аппаратного обеспечения.

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

Хотя я не знаю полного списка свойств, запускающих передачу за пределы экрана, вы можете диагностировать это с помощью базового слоя анимации инструмента «Цвет закадрового отображения».переключения.Я предполагаю, что любое свойство, кроме альфа, выполняется с помощью закадрового прохода.

На раннем оборудовании iOS было разумно сказать «делай все в drawRect».В настоящее время графические процессоры лучше, а в UIKit есть такие функции, как shouldRasterize.Сегодня это баланс между временем, проведенным в drawRect, количеством закадровых проходов и количеством смешивания.Для получения полной информации смотрите сеанс WWDC 2014 года 419 «Усовершенствованная графика и анимация для приложений iOS».

Тем не менее, хорошо понимать, что происходит за кулисами, и держать это взатылок, чтобы вы не делали ничего безумного, но вы должны начать с самого простого решения.Затем протестируйте его на самом медленном оборудовании, которое вы поддерживаете.Если вы не набираете 60FPS, используйте инструменты, чтобы измерить вещи и выяснить это.Есть несколько возможных узких мест, и если вы не используете данные для диагностики, вы просто догадаетесь.

10 голосов
/ 09 февраля 2016

Внеэкранный рендеринг / Рендеринг на CPU

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

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

Следующее вызовет закадровый рендеринг:

  • Любой слой с маской (layer.mask)

  • Любой слой с layer.masksToBounds / view.clipsToBounds, равным true

  • Любой слой с layer.allowsGroupOpacity, установленным на ДА, и layer.opacity меньше 1,0
    Когда представление (или слой) требует закадрового рендеринга?

  • Любой слой с тенью (layer.shadow*).
    Советы о том, как исправить: https://markpospesel.wordpress.com/tag/performance/

  • Любой слой с layer.shouldRasterize, равным

  • Любой слой с layer.cornerRadius, layer.edgeAntialiasingMask, layer.allowsEdgeAntialiasing

  • Любой слой с layer.borderWith и layer.borderColor?
    Отсутствует ссылка / подтверждение

  • Текст (любой вид, включая UILabel, CATextLayer, Core Text и т. Д.).

  • Большую часть рисунка вы делаете с CGContext в drawRect:. Даже пустая реализация будет отображена за кадром.


Этот пост посвящен смешиванию и другим факторам, влияющим на производительность: Что вызывает закадровый рендеринг, смешивание и макет Subviews в iOS?

...