Портирование приложений OpenGL* на Android* на Intel® Atom (часть 2)

Эта статья является продолжением серии из двух статей, в которой рассматриваются проблемы, возникающие в процессе портирования преложений на OpenGL на платформу Google Android. В данной статье рассматриваются ограничения, связанные с различиями расширений OpenGL, поддержкой операций с плавающей запятой, сжатыми форматами текстур и библиотекой OpenGL Utility Library (GLU). Кроме того, здесь описана настройка системы разработки для Android на базе процессоров Intel® Atom и пути достижения максимально возможной производительности в средствах эмуляции виртуального устройства Android при использовании OpenGL ES.

В первой части данной серии статей содержится информация об использовании OpenGL ES на платформе Android с помощью пакета средств разработки программного обеспечения (SDK) или пакета Android NDK (Native Development Kit) и о том, по какому принципу выбирается тот или иной пакет. В ней описаны различные примеры приложений OpenGL ES в SDK и NDK и интерфейс Java* Native Interface, позволяющий комбинировать компоненты Java и C/C++.

Препятствия при портировании приложений OpenGL для настольных ПК

API-интерфейс OpenGL ES 1.1 является подмножеством API-интерфейсов OpenGL 1.x, которые использовались в настольных системах Linux* и Windows* на протяжении десятилетий. Аналогично API-интерфейс OpenGL ES 2.0 является подмножеством API-интерфейса OpenGL 2.0 для настольных систем. Поэтому любое портирование следует начать с оценки набора функций OpenGL, используемых в коде приложения, определения того насколько стар этот код и какие его части необходимо переписать по причине различий между используемой версией OpenGL и целевой версией OpenGL ES на Android.

Основные различия между OpenGL 2.0 и OpenGL ES 2.0 можно разделить на три категории: спецификации геометрии, преобразования геометрии и изменения в языке GLSL (OpenGL Shading Language). OpenGL 2.0 позволяет задавать спецификацию геометрии четырьмя способами: с помощью непосредственного режима (immediate mode), списков отображения (display lists), массивов вершин (vertex arrays) и объектов буфера вершин (vertex buffer objects). OpenGL ES 2.0 не поддерживает непосредственный режим (блоки glBegin и glEnd) и списки отображения, поэтому задавать геометрию необходимо с помощью массивов вершин или объектов буфера вершин.

В OpenGL 2.0 есть функции для загрузки матриц модели-вида (model view), проекции (projection) и текстуры (texture), а также функции, упрощающие совместное использование этих матриц, например glTranslate, glRotate и glScale. В OpenGL ES 2.0 нет ни этих функций, ни функций освещения, поскольку фиксированный конвейер (fixed-function pipeline) был заменен на модель программирования шейдеров. В OpenGL ES 2.0 расчеты матриц и освещения должны выполняться в вершинном шейдере (vertex shader).

Язык шейдеров для OpenGL ES 2.0 (GLSL ES) также является подмножеством языка шейдеров для настойной версии OpenGL 2.0 (GLSL). Одно основное отличие состоит в том, что язык GLSL включает в себя встроенные переменные для доступа к состояниям в фиксированном конвейере вершинного шейдера (например, gl_ModelViewMatrix). Поскольку OpenGL ES 2.0 не поддерживает фиксированный конвейер, эти переменные не поддерживаются в GLSL ES.

В OpenGL ES 2.0 отсутствуют следующие функции OpenGL 2.0:

  • Спецификация геометрии с помощью непосредственного режима
  • Спецификация геометрии с помощью списка отображения
  • Обработка всего фиксированного конвейера
  • Фиксированные преобразования и освещенность
  • Матричный стек и преобразования матриц
  • Пользовательские плоскости отсечения
  • Сглаживание и пунктирное отображение линий и многоугольников
  • Пиксельные прямоугольники и растровые изображения
  • Одномерные текстуры и некоторые режимы обертывания текстур
  • Запросы на перекрытие
  • Туман

