Параллелизм и OpenGL ES
В вычислениях параллелизм обычно относится к выполняющимся задачам больше чем на одном процессоре одновременно. Путем выполнения работы параллельно, задачи, завершенные раньше, и приложения, становятся более быстро реагирующими пользователю. Хорошо разработанный OpenGL приложение ES уже показывает определенную форму параллелизма — параллелизм между обработкой приложения на CPU и OpenGL обработка ES на GPU. Много методов представили в OpenGL, Руководство по проектированию ES нацелено в частности на создание приложений OpenGL, показывающих большой параллелизм CPU-GPU. Разработка параллельного приложения означает анализировать работу в подзадачи и идентифицировать, какие задачи могут безопасно работать параллельно и какие задачи должны быть выполнены последовательно — т.е. какие задачи зависят или от ресурсов, используемых другими задачами или от результатов, возвращенных из тех задач.
Каждый процесс в iOS состоит из одного или более потоков. Поток является потоком выполнения, выполняющего код для процесса. Apple предлагает и традиционные потоки и функцию под названием Grand Central Dispatch (GCD). Используя Центральную Отгрузку, можно анализировать задачу в подзадачи, вручную не управляя потоками. GCD выделяет потоки на основе числа ядер, доступных на устройстве, и автоматически планирует задачи к тем потокам.
В более высоком уровне, Сенсорных предложениях Какао NSOperation
и NSOperationQueue
обеспечить абстракцию Objective C для создания и планирования единиц работы.
Эта глава не описывает эти технологии подробно. Перед рассмотрением, как добавить параллелизм к OpenGL приложение ES, консультируйтесь с Руководством по программированию Параллелизма. Если Вы планируете управлять потоками вручную, также см. Руководство по программированию Поточной обработки. Независимо от которого метода Вы используете, существуют дополнительные ограничения при вызове OpenGL ES в многопоточных системах. Эта глава помогает Вам понять, когда многопоточность улучшает Ваш OpenGL производительность приложения ES, ограничения OpenGL места ES на многопоточном приложении и общих стратегиях проектирования, Вы могли бы использовать для реализации параллелизма в OpenGL приложение ES.
Решение, можно ли получить преимущества от параллелизма
Создание многопоточного приложения требует значительного усилия в проекте, реализации и тестировании Вашего приложения. Потоки также добавляют сложность и наверху. Ваше приложение, возможно, должно скопировать данные так, чтобы это могло быть вручено рабочему потоку, или многократные потоки, возможно, должны синхронизировать доступ к тем же ресурсам. Прежде чем Вы попытаетесь реализовать параллелизм в OpenGL приложение ES, оптимизируйте свой OpenGL код ES в однопоточной среде с помощью методов, описанных в OpenGL Руководство по проектированию ES. Внимание на достижение большого параллелизма CPU-GPU сначала и затем оценивает, может ли параллельное программирование обеспечить дополнительную производительность.
Хороший кандидат имеет или или обе из следующих характеристик:
Приложение выполняет много задач на CPU, который независим от OpenGL рендеринг ES. Игры, например, моделируют игровой мир, вычисляют искусственный интеллект от управляемых компьютером противников и звук игры. Можно использовать параллелизм в этом сценарии, потому что многие из этих задач не зависят от OpenGL код для прорисовки ES.
Профилирование Вашего приложения показало, что Ваш OpenGL код рендеринга ES проводит много времени в CPU. В этом сценарии GPU неактивен, потому что Ваше приложение неспособно к питанию, это управляет достаточно быстро. Если Ваш ограниченный CPU код был уже оптимизирован, можно быть в состоянии улучшить его производительность далее путем разделения работы на задачи, выполняющиеся одновременно.
Если Ваше приложение блокируется, ожидая GPU и не имеет никакой работы, оно может выполнить параллельно с ее OpenGL получение ES, то это не хороший кандидат на параллелизм. Если CPU и GPU оба неактивны, то Ваш OpenGL , потребности ES, вероятно, достаточно просты, что не необходима никакая дальнейшая настройка.
OpenGL ES ограничивает каждый контекст единственным потоком
Каждый поток в iOS имеет единственный текущий OpenGL контекст рендеринга ES. Каждый раз, когда Ваше приложение вызывает OpenGL функция ES, OpenGL ES неявно ищет контекст, связанный с текущим потоком, и изменяет состояние или объекты, связанные с тем контекстом.
OpenGL ES не повторно используем. При изменении того же контекста от многократных потоков одновременно результаты непредсказуемы. Ваше приложение могло бы отказать, или оно могло бы представить неправильно. Если по некоторым причинам Вы решаете установить больше чем один поток для предназначения для того же контекста, то необходимо синхронизировать потоки путем размещения взаимного исключения вокруг всего OpenGL вызовы ES к контексту. Команды OpenGL ES, блокирующие — такой как glFinish
— не синхронизируйте потоки.
GCD и NSOperationQueue
объекты могут выполнить Ваши задачи на потоке их выбора. Они могут создать поток в частности для той задачи, или они могут снова использовать существующий поток. Но в любом случае, Вы не можете гарантировать, какой поток выполняет задачу. Для OpenGL приложение ES, означающее:
Каждая задача должна установить контекст прежде, чем выполнить любые команды OpenGL ES.
Две задачи, получающие доступ к тому же контексту, никогда могут не выполняться одновременно.
Каждая задача должна очистить контекст потока перед выходом.
Стратегии реализации параллелизма в OpenGL приложения ES
Параллельное приложение ES OpenGL должно фокусироваться на параллелизме CPU так, чтобы OpenGL ES мог обеспечить больше работы для GPU. Вот несколько стратегий реализации параллелизма в OpenGL приложение ES:
Анализируйте свое приложение в OpenGL ES и не-OpenGL задачи ES, которые могут выполниться одновременно. Ваш код для прорисовки ES OpenGL выполняется как единственная задача, таким образом, он все еще выполняется в единственном потоке. Эта стратегия работает лучше всего, когда Ваше приложение имеет другие задачи, требующие значительной обработки CPU.
Если профилирование производительности показывает, что Ваше приложение проводит много процессорного времени в OpenGL, переместите часть той обработки к другому потоку путем включения многопоточности для OpenGL контекст ES. Преимущество является простотой; включение многопоточности берет одну строку кода. Посмотрите Многопоточный OpenGL ES.
Если Ваше приложение тратит много данных подготовки процессорного времени, чтобы отправить в OpenGL ES, разделить работу между задачами, подготавливающими данные рендеринга и задачи, представляющие команды рендеринга OpenGL ES. Посмотрите Выполняют OpenGL Вычисления ES в Задаче Работника
Если Ваше приложение имеет многократные сцены, оно может представить одновременно или работать, оно может выполнить в многократных контекстах, оно может создать многократные задачи с одним OpenGL контекст ES на задачу. Если контекстам нужен доступ к тем же художественным активам, используйте sharegroup для совместного использования OpenGL объекты ES между контекстами. Посмотрите Использование Многократный OpenGL Контексты ES.
Многопоточный OpenGL ES
Каждый раз, когда Ваше приложение вызывает OpenGL функция ES, OpenGL , ES обрабатывает параметры для помещения их в формат, который понимают аппаратные средства. Время, требуемое обработать эти команды, варьируется в зависимости от того, являются ли вводы уже в благоприятном для аппаратных средств формате, но там является всегда служебным в подготовке команд для аппаратных средств.
Если Ваше приложение проводит много времени, выполняя вычисления в OpenGL ES, и Вы уже предприняли шаги для выбора идеальных форматов данных, приложение могло бы получить дополнительную выгоду путем включения многопоточности для OpenGL контекст ES. Многопоточный OpenGL контекст ES автоматически создает рабочий поток и передает некоторые его вычисления к тому потоку. На многожильном устройстве, включая многопоточность позволяет внутреннему OpenGL вычисления ES, выполняемые на CPU для действия параллельно с приложением, улучшая производительность. Синхронизирующиеся функции продолжают блокировать вызывающий поток.
Чтобы включить OpenGL многопоточность ES, установите значение multiThreaded
свойство Вашего EAGLContext
объект к YES
.
Включение многопоточности означает OpenGL , ES должен скопировать параметры для передачи их к рабочему потоку. Из-за этих издержек всегда тестируйте свое приложение с, и без многопоточности включил, чтобы определить, обеспечивает ли это улучшение исполнения всех условий. Можно минимизировать эти издержки путем реализации собственной стратегии x OpenGL использование ES в многопоточном приложении, как описано в остатке от этой главы.
Выполните OpenGL вычисления ES в задаче работника
Некоторое приложение выполняет много вычислений на их данных перед передачей данных к OpenGL ES. Например, приложение могло бы создать новую геометрию или анимировать существующую геометрию. Где возможно, такие вычисления должны быть выполнены в OpenGL ES. Это использует в своих интересах больший параллелизм, доступный в GPU, и сокращает издержки копирования результатов между Вашим приложением и OpenGL ES.
Подход описал в альтернативах рисунка 6-6 между обновлением OpenGL объекты ES и выполнением команд рендеринга, использующих те объекты. OpenGL ES представляет на GPU параллельно с обновлениями Вашего приложения, работающими на CPU. Если вычисления, выполняемые на CPU, занимают больше времени обработки, чем те на GPU, то GPU проводит больше неактивного времени. В этой ситуации можно быть в состоянии использовать в своих интересах параллелизм в системах с многократным CPUs. Разделите свой OpenGL код рендеринга ES на отдельное вычисление и обработку задач, и выполните их параллельно. Одна задача производит данные, использующиеся вторым и представленным к OpenGL.
Для лучшей производительности избегите копировать данные между задачами. Вместо того, чтобы вычислять данные в одной задаче и копировать его в буферный объект вершины в другом, отобразитесь, буферный объект вершины в установке кодируют и вручают указатель непосредственно на задачу работника.
Если можно далее анализировать задачу модификаций в подзадачи, можно видеть лучшие преимущества. Например, примите два или больше буферных объекта вершины, каждый из которых должен быть обновлен прежде, чем представить команды рисования. Каждый может быть повторно вычислен независимо от других. В этом сценарии модификации к каждому буферу становятся работой, с помощью NSOperationQueue
объект управлять работой:
Установите текущий контекст.
Отобразите первый буфер.
Создайте
NSOperation
возразите, чья задача состоит в том, чтобы заполнить тот буфер.Очередь, что работа на очереди работы.
Выполните шаги 2 - 4 для других буферов.
Вызвать
waitUntilAllOperationsAreFinished
на очереди работы.Не отобразите буферы.
Выполните команды рендеринга.
Используйте многократный OpenGL контексты ES
Один общий подход для использования многократных контекстов должен иметь один контекст, обновляющий OpenGL объекты ES, в то время как другой использует те ресурсы, с каждым контекстом, работающим на отдельном потоке. Поскольку каждый контекст работает на отдельном потоке, его действия редко блокируются другим контекстом. Для реализации этого приложение создало бы два контекста и два потока; каждый поток управляет одним контекстом. Далее, любой OpenGL , ES возражает Вашему приложению, намеревается обновить на втором потоке, должен быть дважды буферизован; поток потребления может не получить доступ к OpenGL объект ES, в то время как другой поток изменяет его. Процесс синхронизации изменений между контекстами описан подробно в EAGL Sharegroup, Управляет OpenGL Объекты ES для Контекста.
GLKTextureLoader
класс реализует эту стратегию обеспечить асинхронную загрузку данных текстуры. (См. Использование Платформа GLKit для Загрузки Данных Текстуры.)
Инструкции для поточной обработки OpenGL приложения ES
Следуйте этим инструкциям для обеспечения успешной поточной обработки в приложении, использующем OpenGL ES:
Используйте только один поток на контекст. Команды OpenGL ES для определенного контекста не ориентированы на многопотоковое исполнение. Никогда не имейте больше чем один поток, получающий доступ к единственному контексту одновременно.
При использовании GCD используйте специализированную последовательную очередь для диспетчеризации команд OpenGL ES; это может использоваться для замены стандартного взаимоисключающего образца.
Отслеживайте текущий контекст. При переключении потоков просто переключить контексты непреднамеренно, который вызывает непредвиденные эффекты на выполнение графических команд. Необходимо установить текущий контекст при переключении на недавно создаваемый поток и очистить текущий контекст прежде, чем оставить поток.