Overdraw — это избыточная перерисовка одних и тех же пикселей несколько раз за один кадр. Когда на экране отображается сложный интерфейс с множеством перекрывающихся элементов, GPU вынужден обрабатывать каждый пиксель многократно, что напрямую влияет на частоту кадров и энергопотребление. По данным Google Android Developer Documentation, 2025, снижение overdraw на 50% может увеличить производительность рендеринга до 30%. Оптимизация overdraw — обязательный этап при разработке приложений с плавной анимацией и отзывчивым интерфейсом.
Главное
Overdraw — это ситуация, когда один и тот же пиксель экрана перерисовывается несколько раз в течение одного кадра рендеринга. В идеальном сценарии каждый пиксель должен быть записан ровно один раз, но в реальных интерфейсах из-за вложенных View, фоновых изображений и прозрачных слоёв GPU выполняет повторные записи.
Каждая дополнительная перерисовка увеличивает время рендеринга кадра. При стандартной частоте 60 FPS на обработку одного кадра отводится примерно 16.6 мс. Если overdraw приводит к превышению этого лимита, частота кадров падает до 30 FPS или ниже, что заметно ухудшает плавность интерфейса.
По данным Android Performance Patterns от Google, приложение с коэффициентом overdraw 3x тратит в три раза больше времени на фрагментный шейдер, чем приложение с overdraw 1x. На устройствах с низкой производительностью GPU это приводит к ощутимым лагам при скролле и анимации.
Для мобильных разработчиков понимание overdraw критически важно: именно этот фактор чаще всего вызывает дёрганный скролл и низкую частоту кадров в, казалось бы, простых экранах с большим количеством вложенных элементов.
GPU-конвейер состоит из нескольких этапов: вершинный шейдер, растеризация и фрагментный шейдер. Фрагментный шейдер — самая затратная часть, так как он выполняется для каждого пикселя каждого примитива. При overdraw x2 фрагментный шейдер обрабатывает вдвое больше пикселей, что напрямую увеличивает время кадра.
Современные мобильные GPU, такие как Qualcomm Adreno и Apple GPU, имеют механизмы Early-Z Test и Hidden Surface Removal, которые частично компенсируют overdraw. Однако эти оптимизации работают только при определённых условиях, и полагаться исключительно на аппаратное ускорение не следует.
Например, при рендеринге полупрозрачных элементов аппаратный Early-Z неэффективен, и каждый пиксель обрабатывается полностью — overdraw в таких сценариях может достигать 5x и выше.
Многослойные фоны — одна из главных причин overdraw в мобильных приложениях. Когда Activity или ViewController устанавливает фоновый цвет, каждый вложенный View может добавлять собственный фон, и пиксель перерисовывается на каждом уровне иерархии.
Исследование Uber Engineering показало, что удаление избыточных фонов в своём Android-приложении сократило overdraw на 32%, а время рендеринга экрана — на 25%. Аналогичная ситуация в iOS: установка opaque = true для непрозрачных View исключает альфа-блендинг и предотвращает множественную запись пикселей.
На платформе iOS overdraw часто возникает из-за использования прозрачных UIStackView, CALayer с shouldRasterize и перекрывающихся UIBlurEffect. Apple рекомендует проверять overdraw через Core Animation инструмент в XCode — он показывает зоны перерисовки в виде наложения красного цвета.
Debug GPU Overdraw — встроенный инструмент Android, который окрашивает экран в разные цвета в зависимости от кратности overdraw. Фиолетовый цвет означает 1x, синий — 2x, зелёный — 3x, розовый — 4x, красный — 5x и более. Идеальный экран должен быть преимущественно фиолетовым.
В iOS аналогичную диагностику выполняет инструмент Core Animation в составе XCode Instruments. Он визуализирует зоны перерисовки и показывает точное количество записей на пиксель в режиме Color Blended Layers. Зелёные слои — непрозрачные (оптимально), красные — содержат прозрачность и вызывают overdraw.
После диагностики важно замерить FPS до и после оптимизации. Разница в 10–15 FPS при исправлении overdraw — нормальный результат для сложного экрана со списками и анимацией.
Удаление избыточных фонов — самый простой и эффективный метод. В Android достаточно установить android:windowBackground только для Activity или темы, а не для каждого View. В iOS opaque = true для всех непрозрачных UIView снижает overdraw практически до нуля для этих элементов.
По данным Google I/O 2019, оптимизация overdraw в Google Maps позволила снизить время рендеринга кадра на 40% за счёт объединения слоёв и использования ClipRect для ограничения области отрисовки. Для Android разработчиков Google рекомендует следующие практики:
В iOS оптимизация достигается через настройку CALayer: установка masksToBounds = true обрезает содержимое за пределами границ слоя, а shouldRasterize включает кэширование растрового представления для статичных слоёв.
Рассмотрим практические примеры на Kotlin и Swift, демонстрирующие типичные сценарии устранения overdraw. Первый пример показывает оптимизацию через ClipRect в Android:
class OptimizedView@JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : View(context, attrs) {
override fun onDraw(canvas: Canvas) {
canvas.clipRect(
paddingLeft.toFloat(), paddingTop.toFloat(),
width - paddingRight.toFloat(), height - paddingBottom.toFloat()
)
// Draw content only within clipped area
super.onDraw(canvas)
}
}
Второй пример — на Swift, показывает отключение прозрачности для слоя, если элемент не должен быть полупрозрачным:
class OpaqueLabel: UILabel {
override var isOpaque: Bool {
get { true }
set { }
}
override func draw(_ rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
super.draw(rect)
}
}
Третий пример — использование ViewStub для отложенной загрузки карты в Android. ViewStub не рендерится до момента, пока не станет видимым, что устраняет overdraw на этапе инициализации экрана:
<!-- layout/activity_main.xml -->
<ViewStub
android:id="@+id/map_stub"
android:layout_width="match_parent"
android:layout_height="200dp"
android:inflatedId="@+id/map_container"
android:layout="@layout/map_fragment" />
// Inflate on demand
ViewStub stub = findViewById(R.id.map_stub)
stub?.inflate()
Часто задаваемые вопросы
Overdraw — это когда пиксель на экране перерисовывается несколько раз за один кадр. Представьте, что вы закрашиваете лист бумаги, а поверх него клеите несколько прозрачных плёнок с рисунками — нижние слои приходится перерисовывать каждый раз, когда меняется верхний слой.
Включите Debug GPU Overdraw в настройках разработчика. Элементы с overdraw 1x окрашиваются фиолетовым, 2x — синим, 3x — зелёным, 4x — розовым, 5x+ — красным. Оптимальный экран — преимущественно фиолетовый без красных зон.
Каждая дополнительная перерисовка пикселя требует вызова фрагментного шейдера, который обрабатывает цвет, текстуру и освещение. При 60 FPS на кадр отводится 16.6 мс — если overdraw заставляет GPU обрабатывать в 2–3 раза больше пикселей, лимит превышается, и FPS падает до 30.
Да, напрямую. GPU, выполняющий избыточную работу, потребляет больше энергии. По данным исследования Google, снижение overdraw с 4x до 1x уменьшает энергопотребление GPU на 35–50%, что особенно заметно на устройствах с дисплеями высокой чёткости.
Для простых экранов — 1x–1.5x (фиолетовый с небольшим количеством синего). Для насыщенных интерфейсов — до 2x. Уровень 3x и выше (розовый, красный) требует оптимизации. Google рекомендует не превышать overdraw 2.5x в среднем по экрану.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также