Примечание. Сведения о других отличиях OpenGL 2.0 от OpenGL ES 2.0 см. по адресу http://software.intel.com/en-us/articles/targeting-3d-applications-for-mobile-devices-powered-by-opengl-and-opengl-es.

Портирование из других встроенных систем

Приложение OpenGL ES обычно проще портировать на Android из других встроенных систем, чем из настольных систем с OpenGL, поскольку в большинстве встроенных систем, как и в Android, используются спецификации OpenGL ES 1.1 и 2.0. При портировании кода OpenGL ES из другой встроенной системы наиболее важные отличия обычно касаются поддержки расширений OpenGL ES, а именно сжатых форматов текстур. Еще одним источником проблем могут стать различия в поддержке операций с плавающей запятой между встроенными системами.

Поддержка операций с плавающей запятой

Ранние реализации OpenGL ES 1.0 и 1.1 поставлялись в двух версиях — Common и Common-Lite. Версия Common предназначалась для процессоров с поддержкой аппаратной обработки операций с плавающей запятой; версия Common-Lite — для процессоров без такой поддержки, требующих использования расчетов с фиксированной запятой. Поскольку для Android требуются процессоры, поддерживающие операции с плавающей запятой, такие как Intel Atom, необходимость в использовании фиксированной запятой не возникает никогда, и образы системы Android, предоставленные компанией Google, включают в себя только драйверы Common для OpenGL ES 1.1 (с поддержкой плавающей запятой). Стандарт Khronos для OpenGL ES 2.0 предусматривает только операции с плавающей запятой. Это нужно учитывать при портировании игры OpenGL ES 1.0 или 1.1 из другой встроенной системы, использующей реализацию Common-Lite стандарта OpenGL ES, поскольку вы должны будете преобразовать все имеющиеся в коде расчеты с фиксированной запятой в формат с плавающей запятой (так как в Android доступна только версия Common стандарта OpenGL ES). Драйверы Common и Common-Lite во встроенных системах Linux обычно имеют имена, похожие на libGLESv1_CM.so и libGLESv1_CL.so.

Если код OpenGL портируется из приложения для настольных ПК, то, скорее всего, в нем уже используются операции с плавающей запятой. Однако следите за тем, чтобы код не включал в себя операции с плавающей запятой с двойной точностью. Android поддерживает операции с плавающей запятой с двойной точностью, но OpenGL ES поддерживает только одинарную точность. По этой причине перед переносом кода OpenGL ES 1.1 или 2.0 необходимо преобразовать все значения с двойной точностью в значения с одинарной точностью.

Расширения OpenGL

Одно из наиболее значительных препятствий при портировании кода OpenGL на другую платформу возникает в связи с использованием в коде приложения расширений OpenGL и библиотеки EGL (Embedded System Graphics Library). Необходимо на раннем этапе портирования выяснить, какие расширения используются в старом коде, и сравнить их с расширениями, доступными на целевых устройствах Android. Расширение — это реализованный разработчиками графического процессора способ предоставления доступа к специальным возможностям графического процессора, выходящими за рамки стандартных спецификаций OpenGL. Для каждого использованного в старом коде расширения, недоступного на целевой платформе, потребуется написать новый код, позволяющий обойтись без этого расширения, или использовать другое расширение.

Поддерживаемые расширения существенно различаются в разных версиях OpenGL и даже на разных платформах Android из-за различий в архитектуре графического процессора. Системы с процессорами Intel Atom оснащаются графическими процессорами PowerVR*, представляющими наиболее распространенную архитектуру графических процессоров в современных мобильных устройствах. При создании приложений для Android не следует полагаться на то, что определенное расширение OpenGL ES будет доступно на любом устройстве. Приложение должно запрашивать список доступных расширений OpenGL ES во время выполнения. Такие списки расширений можно получить из драйверов OpenGL ES и EGL с помощью следующих функций:

  • glGetString(GL_EXTENSIONS); 
  • eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);

Имена всех функций и перечислений, необходимых для вызова расширений, определены в файлах заголовков glext.h, gl2ext.h и eglext.h, поэтому после того, как приложение проверит доступность определенного расширения во время выполнения, его можно будет непосредственно вызвать.

