Linux」カテゴリーアーカイブ

Raspberry Pi 2 OpenGL ES のレイヤー合成

大幅に強化された CPU と違い、GPU 周りは Raspberry Pi 1 とほとんど変わっていないようです。
以前移植したコードが Raspberry Pi 2 でもそのまま動いています。

Raspberry Pi 2 の Desktop (Raspbian) から起動できる Minecraft は、
一見 Windows 内で動いているように見えますが他のウィンドウの下に隠れることができません。
3D Rendering 自体は別のレイヤーに描画されており、
スクリーンに対して Overlay で表示されているようです。

raspberry_pi_201.jpg

↑ 上のように半透明が描画されているシーンだけ下のウィンドウが透けて見えます。
フレームバッファに alpha 値が入るとレイヤー同士の合成とみなされてしまうため。

この辺りの挙動は Window 無しのフルスクリーン描画と違いがないようです。
自分が移植したプログラムでも最初は下記のようになっていました。

raspberry_pi_202.jpg

↑背景を alpha = 0.0f でクリアしていたため console と合成されてしまっています。
うっすら見えているのは alpha 値が入っているところだけです。

OpenGL で常に Alpha=1.0 を書き込んでも良いのですが、
VideoCore の API でも指定できるようです。
下記のように alpha に固定値 255 を指定することで layer が不透明になりました。

static VC_DISPMANX_ALPHA_T alpha= {
  DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
  255,
  NULL
};

dispman_element= vc_dispmanx_element_add(
  dispman_update,           // DISPMANX_UPDATE_HANDLE_T
  dispman_display,          // DISPMANX_DISPLAY_HANDLE_T
  0,                        // layer
  &dest_rect,               // VC_RECT_T*
  0,                        // DISPMANX_RESOURCE_HANDLE_T
  &src_rect,                // VC_RECT_T*
  DISPMANX_PROTECTION_NONE, // DISPMANX_PROTECTION_T
  &alpha,                   // VC_DISPMANX_ALPHA_T
  NULL,                     // DISPMANX_CLAMP_T*
  DISPMANX_NO_ROTATE        // DISPMANX_TRANSFORM_T
);

↓不透明になったもの

raspberry_pi_203.jpg

他にも位置の指定や拡縮、90度回転や反転等の指定もできるようです。

↓ ありもののケース(旧型)

raspberry_pi_1b.jpg

関連エントリ
Raspberry Pi 2 で速くなったコンパイル時間の比較

Raspberry Pi 2 で速くなったコンパイル時間の比較

Raspberry Pi 2 を入手したので使ってみました。
ARM11 の Raspberry Pi と比べると格段に速くなっています。

VFP Benchmark の比較

               CPU       clock       single fp      double fp
----------------------------------------------------------------
Raspberry Pi B ARM1176   0.7GHz x1   0.674 GFLOPS   0.674 GFLOPS
Raspberry Pi 2 Cortex-A7 0.9GHz x4   7.087 GFLOPS   3.472 GFLOPS

ARM11 世代の VFP と比べると core あたり 2.6倍 (単精度時,クロック差含む)。

詳細な結果は下記に追加しました

VFP Benchmark Log

Cortex-A7 は big.LITTLE でも省電力 core として用いられており、
単体の性能はあまり高くありません。

それでもエントリークラスのスマートフォンやタブレットでは
同じ Cortex-A7 Quad core のデバイスが多数リリースされています。
Snapdraogn 400 MSM8926/8226 や MT8125/8389/6582 など、
それなりにバランスが良い構成なのだと思われます。

下記は手持ちライブラリ(flatlib3)のビルド時間の比較です。
36分から 5分半へと現実的な数値になりました。
SD Card の速度に依存するためあまり正確ではないですが、
およそ 6.6倍で公称値通りといえそうです。

                                Clock  core  ISA    RAM    gcc-4.8 clang-3.4
---------------------------------------------------------------------------
(1) Raspberry Pi B ARM1176JZF   0.7GHz x1    armv6l 0.5GB   36m18s
(2) Raspberry Pi 2 Cortex-A7    0.9GHz x4    armv7l   1GB    5m29s
(3) Nexus 7 2012   Cortex-A9    1.3GHz x4    armv7l   1GB    3m42s
(4) Atom Z540      Bonnell      1.8GHz x1+HT x86      2GB    6m23s   6m18s
(5) BayTrail-D J1900 Silvermont 2.0GHz x4    x86_64   8GB    1m30s   1m11s
(6) Athlon-5350    Jaguar       2.0GHz x4    x86_64   8GB    1m33s   1m10s
(7) Core i7-2720QM SandyBridge  2.2GHz x4+HT x86_64  16GB    0m31s   0m24s

