company_banner

Запуск физического движка Bullet Physics на Android х86

  • Tutorial

Источник фото
Постоянный рост вычислительной мощности мобильных устройств способствует развитию мобильных игр. В мобильном сегменте появился целый класс игр, который славится реалистичной графикой и правдоподобной физикой. Такие эффекты как взрыв гранаты в шутере, занос машины в гонке ложатся на плечи физического движка. В основе физического движка заложены математические модели, которые просчитываются в процессе игры. Как правило это вычислительные задачи и от того насколько быстро и качественно физический движок справляется с ними зависит привлекательность игры.
В этой статье показано, как собрать и портировать физический движок Bullet Physics на платформу Android на базе процессора Intel Atom.

Bullet Physics


Bullet Physics Library – физический движок реального времени, который активно используется в компьютерных играх, фильмах, программах трёхмерного моделирования, как компонент других игровых движков и во множестве других более специфичных случаях. В середине 2011 года появилась версия, поддерживающая ОС Android и включающая в себя оптимизированные под ARM NEON функции.
Bullet Physics собирается под архитектуру ARM из коробки. Такое приложение на телефонах с процессором Intel Atom будет работать через эмулятор.
Устройство ARM версия x86 версия
Samsung Galaxy tab 3 10.1 30 FPS 60 FPS

Таблица 1. Сравнение производительности (FPS – кадры в секунду) ARM и x86 версий демонстрационного приложения из Bullet Physics.
В таблице 1 приведено сравнение запусков приложения, собранного под разные архитектуры. Замеры производились с помощью инструмента профилирования графики Intel GPA. Для того, чтобы достичь максимальной эффективности работы и производительности на устройствах на базе Intel Atom – приложение должно быть портировано на архитектуру x86.
Повысив скорость обсчета физики в своей игре разработчик получает дополнительный временной бюджет кадра, который он может потратить либо на более реалистичную графику либо на более физичную модель.

Подготовка


Для сборки и портирования нам потребуется:

Весь процесс будет проходить на Windows, для Linux/Mac OS принципиально отличаться не будет. Производить тестовые запуски будем на Lenovo K900 и Samsung Galaxy Tab 3 10.1. Оба устройства на базе процессора Intel Atom Z2460.
К статье приложен скрипт, который производит все описанные действия в автоматическом режиме. Далее рассмотрим как собрать Bullet Physics в ручном режиме.

Сборка


Сначала соберем и запустим демонстрационное приложение PfxApp_1_Simple под ARM.
image
Рисунок 1. Демонстрационное приложение PfxApp_1_Simple (устройство Samsung Galaxy tab 3 10.1).
Cоберем основную компоненту физического движка — библиотеку PfxLibrary. Для этого, перейдем в проектную директорию библиотеки:
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxLibrary\jni

<BulletPhysics> – это путь, по которому находится проект bullet-2.80-rev2531. В этой директории откроем файл “Android.mk”, найдем и изменим переменную
LOCAL_PATH := <BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects

Далее, откроем консоль. В консоли перейдем по пути
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxLibrary

и выполним команду:
ndk-build

Мы собрали библиотеку PfxLibrary под armeabi-v7a.
Теперь соберем само демо приложение. Для этого, передем в директорию
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxApp_1_Simple\jni

В этой директории откроем файл “Android.mk”, изменим переменную
LOCAL_PATH := “<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects

Далее, откроем консоль. В консоли перейдем в директорию проекта приложения по пути
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxApp_1_Simple

и выполним команду “ndk-build”. Для того чтобы запустить собранное приложение PfxApp_1_Simple на устройстве, будем использовать Eclipse. В Eclipse делаем импорт проекта:
File => Import => Android => Existing Android Code Into Workspace => Browse… => \bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxApp_1_Simple\” => OK => Finish
и запускаем приложение на устройстве. Для этого кликаем правой кнопкой мыши на проект и нажимаем: Run As => Android Application.
image
Рисунок 2. Запуск приложения из Eclipse IDE.
Приложение PfxApp_1_Simple запустилось но работает в режиме эмуляции.

Портирование


Соберем и запустим PfxApp_1_Simple под x86. Сначала портируем библиотеку PfxLibrary под x86. Для этого, вернемся в директорию проекта библиотеки
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxLibrary\jni

Откроем файл “Application.mk”, в котором изменим переменную
APP_ABI := x86

Затем откроем файл “Android.mk”, в котором изменим переменные
LOCAL_PATH := <BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -DUSE_PTHREADS –pthread
LOCAL_ARM_NEON := false

и удалим строки из LOCAL_SRC_FILES, чтобы убрать исходные файлы, оптимизированные под ARM Neon:
src/base_level/solver/pfx_constraint_row_solver_neon.cpp
include/vecmath/neon/vectormath_neon_assembly_implementations.S