На веб-сайте Google Play предлагается полезное приложение OpenGL Extensions Viewer (GLview), выполняющее данный запрос и отображающее полученную информацию для любого устройства Android, на котором оно запускается. Было бы неплохо, если бы вы сами протестировали несколько устройств Android на наличие нужных расширений средством, подобным GLview. Кроме того, Khronos поддерживает реестр API-интерфейсов OpenGL ES для всех известных расширений OpenGL ES — используйте этот важный источник информации.

Сжатые форматы текстур

Наиболее важные расширения OpenGL ES обеспечивают поддержку сжатых текстур. Эта важная технология используется в большинстве 3D-игр для снижения требований к памяти и повышения производительности, но форматы, применяемые в OpenGL ES, определяются только расширениями и поэтому различаются для каждой платформы. К сожалению, единственным форматом, который поддерживается на всех устройствах Android (кроме устройств первого поколения, не поддерживавших OpenGL ES 2.0) является ETC1 (Ericsson Texture Compression). Формат ETC1 обеспечивает точность только 8 бит на пиксель и не поддерживает альфа-канал. Так как в большинстве игр используются сжатые текстуры с альфа-каналом, это часто затрудняет процесс портирования. Несколько архитектурно-зависимых форматов для различных платформ Android поддерживают альфа-канал, но при их использовании ваша игра будет работать только на устройствах Android с данной архитектурой графического процессора. В таблице 1 приведен список архитектур графических процессоров и соответствующих сжатых форматов текстур для Android.

Таблица 1. Архитектурно-зависимые сжатые форматы текстур с поддержкой альфа-канала

Архитектура графического процессора Форматы текстур
PowerVR PVRTC
ATI/AMD ATITC/3DC
NVIDIA Tegra* 2/3 DXT/S3TC

Графический процессор PowerVR на системах с процессором Intel Atom помимо ETC1 поддерживает форматы PVRTC. PVRTC поддерживает альфа-канал и точность 2 или 4 бит на пиксел, что помогает значительно уменьшать размер текстур по сравнению с форматом ETC1. PVRTC — самый массовый формат после ETC1, который также используется на всех поколениях устройств Apple iPhone*, iPod touch* и iPad*, поэтому он обеспечивает некоторую совместимость с устройствами Android на процессорах Intel Atom за рамками базового стандарта OpenGL ES, что имеет важное значение при портировании игр на платформы Android и Apple iOS*. Тем не менее остаются устройства Android с другими архитектурами графических процессоров, для которых также требуется решение. Если в вашем приложении используются любые архитектурно-зависимые форматы текстур, оно должно запрашивать расширения OpenGL ES во время выполнения для определения доступных форматов и использовать только текстуры, которые были сжаты в этом формате. Нужно принять непростое проектное решение. Варианты таковы:

  • Не поддерживать устройства Android с другими архитектурами графических процессоров.
  • Предоставить текстуры, сжатые во всех трех архитектурно-зависимых форматах.
  • Не использовать сжатие текстур с альфа-каналом.
  • Разделить цветовые и альфа-компоненты на пары файлов ETC1 и совмещать их во фрагментном шейдере (fragment shader).

Приняв решение о том, какие архитектурно зависимые форматы должны присутствовать в вашем приложении, не забудьте объявить их в файле манифеста, как будет описано далее. Дополнительные сведения см. в статье о поддержке сжатия текстур [Eng].

Библиотека GLU

Версии OpenGL для настольных ПК обычно включают в себя библиотеку утилит OpenGL (GLU), содержащую функции для упрощения работы. В библиотеку GLU входят функции, не относящиеся напрямую к OpenGL и необязательные для использования OpenGL, но они могут быть полезны при создании 3D-приложений для OpenGL. Обычно библиотека GLU включает в себя функции для конструирования матриц модели-вида и проекции, выполнения общих матричных расчетов, расчета поверхностей с произвольной геометрией (quadric), тесселяции полигонов (tessellation), генерации мип-карт (mipmap) и вывода сообщений об ошибках. Во многих играх OpenGL для настольных ПК используются некоторые функции GLU, что может вызвать проблемы, поскольку в Android реализован только минимум возможностей GLU и они доступны только в SDK. Эти классы перечислены в таблице 2.