・36m18s = 36分18秒
・値は実行時間(3回の平均)。数値が小さい方が高速

Raspberry Pi 2 でそのままビルドすると ARMv6 のバイナリが生成されるため、
gcc-4.8 -march=armv7-a mfpu=neon-vfpv4 のオプションでコンパイルしています。

下記はそれぞれの詳細です。

(1) Raspberry Pi model B
BMC2835 ARM1176JZF 0.7GHz x1
RAM 512MB, SD 16GB
Debian wheezy armv6l (console)


(2) Raspberry Pi 2 model B
BMC2836 Cortex-A7 0.9GHz x4
RAM 1GB DDR2, SD 16GB
Debian wheezy armv7l (console)
gcc-4.8 (-march=armv7-a mfpu=neon-vfpv4)


(3) Nexus 7 (2012)
Tegra 3 T30L Cortex-A9 1.3GHz x4
RAM 1GB DDR3L, 8GB
Ubuntu 13.04 armv7l (console)


(4) VAIO Type P
Atom Z540 Bonnell 1.86GHz x1+HT
RAM 2GB, SSD 64GB
Ubuntu 14.04LTS x86 (console)


(5) Desktop PC
BayTrail-D Celeron J1900 Silvermont 2.0GHz x4
RAM 8GB, HDD
Ubuntu 14.04LTS x86_64


(6) Desktop PC
Athlon-5350 Jaguar 2.0GHz x4
RAM 8GB, HDD
Ubuntu 14.04LTS x86_64


(7) Desktop PC
Core i7-2720QM SandyBridge 2.2GHz x4+HT
RAM 16GB, HDD
Ubuntu 14.04LTS x86_64

GPU 周りは変わっていないようです。下記ページに追加しました。

CPU/GPU OpenGL ES Extension (Mobile GPU)

Linux で Gamepad の値を読み込む & デバイスの判定

Linux では接続した Gamepad の情報を /dev/input/js* から読み取ることができます。
構造体などは /usr/include/linux/joystick.h で定義されており、
具体的な方法は下記ドキュメントの通り。

joystick-api.txt

int fd= open( "/dev/input/js0", O_RDONLY );

unsigned char  ButtonData[BUTTON_DATA_MAX];
signed int     StickData[STICK_DATA_MAX];

for(;;){
    struct js_event  event;
    if( read( fd, &event, sizeof(struct js_event) ) >= sizeof(struct js_event) ){
        switch( event.type & 0x7f ){
        case JS_EVENT_BUTTON:
            if( event.number < BUTTON_DATA_MAX ){
                ButtonData[ event.number ]= event.value != 0;
            }
            break;
        case JS_EVENT_AXIS:
            if( event.number < STICK_DATA_MAX ){
                StickData[ event.number ]= event.value;
            }
            break;
        }
    }
}
close( fd );

read() はイベントが発生するまで block するので、スレッドを使うか
他の IO のように select() を用いることが可能です。

ボタンやスティックの配列はコントローラ毎に異なっています。
アプリケーション側で配列の変更が必要です。
Windows の DirectInput で認識する配列とも異なっているようです。

とりあえず下記コントローラで動作を確認しました。

・PS3 コントローラ (USB 接続)
・Xbox 360 USB コントローラ
・PS4 DUALSHOCK4 (USB 接続)

PS3コントローラは各ボタンの感圧情報も送られてきます。
使用した環境は下記の通り。
Ubuntu 13.10 x86_x64 (64bit)

● デバイスの種類の判定

自分の環境では Gamepad だけでなく、ワイヤレスマウスのレシーバーも
/dev/input/js* に列挙されていました。
そのままでは不便なので、Gamepad かどうかの識別を行います。

udevadm info /dev/input/js0

上記コマンドでは正しく ID_INPUT_JOYSTICK と識別されているので、
udevadm の手法を調べてみました。
まず stat() で /dev/input/js* の device 番号を調べます。