Пересоберем физический движок. В консоли перейдем по пути:
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxLibrary

и выполним команду “ndk-build”. Мы собрали библиотеку PfxLibrary под x86. Теперь соберем само приложение под x86. Для этого, перейдем в директорию проекта приложения
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxApp_1_Simple\jni

В этой директории откроем файл “Application.mk”, изменим переменную
APP_ABI := x86

Затем откроем файл “Android.mk”, в котором изменим переменные
LOCAL_PATH := “<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects
LOCAL_SRC_FILES := project/Android/PfxLibrary/obj/local/x86/libpfxlibrary.a
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
LOCAL_ARM_NEON := false

и удалим строки из LOCAL_SRC_FILES, такие как
         “sample/test_ARM_NEON_performance/neon_dot_product.S \”,
       	 “sample/test_ARM_NEON_performance/neon_cross_product.S \”,
         “sample/test_ARM_NEON_performance/neon_matrix4_operator_multiply.S \”,
         “sample/test_ARM_NEON_performance/neon_matrix3_operator_multiply.S \”,
       	 “sample/test_ARM_NEON_performance/neon_orthoInverse_transform3.S \”,
       	 “sample/test_ARM_NEON_performance/neon_transform3_operator_multiply.S \”,
       	 “sample/test_ARM_NEON_performance/neon_transpose_matrix3.S \”,
         “sample/test_ARM_NEON_performance/test_neon_cross_product.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_dot_product.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_matrix3_operator_multiply.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_matrix4_operator_multiply.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_orthoInverse_transform3.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_transform3_operator_multiply.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_transpose_matrix3.cpp \”,
         “sample/test_ARM_NEON_performance/test_neon_solve_linear_constraint_row.cpp”.

Далее, в консоли перейдем в директорию проекта по пути
<BulletPhysics>\bullet-2.80-rev2531\Extras\PhysicsEffects\project\Android\PfxApp_1_Simple

и выполним команду “ndk-build”. Запускаем приложение на устройстве.
Для проверки результата использалось приложение APK Info.
image
Рисунок 3. Скриншоты APK Info (устройство Lenovo K900).

Заключение


В статье приведена пошаговая инструкция как собрать и портировать физический движок Bullet Physics. Результатом успешного портирования на архитектуру x86, для конкретного примера, можно считать двукратное ускорение вычислений физики, как следствие – повышение частоты обновления кадров (FPS).

Об авторах