Таблица 2. Сводная информация о классах Android с поддержкой функций GLU

Класс Функция
android.opengl.GLU Создание матриц проекции для OpenGL ES
android.graphics.Matrix Создание матриц модели вида и общих матриц

В OpenGL ES 1.1 и 2.0 поддерживается генерация мип-карт и отсутствует поддержка расчета поверхностей с произвольной геометрией и тесселяции полигонов. Если эти функции необходимы, существуют другие реализации GLU с открытым исходным кодом, более полные и совместимые с Android NDK, например GLU ES.

Объявление OpenGL ES в файле манифеста

Приложения, требующие OpenGL ES, должны содержать соответствующую декларацию в файле манифеста. Это поможет предотвратить установку вашего приложения на устройства, не поддерживающие требуемую версию OpenGL ES. В следующих примерах показан правильный синтаксис обязательных параметров манифеста в файле AndroidManifest.xml.

OpenGL ES 1.1:

  • <uses-feature android:glEsVersion="0x00010001" android:required="true" />
  • <uses-sdk android:minSdkVersion="4"/>

OpenGL ES 2.0:

  • <uses-feature android:glEsVersion="0x00020000" android:required="true" />
  • <uses-sdk android:minSdkVersion="8"/>

В Android 4.0 (API level 14) было представлено важное изменение — аппаратное ускорение OpenGL ES теперь включено по умолчанию для всех приложений, в которых декларируется параметр minSdkVersion со значением 14 или выше. Приложения могут включать ускорение на более низких уровнях API путем добавления атрибута android:hardwareAccelerated=“true” в тег <application>. Если ваше приложение использует новые функции Android 4.0, требующие аппаратного ускорения OpenGL ES, например класс TextureView, его необходимо включить в файле манифеста, иначе эти функции не будут работать.

Если ваше приложение использует класс NativeActivity, он должен быть объявлен в файле манифеста и должно быть указано имя библиотеки общих объектов, содержащей действие NativeActivity. Параметр minSdkVersion также должен иметь значение 9 или выше. См. пример в образце приложения native-activity в NDK.

Если в вашем приложении используются сжатые текстуры, их следует объявить, как показано далее. Это не помешает установке вашего приложения на устройствах, не поддерживающих данные функции, поэтому по-прежнему важно во время выполнения запросить данные об имеющихся на устройстве расширениях для необходимых архитектурно-зависимых форматов. С помощью этих параметров манифеста внешние службы, такие как Google Play, отфильтровывают приложения, не работающие на устройствах, которые не поддерживают необходимые форматы текстур.

Параметры манифеста, необходимые при использовании сжатых форматов текстур:

  • <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
  • <supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
  • <supports-gl-texture android:name="GL_IMG_texture_compression_pvrtc" />

Настройка системы разработки под Android для процессоров Intel Atom

При настройке своей системы разработки под Android обязательно выберите версию Android со встроенной поддержкой процессоров Intel Atom. Таким образом, вы сможете запускать свои приложения на устройствах Intel Atom и использовать системные образы AVD (Android Virtual Devices) с эмуляцией Intel Atom. В таблице 3 собрана информация обо всех основных версиях Android до сегодняшнего дня и о том, для каких из них доступны системные образы с эмуляцией встроенных процессоров Intel Atom.

Таблица 3. Сводная информация о версиях Android с поддержкой OpenGL ES и процессоров Intel® Atom