struct stat  file_stat;
stat( "/dev/input/js0", &file_stat );
assert( S_ISCHR( file_stat.st_mode ) );
int dev_major= major( file_stat.st_rdev );
int dev_minor= minor( file_stat.st_rdev );

キャラクタデバイスなら "/sys/dev/char/" 以下に "major:minor" という
名前でリンクが作られているので、それを開きます。
その中の device/capabilities 以下に、対応しているボタンなどの
情報が格納されています。

例えば major,minor が 13,0 なら
/sys/dev/char/13:0/device/capabilities/key

中身は text で long 型の bit mask です。
udevadm では、この bitmask を読み取ってゲームコントローラ用のボタンが
存在してるかどうかで判別を行っていました。
ボタンなどのシンボルは /usr/include/linux/input.h で定義されています。

static bool ReadCaps( int dev_major, int dev_minor, const char* file_name, CapsType& caps )
{
    caps.Clear();
    char cap_name[CAP_NAME_MAX];
    sprintf_s( cap_name, CAP_NAME_MAX, "/sys/dev/char/%d:%d/device/capabilities/%s", file_name, dev_major, dev_minor );
    int fd= open( cap_name, O_RDONLY );
    if( fd < 0 ){
        return  false;
    }
    char    caps_buffer[STAT_MAX_SIZE];
    memset( caps_buffer, 0, STAT_MAX_SIZE );
    read( fd, caps_buffer, STAT_MAX_SIZE-1 );
    close( fd );

    const char* cp= caps_buffer;
    for(; *cp && *cp != '\n' ;){
        unsigned long   value= strtoul( cp, NULL, 16 );
        for(; *cp && *cp != ' ' ; cp++ );
        for(; *cp == ' ' || *cp == '\n' ; cp++ );
        caps.Push( value );
    }
    return  true;
}

bool IsJoystick( const char* device_path )
{
    struct stat  file_stat;
    stat( device_path, &file_stat );
    assert( S_ISCHR( file_stat.st_mode ) );
    int dev_major= major( file_stat.st_rdev );
    int dev_minor= minor( file_stat.st_rdev );

    CapsType  caps_ev;
    CapsType  caps_key;
    CapsType  caps_abs;
    ReadCaps( dev_major, dev_minor, "ev", caps_key );
    ReadCaps( dev_major, dev_minor, "key", caps_key );
    ReadCaps( dev_major, dev_minor, "abs", caps_key );

    if( caps_ev.TestBit( EV_ABS ) && caps_abs.TestBit( ABS_X ) && caps_abs.TestBit( ABS_Y ) ){
        if( cap_key.TestBit( BTN_A ) || caps_key.TestBit( BTN_TRIGGER ) || caps_key.TestBit( BTN_1 ) ){
            return  true;
        }
    }
    return  false;
}

abs に ABS_X / ABS_Y のアナログの絶対座標データが含まれており、
かつ key に BTN_A / BTN_TRIGGER / BTN_1 のいずれかが存在している場合に
JOYSTICK とみなしています。

