Какой самый быстрый способ кэшировать нарисованное изображение на экране и отображать его на iOS?
Вместо того, чтобы позволить drawRect
каждый раз перерисовывая тысячи точек, я думаю, что есть несколько способов "кэшировать изображение на экране" и любой дополнительный рисунок, мы добавим к этому изображению и просто покажем это изображение, когда придет время drawRect
:
Используйте BitmapContext и рисуйте в растровое изображение, и в
drawRect
Нарисуйте этот растр.использование
CGLayer
и нарисуйтеCGLayer
вdrawRect
, и это может быть быстрее, чем метод 1, так как это изображение кэшируется в графической карте (и оно не будет учитываться в использовании оперативной памяти для "предупреждения о памяти" на iOS?)Рисовать на
CGImage
и используйте слой вида:view.layer.contents = (id) cgimage;
Так что, кажется, есть три метода, и я думаю, CALayer
в методе (3) можно использовать только CGImage
добиться этого. CALayer
само по себе не может кэшировать изображение на экране, не как CGLayer
в (2).
Является ли метод (2) самым быстрым из всех трех, и есть ли другие методы, которые могут достичь этого? Я на самом деле планирую анимировать несколько изображений на экране (с 5 или 6 циклами) и попробую использовать CADisplayLink
попробовать самую высокую частоту кадров 60 кадров в секунду. Будет ли какой-либо из методов (1), (2) или (3) использовать память графической карты и, следовательно, не использовать оперативную память и, следовательно, с меньшей вероятностью получить предупреждение о памяти от iOS тоже?
2 ответа
Судя по последним нескольким вопросам, которые вы задали, похоже, что вы полностью путаете CGLayers и CALayers. Это разные понятия, и они на самом деле не связаны друг с другом. CGLayer - это конструкция Core Graphics, которая помогает многократно воспроизводить содержимое в пределах холста контекста Core Graphics и ограничивается одним представлением, растровым изображением или контекстом PDF. Редко мне приходилось работать с CGLayer.
CALayer - это слой Core Animation, и на каждом UIView в iOS (и на уровне слоя NSView на Mac) поддерживается один слой. Вы имеете дело с этим все время на iOS, потому что они являются фундаментальной частью архитектуры пользовательского интерфейса. Каждый UIView - это, по сути, легкая оболочка вокруг CALayer, а каждый CALayer, в свою очередь, фактически является оберткой вокруг текстурированного четырехугольника на GPU.
При отображении UIView на экране самый первый раз, когда необходимо визуализировать контент (или когда запускается полная перерисовка) Core Graphics используется для получения линий, дуг и других векторных рисунков (иногда также включая растровые растровые изображения) и растеризации их на растровое изображение. Затем это растровое изображение загружается и кэшируется на GPU через ваш CALayer.
Для изменений в интерфейсе, таких как перемещение, вращение, масштабирование и т. Д. Видов, эти виды или слои не нужно перерисовывать заново, что является дорогостоящим процессом. Вместо этого они просто преобразуются в графическом процессоре и компонуются в новом месте. Это то, что обеспечивает плавную анимацию и прокрутку в интерфейсе iOS.
Поэтому вам следует избегать использования Core Graphics для перерисовки чего-либо, если вы хотите добиться максимальной производительности. Кэшируйте, какие части сцены вы можете в CALayers или UIViews. Подумайте о том, как анимация более старого стиля использовала клетки для хранения частей сцены, которые они будут перемещать, вместо того, чтобы аниматоры перерисовывали каждое изменение сцены.
Вы можете легко заставить сотни CALayers плавно анимировать экран на современных устройствах iOS. Однако, если вы хотите заработать тысячи баллов за что-то вроде системы частиц, вам будет лучше перейти на OpenGL ES и выполнить рендеринг с использованием GL_POINTS. Для настройки потребуется гораздо больше кода, но это может быть единственным способом получить приемлемую производительность для "тысяч точек", о которых вы спрашиваете.
Одним из быстрых методов, который позволяет как кэшировать графику, так и модифицировать содержимое этой кэшированной графики, является сочетание ваших методов (1) и (3).
(1) Создайте свой собственный графический контекст, поддерживаемый растровым изображением, нарисуйте его, а затем измените его в любое время (постепенно добавляйте одну точку или тысячи точек время от времени и т. Д.) По мере необходимости. К сожалению, это будет невидимо, потому что нет способа напрямую получить какое-либо растровое изображение на дисплей на устройстве iOS.
Итак, кроме того,
(3) при некоторой частоте кадров (60 Гц, 30 Гц и т. Д.), Если битовая карта загрязнена (была изменена), преобразуйте контекст битовой карты в CGImage и назначьте это изображение содержимому CALayer. Это преобразует и копирует всю память вашего растрового изображения в кеш текстуры GPU (это медленная часть). Затем используйте базовую анимацию, чтобы сделать со слоем все, что вы хотите (очистить, сложить, обвести вокруг окна и т. Д.), Чтобы отобразить текстуру, созданную из вашего растрового изображения. За кулисами Core анимация в конечном итоге позволит графическому процессору сгенерировать квад с помощью этой текстуры на некоторых составных мозаичных окнах, которые в конечном итоге будут отправлены на дисплей устройств (это описание, вероятно, пропустит целую кучу этапов в графике и конвейерах графического процессора). Промойте и повторите при необходимости в главном цикле выполнения пользовательского интерфейса. Мой пост в блоге об этом методе находится здесь.
Нет возможности частично изменить содержимое существующей текстуры графического процессора. Вы должны либо заменить его полностью новой загрузкой текстуры, либо создать другой слой поверх слоя текстуры. Таким образом, вы в конечном итоге будете сохранять вдвое больше используемой памяти, некоторые в адресном пространстве процессоров, некоторые в кэше текстур GPU.