Версия Название API Поддерживает Поддерживает Intel Atom
Android 1.5 Cupcake 3 OpenGL ES 1.0 Нет
Android 1.6 Donut 4 OpenGL ES 1.0, 1.1 Нет
Android 2.0 Éclair 5 OpenGL ES 1.0, 1.1 Нет
Android 2.1 Éclair 7 OpenGL ES 1.0, 1.1 Нет
Android 2.2 Froyo 8 OpenGL ES 1.0, 1.1, 2.0 Нет
Android 2.3.3 Gingerbread 10 OpenGL ES 1.0, 1.1, 2.0 Да
Android 3.0 Honeycomb 11 OpenGL ES 1.0, 1.1, 2.0 Нет
Android 3.1 Honeycomb 12 OpenGL ES 1.0, 1.1, 2.0 Нет
Android 3.2 Honeycomb 13 OpenGL ES 1.0, 1.1, 2.0 Нет
Android 4.0 Ice Cream Sandwich 14 OpenGL ES 1.0, 1.1, 2.0 Нет
Android 4.0.3 Ice Cream Sandwich 15 OpenGL ES 1.0, 1.1, 2.0 Да
Android 4.1 Jelly Bean 16 OpenGL ES 1.0, 1.1, 2.0 Да

Версии Android 2.3.3 (Gingerbread), 4.0.3 (Ice Cream Sandwich) и 4.1 (Jelly Bean) полностью поддерживают процессоры Intel Atom, включая драйверы для OpenGL ES 1.0, 1.1 и 2.0. Просто выберите одну из этих версий в Android SDK Manager и убедитесь, что в списке есть системный образ Intel x86 Atom System Image. Кроме того, загрузите и установите Intel® Hardware Accelerated Execution Manager (HAXM), который указывается в разделе Extras в SDK Manager. Если вы еще не установили средство Android SDK Manager, его можно загрузить по адресу http://developer.android.com/sdk/index.html.

SDK Manager загружает программу установки HAXM и помещает ее в папку Extras, но для завершения установки необходимо запустить программу установки HAXM вручную. Необходимо также включить функцию Virtualization Technology в меню установки ROM BIOS на компьютере, который используется для разработки. Программа установки HAXM находится в папке …\android-sdk\extras\intel\Hardware_Accelerated_Execution_Manager. При запуске эмулятора x86 AVD с правильно установленным средством HAXM отображается следующее сообщение: "HAX is working and emulator runs in fast virt mode" (Средство HAX запущено, и эмулятор работает в быстром виртуальном режиме)

Использование системных образов x86 и HAXM с эмулятором AVD

Любому разработчику приложений для встроенных систем известно, насколько ускоряет работу эмулятор виртуального устройства. Но с системным образом ARM эмулятор AVD работает невыносимо медленно, поскольку он должен эмулировать каждую инструкцию ARM в системе разработки на базе Windows или Linux. На типичном эмуляторе AVD с ARM одна лишь загрузка Android может занять 5 минут. Для решения этой проблемы компания Intel выпустила средство HAXM, запускающее системные образы Android x86 непосредственно с помощью функции Virtualization Technology, встроенной в новые процессоры Intel для настольных ПК. Если вы установите и будете использовать это средство для работы с AVD и системным образом Intel Atom x86, это позволит значительно ускорить разработку приложений, и для начала работы вам даже не понадобится устройство с Intel Atom.

Компания Google добавила поддержку OpenGL ES 2.0 в эмулятор AVD, начиная с версии SDK Tools 17 (Android 4.0.3 r2) в апреле 2012 года. Это позволяет транслировать вызовы OpenGL ES 2.0 в функции API OpenGL 2.0, доступные в операционной системе компьютера, что намного ускоряет обработку 3D-графики. Однако эта функция должна быть специально включена при создании AVD; иначе вызовы OpenGL ES 2.0 возвращают ошибку. В операционной системе Windows или Linux на компьютере также должны быть установлены драйверы для OpenGL 2.0 (или более поздней версии), что, в свою очередь, обычно требует наличия установленного отдельного графического адаптера. Эмуляция OpenGL ES 2.0 работает в системных образах ARM и x86, но для достижения максимальной производительности используйте системный образ x86 с включенным HAXM. Разница в производительности огромна.

