Как стать автором
Обновить

Комментарии 8

Не хватает введения в предметную область. Изложение начниается откуда-то из середины. ;-(

Новые MacBook Pro и macOS соответственно тоже теперь поддерживают динамическую частоту кадров до 120 герц

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

1) Описание Offscreen Rendering

Кажется, здесь RenderServer подменяется понятием GPU. Если не ошибаюсь, до offscreen rendering ещё никакой GPU не используется. CoreAnimation работает на CPU, все необходимые дорисовки слоёв с использованием СoreGraphics происходят на CPU (если не говорить о слоях, которые напрямую используют Metal или OpenGL). То есть, если оперировать шагами из статьи, offscreen rendering происходит на этапе Render Prepare до Render Execute.

2) Изображения и GPU

Как только GPU выполняет отрисовку изображений, то это готово к отображению для следующего VSYNC

О каких изображениях идёт речь? О картинках? О контенте (CALayer.contents, bitmap) слоёв?

Картинки, которые требуют декомпрессии (WebP, JPEG) обрабаыватываются нашим приложением. И могут вообще служить причиной тормозов UI потока (CATransaction.commit), если не было предварительной декомпрессии.

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

Contents слоёв тоже рисуется на CPU, в UI-потоке в нашем приложении: например, буффер пикселей текста, это можно по CALayer.contents увидеть для стандартных View, рисующих текст. Ну и использования drawInContext или drawRect как раз являются примером рисования на CPU.

Или же тут всё-таки речь о итоговом отображении экрана?

Ну и:

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

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

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

Из таких аспектов возникает ощущение неточностей и несогласованностей внутри статьи, когда предложение из одного пункта, кажется, противоречит информации из другого пунта.

3) Не понятно, что такое "лайут реквест"

Может возникнуть ощущение, что это какой-то механизм для синхронизации layout или ещё какой-то системный callback. Хочется понять, о чём всё-таки речь? Любой вызовCATransaction.commit? Любой вызов layoutIfNeeded()? Или же что-то другое?

4) Vsync

VSYNC — это дедлайн для каждой фазы нашего рендер лупа

Точный ответ можно узнать, конечно, только из кода CoreAnimation, но всё же не похоже, чтобы VSYNC был дедлайном для каждой описанной в статье фазы подготовки изображения.

Согласен, что есть какая-то логичная отсечка, когда обновляется сам физический дисплей, остальное, думаю, всё условно. Например, что-то намекающее на Vsync, я видел только в виде даты CADisplayLink.targetTimestamp. Но, следует помнить, что CADisplayLink — это почти просто таймер, имеющий специализированный интерфейс для удобной работы с формированием кадров (а точнее транзакций).

Я не уверен, что как минимум для процесса нашего приложения не попадение в рамки 1/fps между CADisplayLink.timestamp и CADisplayLink.targetTimestamp обязательно приведёт к залипанию кадра, если CoreAnimation всё-таки успеет за оставшееся время (уже меньше 1/fps) обработать эту транзакцию.

Также, если верить старым докладам Apple, RenderServer не ждёт никаких синхронизаций кадров, а просто обрабатывает прилетающие транзакции. Которых мы иногда закидываем больше, чем 1 на кадр (надо вспомнить, где в коде мы сами создаём CATransaction.begin/CATransaction.commit):

WWDC 2014 Session 419. Advanced Graphics and Animations for iOS Apps.

Возможно, за 8 лет с того WWDC что-то поменялось в CoreAnimation, но что-то мне кажется, что вряд ли. Надо будет проверить через Instruments Metal System Trace, там видна и синхронизация дисплея и то, что делают другие процессы. Я немного рассказывал про Render pipeline, работу UIKit+CoreAnimation и инструменты в своём докладе: https://habr.com/ru/company/vk/blog/481626/

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

https://developer.apple.com/videos/play/tech-talks/10857/

https://developer.apple.com/videos/play/tech-talks/10855

Спасибо! Я смотрел эти доклады несколько месяцев назад. У меня было ощущение, что коллеги из Apple просто упростили и абстрактно формализовали существующий процесс рендеринга в этом видео. Но надо будет проверить. Спасибо)

Кто-то пишет не использовать параметр cornerRadius. Применение viewLayer.cornerRadius может привести к offscreen rendering. Вместо этого можно использовать класс UIBezierPath

Судя по видео из источников (https://developer.apple.com/videos/play/tech-talks/10857/), использование .cornerRadius приводит к offscreen rendering, только если .masksToBounds == true, но это все равно эффективнее чем использовать маску.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории