OpenGL 程式設計/安裝/Android NDK

我們的 GLUT 教程可以使用提供的簡單包裝器在 Android 上執行。
注意:包裝器將整合到下一個官方 FreeGLUT(版本 3.0)中!
要了解 GLUT 包裝器在內部的工作原理,請參閱 Android GLUT 包裝器。
首先,您需要一個最小的 Java 開發環境
sudo apt-get install openjdk-7-jdk ant
然後從 Android 開發者 獲取 Android NDK r9d,以編譯用於 Android 的 C/C++ 程式碼。
最後,您需要安裝 Android API 級別 10,從同一網站獲取 Android SDK 並使用android圖形工具來安裝它。
程式本身可能還需要 GLM 和 FreeType 庫 - 請參閱下面的專用部分。
Android 模擬器從 2012 年 4 月開始僅支援 OpenGL ES 2.0,需要特定的模擬器配置和系統映像,並且似乎並非在所有平臺上都能正常工作。
還要注意,“API 演示”應用程式提供了一個“OpenGL ES 2.0”示例,如果 2.0 不可用,它會靜默且令人困惑地回退到 OpenGL ES 1.0,因此這不是一個很好的測試來檢視是否支援 OpenGL ES 2.0。
在 Android 上使用 支援裝置 實驗 OpenGL 2.0 仍然是最好的選擇。
官方文件:https://developer.android.com/tools/devices/emulator.html#accel-graphics
當您透過 USB 連線裝置時,可以使用 adb 命令(來自 Android SDK)瀏覽檔案系統、安裝應用程式、除錯它們等。
$ adb devices List of devices attached 4520412B47C0207D device
在本華夏公益教科書中,示例基於 GLUT 庫。
由於 GLUT 尚未移植到 Android,因此我們為 Android 編寫了一個簡單的 GLUT 相容包裝器(請參閱 程式碼庫)。
注意:包裝器仍處於早期階段,可能會在不久的將來發生變化。
檢視“android_wrapper/”目錄。
- 透過 USB 插入您的裝置(智慧手機、平板電腦...)。
- 將 Android 工具新增到您的 PATH,例如
export PATH="$PATH:/usr/src/android-sdk-linux/tools:/usr/src/android-sdk-linux/platform-tools:/usr/src/android-ndk-r9d"
- 在
jni/目錄中,使src成為您需要編譯的 GLUT 程式碼的符號連結(例如ln -nfs ../../tut02_clean src)。 - 使
assets成為您正在編譯的教程的符號連結(例如ln -s jni/src assets)。 - 現在您可以鍵入
make clean; make && make install
- 您將在裝置上獲得一個“OpenGL 華夏公益教科書”應用程式,可以立即執行!
要使您的應用程式全屏,請在您的 AndroidManifest.xml 中新增此屬性
<application
...
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
>
預設的 Android 鍵盤沒有 F1/F2/F3 等鍵。
相反,您可以使用 Hacker's Keyboard,這是一種具有更多鍵的替代輸入法
確保您的應用程式在 AndroidManifest.xml 中定義了 android:icon。
<application ...
android:icon="@drawable/icon"
建立兩個圖示
- res/drawable/icon.png (48x48)
- res/drawable-hdpi/icon.png (72x72)
現在您的應用程式將在啟動器上有一個自定義圖示。
如果您想檢視程式的標準輸出(stdout 和 stderr),您需要將它們重定向到系統日誌
adb shell root
adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start # this may restart your Android session
要檢查日誌檔案,您可以使用
- 命令:adb logcat
ddms實用程式,它具有圖形 GUI 來瀏覽日誌- Eclipse,它嵌入了一個類似於 DDMS 的 LogCat 檢視器
以下操作將在從 C/C++ 呼叫 JNI 時開啟更多檢查
adb shell stop
adb shell setprop dalvik.vm.checkjni true
adb shell start
您將在系統日誌中獲得額外的跟蹤資訊,並且 JNI 對其接受的內容將更加嚴格。
GDB 也可以啟用。
注意:在 NDKr7 中,在 Android.mk 中使用“stabs”格式進行除錯符號,否則 GDB 將顯示錯誤的原始碼行 [1]
LOCAL_CXXFLAGS := -gstabs+
GDB 需要除錯版本,在構建 C++ 程式碼時新增 NDK_DEBUG=1
ndk-build NDK_DEBUG=1
在啟動 gdb 時,確保您的 AndroidManifest.xml 提到了它是可除錯的,否則 gdb 的行為會很糟糕(缺乏執行緒資訊、崩潰等)
<application ...
android:hasCode="true" android:debuggable="true"
gdb-server 需要幾秒鐘才能在裝置上啟動,因此您的程式將在它被偵錯程式暫停之前開始執行。一個解決方法是在您的 android_main 函式中新增一個等待
sleep(5);
要啟動除錯會話,請鍵入
ndk-gdb --start
如果您遇到以下錯誤:
E/AndroidRuntime( 3021): java.lang.RuntimeException: Unable to start activity
ComponentInfo{org.wikibooks.OpenGL/android.app.NativeActivity}: java.lang.IllegalArgumentException:
Unable to load native library: /data/data/org.wikibook.OpenGL/lib/libnative-activity.so
系統無法載入您的 .so 檔案,原因是底層問題。
要獲取更多資訊,您需要建立一個手動載入庫的最小 Java 應用程式
- src/com/example/test_native_activity/Main.java
package com.example.test_native_activity;
import android.app.Activity;
import android.os.Bundle;
public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.loadLibrary("native-activity");
}
}
- AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_native_activity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application android:label="test_native_activity">
<activity android:name=".Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
編譯、安裝並準備它
android update project --name test_native_activity --path . --target "android-10"
ant debug
ant installd
adb shell
su -c bash
cd /data/data/
cp -a org.wikibooks.OpenGL/lib/libnative-activity.so com.example.test_native_activity/lib/
執行此應用程式時,您將在 Android 日誌中獲得更精確的錯誤,例如錯誤的 STL 實現
E/AndroidRuntime(3009): java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1311]: 2323 cannot locate '_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc'...
或缺少依賴項
E/AndroidRuntime( 3327): java.lang.UnsatisfiedLinkError: Cannot load library:link_image[1962]: 2323 could not load needed library 'libglut.so.3' for 'libnative-activity.so' (load_library[1104]: Library 'libglut.so.3' not found)
在最糟糕的情況下,庫甚至可能無法正確載入。例如,當全域性靜態變數的 C++ 建構函式在庫載入時崩潰時,即使在應用程式啟動之前也會發生這種情況。您需要在 C 級重新生成庫載入
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char* argv[]) {
const char* err = NULL;
const char* filename = "/data/data/org.wikibooks.OpenGL/lib/libnative-activity.so";
if (argc == 2)
filename = argv[1];
printf("Clearing errors: "); fflush(stdout);
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
printf("Loading library: "); fflush(stdout);
void* handle = dlopen(filename, RTLD_LAZY);
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
if (handle != NULL) {
printf("Loading symbol: "); fflush(stdout);
dlsym(handle, "ANativeActivity_onCreate");
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
}
}
然後將其傳送到裝置並執行它
$ arm-linux-androideabi-gcc test-dlsym.c
$ adb push a.out /
$ adb shell
# /a.out
Clearing errors: OK
Loading library: OK
Loading symbol: OK
您也可以使用 strace 獲取更多精度
# strace /a.out
預設情況下,Android 沒有 ldd,但您可以使用以下方法模擬它:
arm-linux-androideabi-objdump -x libs/armeabi/libnative-activity.so | grep NEEDED
# or
arm-linux-androideabi-readelf -d libs/armeabi/libnative-activity.so | grep NEEDED
當您只使用 GLES2 函式時,您的應用程式幾乎可以移植到桌上型電腦和移動裝置。還有一些問題需要解決
- GLSL 的
#version不同 - GLES2 需要與 OpenGL 2.1 不相容的精度提示。
有關詳細資訊和建議的解決方案,請參閱基本教程 02 和 03。
要安裝 GLM,您只需要將最新版本解壓縮到 jni/glm 中(這樣 jni/glm/glm.hpp 就存在)。它是一個僅包含標頭檔案的庫,不需要單獨編譯。
- 從 http://lonesock.net/soil.html 下載 Simple OpenGL Image Library
- 應用來自android_wrapper/soil.patch.
- 的補丁按照.
- projects/Android/Makefile中的說明進行操作.
NDK 模組已準備好在
src/build/soil/FreeType
/usr/src/android-ndk-r8c/build/tools/make-standalone-toolchain.sh \
--platform=android-14 --install-dir=/usr/src/ndk-standalone-14-arm --arch=arm
NDK_STANDALONE=/usr/src/ndk-standalone-14-arm
PATH=$NDK_STANDALONE/bin:$PATH
如果您需要 FreeType(一個渲染字型的庫),您需要交叉編譯它。注意:Android 系統使用 FreeType,但內部它不將其公開給原生應用程式。
tar xf freetype-2.6.tar.bz2
cd freetype-2.6/
# For simplicity, use bundled zlib, and avoid harfbuzz cyclic dependency
./configure --host=arm-linux-androideabi --prefix=/freetype --without-zlib --with-png=no --with-harfbuzz=no
make -j$(nproc)
make install DESTDIR=$(pwd)
首先,從 NDK 準備交叉編譯器
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := freetype
LOCAL_SRC_FILES := lib/libfreetype.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/freetype2
include $(PREBUILT_STATIC_LIBRARY)
然後使用它交叉編譯 freetype
然後在新的 freetype/ 目錄中編寫一個 Android.mk 檔案
有關詳細資訊,請參閱 NDK 中的 docs/STANDALONE-TOOLCHAIN.html 和 docs/PREBUILTS.html。CLEAR_VARS 部分沒有記錄,但對於避免路徑混淆是必要的;它用於 native_app_glue NDK 模組。
LOCAL_STATIC_LIBRARIES := freetype
(或者,如果您不打算使用 NDK 構建系統,則可以在 --prefix=/usr/src/ndk-standalone-14-arm/sysroot/usr 中安裝它。)
要在您的專案中使用 FreeType,請編輯您的Android.mk裝置標記為離線
[編輯 | 編輯原始碼]您第一次將裝置連線到新計算機時,它會要求您確認計算機指紋。在您接受裝置螢幕上的確認之前,它會被標記為離線。如果您沒有被要求確認,請確保您的
adb
是最新的。允許非 root 使用者訪問 USB[編輯 | 編輯原始碼]如今,Android 裝置在您的
/lib/udev/rules.d/
- 中被引用,非特權使用者現在可以安全地連線到裝置。
- 如果 adb 在您的新裝置上遇到許可權問題檢視以 root 身份執行
adb時是否有效(以檢查是否為許可權問題,或者其他問題)。安裝android-tools-adb. - 軟體包,其中包含
/lib/udev/rules.d/70-android-tools-adb.rules
usb 2-1: New USB device found, idVendor=18d1, idProduct=4e22
如果不起作用,請手動建立一個 udev 規則,如下所示。
# Galaxy S
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev"
首先,透過在插入裝置後鍵入“dmesg”來確定裝置的 idVendor;檢查是否有
然後建立一個如下所示的 udev 規則,例如在 /etc/udev/rules.d/51-android.rules 中
/etc/init.d/udev restart
(這可以透過 idProduct 進一步細化。)
# ll /dev/bus/usb/002/ total 0 crw-rw-r-T 1 root plugdev 189, 140 janv. 19 21:50 013
然後重新啟動 udev 守護程序
如果您插入裝置,USB 字元裝置應該有“plugdev”組- 參考資料
- 在此頁面上評論