Чтобы включить эмуляцию OpenGL ES 2.0, выберите AVD в средстве AVD Manager и щелкните Edit (Изменить). Затем в окне Hardware Properties (Свойства оборудования) щелкните New (Создать); прокрутите вниз список свойств и найдите элемент GPU emulation (Эмуляция графического процессора), затем щелкните OK. Измените значение этого свойства с no на yes и щелкните Edit AVD (Изменить AVD), затем щелкните OK для сохранения изменений. Должно появиться сообщение hw.gpu.enabled=yes.

До версии SDK Tools 17 эмуляция AVD поддерживала только OpenGL ES 1.0 и 1.1. Включение эмуляции графического процессора необязательно для версии 1.1, поскольку эмуляция может выполняться без помощи операционной системы компьютера, хотя и намного медленнее. Пакет SDK Tools не может эмулировать версию 2.0 без помощи операционной системы компьютера, и при ее отсутствии AVD просто закрывает ваше приложение, когда пытается инициализировать OpenGL ES 2.0.

В качестве первоначального теста для проверки эмуляции OpenGL ES 2.0 используйте образец приложения HelloEffects. Образец GLES20TriangleRenderer при выполнении на AVD просто восстанавливает версию 1.1, поэтому он неприменим в качестве теста. Все образцы OpenGL ES 2.0, включенные в Android SDK и NDK, достаточно примитивны и не должны рассматриваться как полноценные тесты эмуляции OpenGL 2.0.

Intel® Graphics Performance Analyzers

Еще одним важным набором средств, доступных разработчикам приложений на базе OpenGL ES для устройств Android с процессорами Intel Atom, являются анализаторы производительности графики Intel® (Intel® GPA). Этот набор средств позволяет в режиме реального времени отслеживать десятки критически важных системных метрик, оценивающих параметры ЦП, графического процессора и OpenGL ES. Анализаторы Intel GPA выполняются в системах разработки Windows или Ubuntu Linux и взаимодействуют с компонентами драйверов, работающих на целевом устройстве Android, через отладочный интерфейс Android. Проведя несколько экспериментов, вы можете быстро визуально выявить критические секции графического конвейера и определить наиболее перспективные пути оптимизации кода.

Получить дополнительные сведения и загрузить последнюю версию Intel GPA (2012 R4) для разработки под Android можно по адресу http://software.intel.com/en-us/vcsource/tools/intel-gpa?cid=sem121p7972.

Заключение

Постоянное улучшение поддержки OpenGL ES и C/C++ в Android помогло устранить часть трудностей, связанных с портированием игр и других приложений, интенсивно использующих 3D-графику, на платформу Android, в том числе на устройства на базе процессоров Intel Atom. Тем не менее некоторые препятствия остаются, и важно изучить их, прежде чем начинать проект портирования игры. Наиболее важные препятствия касаются отличий в поддержке расширений OpenGL и сжатых форматов текстур на Android. Можно порадоваться тому, что компании Google и Intel за последние годы совершили внушительный скачок вперед, усовершенствовав средства разработки для OpenGL ES 2.0, и перед разработчиками ПО открылись широкие возможности по адаптации накопившегося к сегодняшнему дню огромного количества игр, игровых движков и других старых программ на базе стандарта OpenGL.

Об авторе

Клэй Д. Монтгомери (Clay D. Montgomery) является одним из ведущих разработчиков драйверов и приложений для OpenGL во встроенных системах. Он участвовал в разработке аппаратных графических ускорителей, графических драйверов, API-интерфейсов и приложений OpenGL для различных платформ в компаниях STB Systems, VLSI Technology, Philips Semiconductors, Nokia, Texas Instruments, AMX и в качестве независимого консультанта. Он сыграл важную роль в разработке некоторых первых драйверов OpenGL ES, OpenVG* и SVG, приложений для платформ Freescale i.MX и TI OMAP* и графических ядер Vivante, AMD и PowerVR. Кроме того, он подготовил и провел ряд семинаров по разработке на базе OpenGL ES во встроенных системах Linux и являлся представителем нескольких компаний консорциума Khronos Group.