2014/02/22
Android SmartWatch ZWatch で 3Dゲーム (ChiRaKS)
昔作成した 3D ポリゴンのゲームを移植してみました。
CPU だけでレンダリングしているので、3D GPU が入っていない Z Watch でも動きます。

・ChiRaKS (Android)
当時 (2000年) は SH3 30~60MHz の SHARP MI-Zaurus (PDA) で動いており
160x160 サイズのレンダリングでぎりぎり 30fps に届かない程度でした。
その後移植した PocketPC (WindowsCE/WindowsMobile) では、すでに iPAQ に
StrongARM (206MHz) が搭載されており 100fps も余裕で超えています。
同世代の MIPS VR4122 端末 (150MHz) は StrongARM の 1/3 くらいの速度でした。
現在のハイエンド端末は single core でも Zaurus の 100倍以上速いので
1080x1080 サイズのレンダリングでも 60fps 近く出ます。
ただし 32bit 固定小数点演算を行っている関係上、演算がオーバーフローしてしまう
問題があったため、アプリでは最大解像度を 540x540 に制限しています。
Z Watch (JZ4775 MIPS) の画面は 240x240 と小さいこともあり余裕です。
設定の NoWait にチェックを入れると 60fps 出ていることがわかります。
レンダリングには NDK の Bitmap API を利用しています。
関連エントリ
・Android SmartWatch スマートウオッチのスペック比較表
・Android SmartWatch SmartQ ZWatch (4) アプリの管理
・Android SmartWatch SmartQ ZWatch (3) 腕に関数電卓
・Android SmartWatch SmartQ ZWatch (2)
・Android 4.1 SmartWatch SmartQ Z Watch
CPU だけでレンダリングしているので、3D GPU が入っていない Z Watch でも動きます。

・ChiRaKS (Android)
当時 (2000年) は SH3 30~60MHz の SHARP MI-Zaurus (PDA) で動いており
160x160 サイズのレンダリングでぎりぎり 30fps に届かない程度でした。
その後移植した PocketPC (WindowsCE/WindowsMobile) では、すでに iPAQ に
StrongARM (206MHz) が搭載されており 100fps も余裕で超えています。
同世代の MIPS VR4122 端末 (150MHz) は StrongARM の 1/3 くらいの速度でした。
現在のハイエンド端末は single core でも Zaurus の 100倍以上速いので
1080x1080 サイズのレンダリングでも 60fps 近く出ます。
ただし 32bit 固定小数点演算を行っている関係上、演算がオーバーフローしてしまう
問題があったため、アプリでは最大解像度を 540x540 に制限しています。
Z Watch (JZ4775 MIPS) の画面は 240x240 と小さいこともあり余裕です。
設定の NoWait にチェックを入れると 60fps 出ていることがわかります。
レンダリングには NDK の Bitmap API を利用しています。
#include <android/bitmap.h> ~ void Render( JNIEnv* env, jobject obj, jobject bitmap_object ) { void* ptr= NULL; AndroidBitmap_lockPixels( env, bitmap_object, &ptr ); ~ AndroidBitmap_unlockPixels( env, bitmap_object ); }
関連エントリ
・Android SmartWatch スマートウオッチのスペック比較表
・Android SmartWatch SmartQ ZWatch (4) アプリの管理
・Android SmartWatch SmartQ ZWatch (3) 腕に関数電卓
・Android SmartWatch SmartQ ZWatch (2)
・Android 4.1 SmartWatch SmartQ Z Watch
2014/02/14
MediaTek MT8125/8389 Cortex-A7 の浮動小数点演算速度
ARM Cortex-A7 は big.LITTLE で用いられる場合、省電力側の CPU core に相当します。
消費電力が少ない代わりに、高性能側の CPU core より性能は劣ります。
VFP Benchmark の結果を送ってもらいました。
結果を見ると、Cortex-A7 の NEON は 32bit 単位で実行していることがわかります。
演算速度は NEON 無しの CPU と変わらないのですが、Cortex-A15 のペアとして
機能できるよう NEON 命令セットに対応しているものと考えられます。
・FPU の演算能力 (上記以外の結果はこちら)
big.LITTLE で用いる場合は、この手の演算は Cortex-A15 の担当なので
おそらく表に出ることは無いでしょう。
単独で用いられている場合は、同じ Quad core CPU と書かれていても
かなり性能差が開いていることを考慮した方が良いかもしれません。
浮動小数点演算速度だけ見てもピーク演算速度で Cortex-A9 の半分、
Krait/Cortex-A15 の 1/4 (同一クロック時) となっています。
以下詳細
倍精度の場合はさらに差が広がっており、加算は 1 cycle で実行できますが乗算は 4 倍低速です。
さらに fmacd (積和) は乗算と同等の速度で演算しているものの、
vfma (FMA) は並列化されておらず 5倍 (1 add + 4 mul cycle) かかっているようです。
関連エントリ
・VFP Benchmark v1.1 浮動小数点演算命令の速度 (NEON/SSE/AVX)
・ARM CPU の VFP Benchmark アプリ 浮動小数点演算速度の計測
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・Nexus 10 CPU Cortex-A15 の速度
・Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・Qualcomm APQ8064 GPU Adreno 320 の速度
・benchmark 関連
消費電力が少ない代わりに、高性能側の CPU core より性能は劣ります。
VFP Benchmark の結果を送ってもらいました。
結果を見ると、Cortex-A7 の NEON は 32bit 単位で実行していることがわかります。
演算速度は NEON 無しの CPU と変わらないのですが、Cortex-A15 のペアとして
機能できるよう NEON 命令セットに対応しているものと考えられます。
SIMD (Vector) SIMD4 single fp (32bit x4) CPU mul add mad fma ------------------------------------------------------ ARM Cortex-A7 1 1 2 2 ARM Cortex-A8 2 2 4 – ARM Cortex-A9 2 2 4 – ARM Cortex-A15 4 4 8 8 Qualcomm Scorpion 4 4 8 – Qualcomm Krait 400 4 4 8 8 Apple A6 Swift 4 4 8 8 Apple A7 Cyclone 32 8 12 16 16 Apple A7 Cyclone 64 8 12 – 16 * 数値は 1 cycle あたりの演算数、大きい方が速い
・FPU の演算能力 (上記以外の結果はこちら)
big.LITTLE で用いる場合は、この手の演算は Cortex-A15 の担当なので
おそらく表に出ることは無いでしょう。
単独で用いられている場合は、同じ Quad core CPU と書かれていても
かなり性能差が開いていることを考慮した方が良いかもしれません。
浮動小数点演算速度だけ見てもピーク演算速度で Cortex-A9 の半分、
Krait/Cortex-A15 の 1/4 (同一クロック時) となっています。
以下詳細
Lenovo YOGA TABLET 8 (3G) MediaTek MT8389 1.2GHz Cortex-A7 Quad core SingleT SP max: 2.374 GFLOPS SingleT DP max: 1.165 GFLOPS MultiT SP max: 9.474 GFLOPS MultiT DP max: 4.653 GFLOPS * VFP/NEON (single fp) VFP fmuls (32bit x1) n8 : 3.634 1100.7 1100.7 VFP fadds (32bit x1) n8 : 3.450 1159.3 1159.3 VFP fmacs (32bit x1) n8 : 3.451 2318.1 2318.1 VFP vfma.f32 (32bit x1) n8 : 3.448 2319.9 2319.9 NEON vmul.f32 (32bit x2) n8 : 6.795 1177.3 1177.3 NEON vadd.f32 (32bit x2) n8 : 6.828 1171.7 1171.7 NEON vmla.f32 (32bit x2) n8 : 6.810 2349.6 2349.6 NEON vfma.f32 (32bit x2) n8 : 6.797 2354.1 2354.1 NEON vmul.f32 (32bit x4) n8 : 13.529 1182.7 1182.7 NEON vadd.f32 (32bit x4) n8 : 13.511 1184.2 1184.2 NEON vmla.f32 (32bit x4) n8 : 13.498 2370.7 2370.7 NEON vfma.f32 (32bit x4) n8 : 13.549 2361.8 2361.8
倍精度の場合はさらに差が広がっており、加算は 1 cycle で実行できますが乗算は 4 倍低速です。
さらに fmacd (積和) は乗算と同等の速度で演算しているものの、
vfma (FMA) は並列化されておらず 5倍 (1 add + 4 mul cycle) かかっているようです。
* VFP/NEON (double fp) VFP fmuld (64bit x1) n8 : 13.628 293.5 293.5 VFP faddd (64bit x1) n8 : 3.439 1163.0 1163.0 VFP fmacd (64bit x1) n8 : 13.508 592.2 592.2 VFP vfma.f64 (64bit x1) n8 : 16.895 473.5 473.5 VFP fmuld (64bit x1) ns4 : 13.434 297.8 297.8 VFP faddd (64bit x1) ns4 : 3.435 1164.6 1164.6 VFP fmacd (64bit x1) ns4 : 13.430 595.7 595.7 VFP vfma.f64 (64bit x1) ns4 : 16.823 475.5 475.5 VFP fmuld (64bit x1) n1 : 13.439 297.6 297.6 VFP faddd (64bit x1) n1 : 3.447 1160.6 1160.6 VFP fmacd (64bit x1) n1 : 26.856 297.9 297.9 VFP vfma.f64 (64bit x1) n1 : 26.860 297.8 297.8
関連エントリ
・VFP Benchmark v1.1 浮動小数点演算命令の速度 (NEON/SSE/AVX)
・ARM CPU の VFP Benchmark アプリ 浮動小数点演算速度の計測
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・Nexus 10 CPU Cortex-A15 の速度
・Nexus 10 CPU Cortex-A15 の浮動小数点演算速度
・Qualcomm APQ8064 GPU Adreno 320 の速度
・benchmark 関連
2014/02/08
Linux 他 X11 で OpenGL 4 を使う
X11 (X window) では Platform Interface に GLX を用います。
Display が本当に意味を持つのは X11 ならではで、egl の API 仕様も
X window のプログラムを見ると納得です。
(1) pixel format の選択
サーバーが対応しているピクセルフォーマットから必要なものを選択しています。
フォーマットの組み合わせは GPU やドライバによって異なります。
X native の API にも似たような仕組みとして XVisualInfo があります。
GLXFBConfig は GLX による拡張で、XVisualInfo* の代わりに用いることが可能です。
Windows でも Win32 API に PIXELFORMATDESCRIPTOR (ChoosePixelFormat())
がありました。WGL Extension の WGL_ARB_pixel_format
(wglChoosePixelFormatARB()) はこれを置き換えるもので、
XVisualInfo と GLXFBConfig との関係に似ています。
もし XCreateColormap などで Visual (XVisualInfo) が必要になったら
下記のように取得すれば OK です。
上の visual_info は config_array 同様 XFree() が必要です。
egl のような wrapper を作る場合、メモリ管理を伴うのは少々都合が悪い
場合があります。
GLXFBConfig をそのまま保持せずに、ID に紐付けておくと管理が楽になります。
この fb_config_id があれば GLXConfig が一意に定まるわけです。
fb_config_id から GLXFBConfig を取り出す方法は下記の通り。
XVisualInfo を得る方法はすでに述べた通りですが、GLXFBConfig から
直接 VisualID を求めることもできます。
(2) Context の作成
任意の Version の OpenGL Context を作成するには GLX_ARB_create_context
( glXCreateContextAttribsARB() ) が必要です。
試した下記の環境ではデフォルトで OpenGL 4.3 が選択されていたので、
場合によっては使わなくても問題ないかもしれません。
・Ubuntu 13.10 desktop x86_64
・GeForce GTX650
・NVIDIA binary Xorg driver 319
Core Profile のみ、OpenGL ES 2.0 互換 Profile の指定など、細かい設定を
行うならやはり glXCreateContextAttribsARB() が必要です。
他にも glX extension を利用する場合が考えられるので、
API の取得はまとめて管理した方が良いでしょう。
glX extension だけでなく、GL 4.x の各命令でも API の取得が必要になります。
4番目の True は Direct Rendering の指定です。
本来の X protocol はネットワーク透過なのでアプリケーションからドライバに
直接アクセスできませんが、ローカルサーバー利用時は条件によって可能になります。
現在の context が Direct Rendering 可能な状態 (DRI) かどうかは
glXIsDirect() で確認することができます。
・GL_ARB_create_context
(3) Window の作成
GLXFBConfig が決まった時点で Window を作れるので (2) との順番は任意。
(4) MakeCurrent
Window は GLXDrawable です。
これでレンダリングできますが、OpenGL 2 以降の API を用いるには
個別に glXGetProcAddress() して関数を用意する必要があります。
(5) OpenGL API の取得
ゼロから始めるとここが一番手間かもしれません。
ただしこの流れは Windows で OpenGL を用いる場合と完全に同一です。
API 名 Table の作成、API の取り出しコードは Windows と共有することができます。
・OpenGL のはじめ方 (Windows)
下記は API Table の例です。
OpenGL 4.x の glcorearb.h からスクリプトで自動変換して生成しています。
この方法だと、新しい API や extension 対応ドライバがリリースされたら
即座に対応することができます。
Platform Interface のまとめ
Windows/Linux X11 は GetProcAddress() が必要ですが対応ドライバがあれば
新しい API をすぐ使えます。
OSX はそのまま OpenGL を使えて手間いらずですが 10.9 は OpenGL 4.1 まで。
OSX + XQuartz (HD4000) は残念ながら 2.1 でした。
Nexus 7 (2012) + Ubuntu desktop のように OpenGL ES 2.0 対応 GPU の
Linux では GLX ではなく X11 上で EGL + OpenGL ES 2.0 API が使えます。
Raspberry Pi や 旧 NetWalker のように、X が動いても OpenGL 未対応の場合
フレームバッファに直接レンダリングすることになります。
この場合も EGL なので、Window の有無にかかわらず利用できる EGL は互換性が
取りやすくなっています。
関連エントリ
・Mac OS X 10.9 Mavericks の OpenGL 4.1 対応と Windows 8.1 Intel HD 4000 Driver
・Mac OS X で OpenGL の描画 (Xcode5/retina)
・Nexus 7 (2012) Ubuntu desktop 上での開発とバッテリー設定
・NetWalker PC-Z1 i.MX515 OpenGL ES 2.0 (3)
・OpenGL のはじめ方
Display が本当に意味を持つのは X11 ならではで、egl の API 仕様も
X window のプログラムを見ると納得です。
Display* display= NULL; int screen= 0; display= XOpenDisplay( NULL ); screen= DefaultScreen( display );
(1) pixel format の選択
static int attrib_list[]= { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DOUBLEBUFFER, True, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, None }; int n_items= 0; GLXFBConfig* config_array= glXChooseFBConfig( display, screen, attrib_list, &n_items ); 〜 if( n_items ){ GLXFBConfig fb_config= config_array[0]; 〜 } XFree( config_array );
サーバーが対応しているピクセルフォーマットから必要なものを選択しています。
フォーマットの組み合わせは GPU やドライバによって異なります。
X native の API にも似たような仕組みとして XVisualInfo があります。
GLXFBConfig は GLX による拡張で、XVisualInfo* の代わりに用いることが可能です。
Windows でも Win32 API に PIXELFORMATDESCRIPTOR (ChoosePixelFormat())
がありました。WGL Extension の WGL_ARB_pixel_format
(wglChoosePixelFormatARB()) はこれを置き換えるもので、
XVisualInfo と GLXFBConfig との関係に似ています。
もし XCreateColormap などで Visual (XVisualInfo) が必要になったら
下記のように取得すれば OK です。
// GLXFBConfig -> XVisualInfo XVisualInfo* visual_info= glXGetVisualFromFBConfig( display, fb_config ); 〜 XFree( visual_info );
上の visual_info は config_array 同様 XFree() が必要です。
egl のような wrapper を作る場合、メモリ管理を伴うのは少々都合が悪い
場合があります。
GLXFBConfig をそのまま保持せずに、ID に紐付けておくと管理が楽になります。
// GLXFBConfig -> fb_config_id int fb_config_id= 0; glXGetFBConfigAttrib( display, fb_config, GLX_FBCONFIG_ID, &fb_config_id );
この fb_config_id があれば GLXConfig が一意に定まるわけです。
fb_config_id から GLXFBConfig を取り出す方法は下記の通り。
// fb_config_id -> GLXFBConfig int attr_list[]= { GLX_FBCONFIG_ID, fb_config_id, None }; int n_items= 0; GLXFBConfig* fb_config_ptr= glXChooseFBConfig( display, screen, attr_list, &n_items ); assert( n_items == 1 ); GLXFBConfig fb_config= fb_config_ptr[0]; 〜 XFree( fb_config_ptr );
XVisualInfo を得る方法はすでに述べた通りですが、GLXFBConfig から
直接 VisualID を求めることもできます。
// GLXFBConfig -> VisualID int visual_id= 0; glXGetFBConfigAttrib( display, config_array[0], GLX_VISUAL_ID, &visual_id );
(2) Context の作成
任意の Version の OpenGL Context を作成するには GLX_ARB_create_context
( glXCreateContextAttribsARB() ) が必要です。
試した下記の環境ではデフォルトで OpenGL 4.3 が選択されていたので、
場合によっては使わなくても問題ないかもしれません。
・Ubuntu 13.10 desktop x86_64
・GeForce GTX650
・NVIDIA binary Xorg driver 319
Core Profile のみ、OpenGL ES 2.0 互換 Profile の指定など、細かい設定を
行うならやはり glXCreateContextAttribsARB() が必要です。
// Extension API glXCreateContextAttribsARB() の取り出し PFNGLXCREATECONTEXTATTRIBSARBPROC f_glXCreateContextAttribsARB= (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( (const GLubyte*)"glXCreateContextAttribsARB" ); // OpenGL 4.3 context 作成 static int att_command[]= { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_FLAGS_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, None }; GLXContext context= f_glXCreateContextAttribsARB( display, fb_config, 0, True, att_command );
他にも glX extension を利用する場合が考えられるので、
API の取得はまとめて管理した方が良いでしょう。
glX extension だけでなく、GL 4.x の各命令でも API の取得が必要になります。
4番目の True は Direct Rendering の指定です。
本来の X protocol はネットワーク透過なのでアプリケーションからドライバに
直接アクセスできませんが、ローカルサーバー利用時は条件によって可能になります。
現在の context が Direct Rendering 可能な状態 (DRI) かどうかは
glXIsDirect() で確認することができます。
・GL_ARB_create_context
(3) Window の作成
GLXFBConfig が決まった時点で Window を作れるので (2) との順番は任意。
XVisualInfo* visual_info= glXGetVisualFromFBConfig( display, fb_config ); Window root= RootWindow( NativeDisplay, screen ); XSetWindowAttributes attr; attr.background_pixel= 0; attr.border_pixel= 0; attr.colormap= XCreateColormap( display, root, visual_info->visual, AllocNone ); attr.event_mask= 0 |StructureNotifyMask |ExposureMask |KeyPressMask |KeyReleaseMask |ButtonPressMask |ButtonReleaseMask ; Window win= XCreateWindow( display, root, x, y, width, height, 0, // border visual_info->depth, InputOutput, visual_info->visual, CWBorderPixel|CWColormap|CWEventMask, &attr ); XFree( visual_info ); visual_info= NULL; XMapWindow( display, win ); XFlush( display );
(4) MakeCurrent
glXMakeCurrent( display, win, context );
Window は GLXDrawable です。
これでレンダリングできますが、OpenGL 2 以降の API を用いるには
個別に glXGetProcAddress() して関数を用意する必要があります。
(5) OpenGL API の取得
ゼロから始めるとここが一番手間かもしれません。
ただしこの流れは Windows で OpenGL を用いる場合と完全に同一です。
API 名 Table の作成、API の取り出しコードは Windows と共有することができます。
・OpenGL のはじめ方 (Windows)
下記は API Table の例です。
OpenGL 4.x の glcorearb.h からスクリプトで自動変換して生成しています。
この方法だと、新しい API や extension 対応ドライバがリリースされたら
即座に対応することができます。
// flatlib3 GL_HeaderParser.py // linux/GLFunction_GL4.inc void (APIENTRY *p_glBlendColor)( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); void (APIENTRY *p_glBlendEquation)( GLenum mode ); void (APIENTRY *p_glDrawRangeElements)( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices ); 〜 void (APIENTRY *p_glTexPageCommitmentARB)( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident ); // total=525 ImportListType ImportList_GL4[]= { { "glBlendColor", (void*)&p_glBlendColor }, { "glBlendEquation", (void*)&p_glBlendEquation }, { "glDrawRangeElements", (void*)&p_glDrawRangeElements }, { "glTexImage3D", (void*)&p_glTexImage3D }, { "glTexSubImage3D", (void*)&p_glTexSubImage3D }, 〜 { "glGetNamedStringARB", (void*)&p_glGetNamedStringARB }, { "glGetNamedStringivARB", (void*)&p_glGetNamedStringivARB }, { "glTexPageCommitmentARB", (void*)&p_glTexPageCommitmentARB }, { NULL, NULL } }; // total=525
// flatlib3 GL_HeaderParser.py // linux/GLFunction_GL4.h extern void (APIENTRY *p_glBlendColor)( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ); inline void glBlendColor( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) { FL_GLAPI_ASSERT( p_glBlendColor ); return p_glBlendColor( red, green, blue, alpha ); } extern void (APIENTRY *p_glBlendEquation)( GLenum mode ); inline void glBlendEquation( GLenum mode ) { FL_GLAPI_ASSERT( p_glBlendEquation ); return p_glBlendEquation( mode ); } extern void (APIENTRY *p_glDrawRangeElements)( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices ); inline void glDrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices ) { FL_GLAPI_ASSERT( p_glDrawRangeElements ); return p_glDrawRangeElements( mode, start, end, count, type, indices ); } 〜
Platform Interface のまとめ
Windows WGL GL4.x wglGetProcAddress() Linux X11 GLX GL4.x glXGetProcAddress() OSX NSOpenGL GL4.1 OSX + X11 GLX GL2.1 (XQuartz + HD4000) Linux X11 + ES EGL ES2/3 Android EGL ES2/3 iOS GLK/EAGL ES2/3
Windows/Linux X11 は GetProcAddress() が必要ですが対応ドライバがあれば
新しい API をすぐ使えます。
OSX はそのまま OpenGL を使えて手間いらずですが 10.9 は OpenGL 4.1 まで。
OSX + XQuartz (HD4000) は残念ながら 2.1 でした。
Nexus 7 (2012) + Ubuntu desktop のように OpenGL ES 2.0 対応 GPU の
Linux では GLX ではなく X11 上で EGL + OpenGL ES 2.0 API が使えます。
Raspberry Pi や 旧 NetWalker のように、X が動いても OpenGL 未対応の場合
フレームバッファに直接レンダリングすることになります。
この場合も EGL なので、Window の有無にかかわらず利用できる EGL は互換性が
取りやすくなっています。
関連エントリ
・Mac OS X 10.9 Mavericks の OpenGL 4.1 対応と Windows 8.1 Intel HD 4000 Driver
・Mac OS X で OpenGL の描画 (Xcode5/retina)
・Nexus 7 (2012) Ubuntu desktop 上での開発とバッテリー設定
・NetWalker PC-Z1 i.MX515 OpenGL ES 2.0 (3)
・OpenGL のはじめ方