class CapsType {
public:
    enum {
        CAPS_BUFFER_MAX= 32,
    };
private:
    unsigned long   CapsBuffer[CAPS_BUFFER_MAX];
    unsigned int    Index;
public:
    CapsType() : Index( 0 )
    {
        Clear();
    }
    void Clear()
    {
        memset( CapsBuffer, 0, sizeof(unsigned long) * CAPS_BUFFER_MAX );
        Index= 0;
    }
    void Push( unsigned long value )
    {
        if( Index < CAPS_BUFFER_MAX ){
            CapsBuffer[Index++]= value;
        }
    }
    bool TestBit( unsigned int bit_id ) const
    {
        const int   LONG_BIT_SIZE= sizeof(unsigned long) * 8;
        unsigned int    bit_no= bit_id & (LONG_BIT_SIZE-1);
        unsigned int    data_no= bit_id / LONG_BIT_SIZE;
        if( data_no < Index ){
            return  ( CapsBuffer[Index - data_no -1] & (1UL<

Linux は LP64 なので long 型のサイズは可変です。
64bit OS なら 64bit, 32bit なら 32bit となる点に注意。
32bit 時は CAPS_BUFFER_MAX が不足する可能性があるため、厳密には
/usr/include/linux/input.h で定義されている EV_MAX, KEY_MAX, ABS_MAX
からバッファサイズを求めた方が安全です。
bitmask は上位データから並んでいるので、読み込んだあとのテーブルが
逆順になる点も注意が必要です。

関連エントリ
Linux 他 X11 で OpenGL 4 を使う
Android 3.1 と GamePad のイベントの詳細 (2)
Android 3.1 と GamePad のイベントコード

Android SmartWatch SmartQ ZWatch (5) debian

MIPS 版の debian があったので試してみました。

Linux on Android

Debian-MIPS.zip を解凍すると image file が 2GB になり
そのままでは内部ストレージから溢れます。
実際の容量は 200M くらいなので、500M の新しい image file を作って
中身を全部コピーしました。
/sdcard/debian の中に debian.img として入れています。

アプリは使いません。
起動スクリプト debian.sh (debian-script.zip) はそのままでは使えないので、
必要な箇所を書き換えて adb shell から直接実行しています。

adb shell では su で容易に root になれます。
最初から busybox も入っています。

system update 直後は /system が rw で mount されているので、
この状態なら chroot で Linux を起動できます。
Z Watch を再起動すると /system は ro に戻りますが、
下記公式ページのドキュメントにあるように rw で remount できます。

SmqrtQ Z Watch Programming Guide

device 名が異なるので、debian.sh の最初で mount (remount) している
命令を削除します。

#mount -o remount,rw /dev/block/mmcblk0p5 /system

cut, grep, sed, umount などの存在しない命令は、
前に busybox を挿入します。

perm=$(id|cut -b 5)
↓
perm=$(id|busybox cut -b 5)

image file のパスは直接変数 kit に代入します。

export kit=$(dirname $0)
↓
export kit=/sdcard/debian

あくまで動くだけ。
もしアプリが root 権限で走るなら、端末の terminal からも
実行できるでしょう。

関連エントリ
Android SmartWatch スマートウオッチのスペック比較表
Android SmartWatch SmartQ ZWatch (4) アプリの管理
Android SmartWatch SmartQ ZWatch (3) 腕に関数電卓
Android SmartWatch SmartQ ZWatch (2)
Android 4.1 SmartWatch SmartQ Z Watch

Nexus 7 (2012) Ubuntu desktop 上での開発とバッテリー設定

以前の記事以降、外出時の開発用 PC として Nexus 7 (2012) が活躍しています。
GUI 周りでは Unity の dash 画面 (半透明で全画面を覆うメニュー) が特に
重いですが、terminal を開いてコードを書いたり make する分には十分です。

nexus7_flview4.jpg

↑ 3D (OpenGL ES 2.0) も動きます。(開発中)

最近 OpenGL ES 3.0 のために Nexus 10 ばかり使っていて、
Ubuntu の Nexus 7 (2012) を放置していたら起動しなくなりました。
おそらくバッテリーの過放電でしょう。

きちんと確認しなかったのが悪いのですが、電源容量が低下した時の設定が
Power off ではなく、何もしない設定になっていたのだと思われます。
Sleep で放置していたので、使わない時は電源を切るか
Android でブートしなおしておいた方がよいかもしれません。

他の Nexus 7 (2012) に新たに Ubuntu を入れなおしました。
Android 4.3 に MultiROM で Ubuntu desktop 13.04 を入れましたが
いくつか問題がありました。

(1) factory image JWR66Y (Nexus 7 nakasi) で bootloader が書き込めない

 以前ダウンロードしておいた JWR66V が動いたのでこちらを使用しました。
 JWR66V の bootloader が書き込まれたあとは JWR66Y も適用出来るようです。

(2) TWRP_multirom_n7_20130830 で ubuntu desktop を install できない

 ubuntu の img.zip decode 時にエラーが出ています。
 一つ前のバージョン TWRP_multirom 20130825 ではうまくいきました。

電源容量低下時の設定は Power Off にしています。
その状態になってみないと確認できないので、ある程度は自己責任で使うことに
なるかと思います。

現在 Ubuntu desktop が動くのは Tegra3 の Nexus 7 2012年版だけです。

関連エントリ
Nexus 7 上に開発環境をつくる (3) Ubuntu
Nexus 7 上に開発環境をつくる (2) Bluetooth と OpenGL ES 2.0
Android Tablet Nexus 7 上に開発環境をつくる (Ubuntu)