Илья Крюков (ilya.krjukov@intel.com)
Денис Смирнов (denis.smirnov@intel.com)
Intel
Компания

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

    0
    Я правильно понял, что в процессе портирования были исключены оптимизированные варианты некоторых функций (вместе с файлами, их содержащими), и вместо них проект подхватил их generic-реализации, написанные на C++ и потому компилирующиеся как на ARM, так и на IA-32?
    В таком случае насколько, по вашему мнению, оправдано в дальнейшем написание аналогично соптимизированных (например, c задействованием асма/интринсиков SSE/AVX) специализаций этих функций для IA-32? Ожидаете ли вы дополнительного прироста в скорости работы движка от подобных усилий?
      +2
      В данном случае исключаются не компоненты библиотеки, а некоторый семпл, просто являющийся частью общего комплекта библиотеки.

      Еще учтите, что движок изначально кросс-платформенный. Поэтому, интринсики SSE там есть. Другое дело, что они не работают, но это не относится к теме поста.
        0
        … некоторый семпл ...
        Действительно, сами пути к файлам на это намекают:
        sample/test_ARM_NEON_...

          0
          Мы исключили компоненты самой библиотеки, оптимизированные под ARM:
          src/base_level/solver/pfx_constraint_row_solver_neon.cpp
          include/vecmath/neon/vectormath_neon_assembly_implementations.S
          

          Да, сэмплы удалили тоже :)
        0
        Да, вы поняли правильно — под ARM взята версия из коробки, а под х86 потребовались небольшие изменения, но они окупились. :)
        Для того чтобы ответить на ваше вопрос нужно сначала проанализировать какой ассемблер генерится компилятором, если он не векторизует критические к производительности участки кода, то тогда необходима ручная модификация, например, переписывание на интринсики или ассемблерные вставки. Такой анализ мы еще не проводили.
          0
          Судя по вашему приросту производительности, код генерится компилятором отличный. Хотя, нет в мире совершенства, может, что-то и улучшится, особенно, если заработает SSE часть.
        0
        А все таки какова скорость для ARM с включенным неоном?
          0
          Уточню вопрос:
          Данный девайс IA32 архитектуры?
          ARM на нем исполняется через трансляцию?
            +1
            Отвечаю на свой же вопрос
            Да он IA32
            Да ARM через трансляцию.

            То есть ваш вывод на мой взгляд должен быть немного другим:
            Разработчикам обязательно надо собирать две версии ABI IA32 и ARM а андроид сам загрузит нужный.
            А вот слова про «можно считать двукратное ускорение вычислений физики» это уже передергивание, так как в вашем случае идет транслция с ARM в IA32.

            Поправите меня если я неправ?
              0
              Да, оба раза приложение запускается на IA32 девайсе, сначала через трансляцию. А вывод «Результатом успешного портирования на архитектуру x86, для конкретного примера, можно считать двукратное ускорение вычислений физики» абсолютно корректен (ускорение в сравнении с непортированной версией), как и корректно то, что вы говорите, одно другому не противоречит.
                0
                Ok
          +1
          В «Таблица 1.» сравнивается производительность нативного x86 кода с работой эмулятора ARM на x86? Это же на голову не налазит, вы бы еще с эмулятором PS1 под Android скорость сравнивали!
          Ну и числа 30 FPS и 60 FPS тоже никуда не годятся — уж очень они похожи на лимит vsync. Чтобы тест был адекватным надо проверять на двух реальных устройствах с похожими параметрами. Причем, сцену надо нагрузить так, чтобы FPS сам по себе просел из-за физики ниже порогового значения, хоть до 40 FPS в x86 варианте. Естественно, надо делать это с минимумом отрисовки, чтобы не оказалось, что сравниваются видеочипы.
          Ну и в конце-концов, я не вижу «портирования» в каком-либо виде — ни одной строки кода не было изменено, только небольшие правки конфигов для смены build target.
            0
            Там нет эмулятора. Houdini — компонета, транслирующая бинарный ARM код в код x86. Причем, перед выполнением, а не во время. Ничего не эмулируется.
            Насчет портирования выабсолютно правы, я именно это и сказала авторам, они общали подумать :). Но, с другой стороны, это отличная новость для разработчиков. Если все, что им надо для «портирования» — это сменить конфиги, то сделать это явно стОит, даже если бы прирост не был столь велик.
              0
              Давайте называть вещи своими именами — трансляция кода одной архитектуры на другую это именно разновидность эмуляции (emulation refers to the ability of a computer program in an electronic device to emulate (imitate) another program or device). Красивые ярлыки вроде Houdini, Rosetta или QuickTransit не отменяют факт, что производительность такого решения будет далека от нативной.
              Статья имеет право на жизнь лишь из-за того, что подтверждает факт, что кросс-платформенная Bullet Physics компилируется под NDK почти без бубна, и это здорово. Но стоит ее дополнить удачными замерами скорости и чуть уменьшить гремящую «канцелярщину» в стиле, как посыплются плюсы и благодарности :)
                –1
                О, да, давайте называть вещи своими именами. Тогда по-вашему получается, что любой компилятор- это эмулятор, ведь он переводит программу, написанную на английском языке в машинный код конкретного процессора, т.е. эмулирует то, что напрямую можно написать в машинном коде :)
                А производительность далека от нативной по простой причине -при прямой компиляции идет оптимизация под конкретный процессор, скажем, автовекторизация, а при переводе -не идет.
              +4
              Спасибо большое за идею исследовать масштабируемость данного приложения. Мы решили провести «усложненный» тест производительности. Демонстрационное приложение из статьи вычисляет взаимодействие 192 коробок, падающих на плоскость. Мы заставили наше устройство попотеть — увеличили число коробок в 16 раз — 3072 штуки.
              image
              ARM версия — 2 fps
              x86 версия — 4 fps
              Замеры проводились на одном и том же устройстве Samsung Galaxy tab 3 10.1, брали средний FPS за минуту работы приложения.
              Чтобы убедиться, что данное приложение является CPU-bound, то есть львиная доля работы приходится именно на вычислительную составляющую мы воспользовались возможностью Intel GPA — Disable Draw Calls (данный эксперимент эмулирует бесконечно быстрый драйвер и GPU) в результате FPS не изменился, следовательно можно предположить, что данное приложение CPU-bound.
                0
                Уже гораздо лучше!
                Я бы посоветовал бы выбрать в этот раз немного меньше моделей, чтобы было к примеру 20 fps в одном режиме и 10 fps в другом — обычно в тестах стараются избегать граничных значений, вдруг уже при таком количестве моделей бутылочное горлышко в памяти или где-то еще? Но все-равно это уже заметно показательнее. Для полноты теста осталось провести такой тест на ARM устройстве, чтобы быть уверенным, что имеет вообще смысл компилировать этот движок под ARM, может вообще окажется, что ему место только на Intel-ах.
                  0
                  А можно результат с точностью хотя бы 2 знака после запятой.
                    0
                    Результат — FPS?
                      –1
                      Я бы конечно посмотрел бы на ms по физике только.
                      Но если это сложно то хотябы для fps.
                      А то там может быть 2.99 vs 4.0 FPS.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое