BC6H/BC7/BPTC は GPU が対応しているテクスチャ圧縮の進化系です。
DXT よりも柔軟な bit 配置が可能で圧縮画質が向上しています。(前回)
その block 構造を調べてみました。
参考にした資料は下記の 2つです。
・ARB_texture_compression_bptc
・BC6HBC7EncoderDecoder11 Sample
基本的な考え方は S3TC(DXT) と同じです。
S3TC の場合 4x4 block 単位で基準となる 2つのカラー値を保持します。
この 2色を補間し 3 または 4 階調のカラーをパレットを生成します。
4x4 block の各 pixel は 2bit の index を持っており、生成されたパレットから
1色を選択します。
BPTC/BC6H/BC7 では格納されているカラーが endpoint、補間に用いる 2色のペアが
subset と呼ばれています。さらにさまざまな工夫が施されています。
●領域分割
4x4 block を複数の領域に分割して、領域ごとに補間カラー (subset) を持つことが
できます。分割数は BC6H で 2領域まで、BC7 では 3領域まで可能です。
例えば BC7 で 3領域存在している場合、それぞれが 2つのカラー (endpoint)
持っているため独立した RGB 値を 6色分保持していることになります。
例
・領域0 = color0 color1 の補間 から 1色選択
・領域1 = color2 color3 の補間 から 1色選択
・領域2 = color4 color5 の補間 から 1色選択
分割方法は自由に選べるわけではなく、プリセットされた分割パターンから選択
することになります。
●P-bit
BC7 では格納されているカラー値の精度を稼ぐために RGB で共有された追加ビットを
加えることが出来ます。
例えば RGB それぞれ 5bit で格納されている場合、下記のように最下位に P-bit
が追加されて 6bit になります。
(この例の場合 SHARP X68000 の 16bit mode VRAM 構造 555I と同じです。)
●分割パターン
4x4 block を複数の領域 (partition) に分割して、それぞれ異なるカラー値
(endpoint) を参照することが出来ます。
BC7 の場合 2分割で 64通り、3分割で 64通りの 128種類存在します。
・BC7
分割なし
2分割、64通りから選択
3分割、16通りから選択
3分割、64通りから選択
・BC6H
分割なし
2分割、32通りから選択
●インデックス長
インデックス長は 2bit, 3bit, 4bit の 3通りあり、それぞれカラー補間によって
パレットが 4階調、8階調、16階調に展開されます。
インデックスサイズはモードによって異なります。
圧縮のために、一部のピクセルでは全階調から選択できないことがあります。
例えば BC7 mode 0 は 3bit index なので 8階調ありますが、先頭 pixel の
インデックスは 2bit しかなく前半の 4階調しか選択できません。
●独立インデックス
BC7 の Alpha 付きモードでは DXT3/DXT5 のように 16個の index を 2セット
保持することが可能です。共有するモードもあります。
・カラーとアルファのインデックスを共有
それぞれ 16個の index があり独立している。合計 32個
・カラーとアルファのインデックスを共有
16個のインデックスのみ
●独立インデックスの入れ替え
BC7 の Alpha 独立インデックスでは RGB が共有されます。
rotation モード指定により、特別扱いするチャンネル (component) を
Alpha 以外にも設定できます。
例えば BC7 mode 4 で rotation = 1 の場合 BGA が共有され、R のみ独立した
専用の index 参照が可能となります。
●BC7 のモード
選択可能な分割パターン、格納するカラー(endpoint) の bit サイズ等、画像に
合わせていくつかの組み合わせから選択することが出来ます。
BC7 では下記の 8モードが定義されています。4x4 block 単位で任意のモードを
選択することが可能です。
モード符号化の構造的上、モード数を拡張することが可能ですがデータの格納
効率は落ちます。
●BC7 の各モードの詳細
BC7 はモードごとに異なる複雑な bit 配置を取りますが、データは順番に詰めて
格納されるため BC6H のように飛び飛びの bit を拾い集める必要がありません。
続きます。
関連エントリ
・OpenGL の圧縮テクスチャ (3) BPTC, BC6H/BC7
・OpenGL の圧縮テクスチャ (2) 法線圧縮
・Android OpenGL ES 2.0 の圧縮テクスチャ
DXT よりも柔軟な bit 配置が可能で圧縮画質が向上しています。(前回)
その block 構造を調べてみました。
参考にした資料は下記の 2つです。
・ARB_texture_compression_bptc
・BC6HBC7EncoderDecoder11 Sample
基本的な考え方は S3TC(DXT) と同じです。
S3TC の場合 4x4 block 単位で基準となる 2つのカラー値を保持します。
この 2色を補間し 3 または 4 階調のカラーをパレットを生成します。
4x4 block の各 pixel は 2bit の index を持っており、生成されたパレットから
1色を選択します。
BPTC/BC6H/BC7 では格納されているカラーが endpoint、補間に用いる 2色のペアが
subset と呼ばれています。さらにさまざまな工夫が施されています。
●領域分割
4x4 block を複数の領域に分割して、領域ごとに補間カラー (subset) を持つことが
できます。分割数は BC6H で 2領域まで、BC7 では 3領域まで可能です。
例えば BC7 で 3領域存在している場合、それぞれが 2つのカラー (endpoint)
持っているため独立した RGB 値を 6色分保持していることになります。
例
・領域0 = color0 color1 の補間 から 1色選択
・領域1 = color2 color3 の補間 から 1色選択
・領域2 = color4 color5 の補間 から 1色選択
分割方法は自由に選べるわけではなく、プリセットされた分割パターンから選択
することになります。
●P-bit
BC7 では格納されているカラー値の精度を稼ぐために RGB で共有された追加ビットを
加えることが出来ます。
例えば RGB それぞれ 5bit で格納されている場合、下記のように最下位に P-bit
が追加されて 6bit になります。
H----L R= RRRRRP G= GGGGGP B= BBBBBP
(この例の場合 SHARP X68000 の 16bit mode VRAM 構造 555I と同じです。)
●分割パターン
4x4 block を複数の領域 (partition) に分割して、それぞれ異なるカラー値
(endpoint) を参照することが出来ます。
BC7 の場合 2分割で 64通り、3分割で 64通りの 128種類存在します。
・BC7
分割なし
2分割、64通りから選択
3分割、16通りから選択
3分割、64通りから選択
・BC6H
分割なし
2分割、32通りから選択
●インデックス長
インデックス長は 2bit, 3bit, 4bit の 3通りあり、それぞれカラー補間によって
パレットが 4階調、8階調、16階調に展開されます。
インデックスサイズはモードによって異なります。
圧縮のために、一部のピクセルでは全階調から選択できないことがあります。
例えば BC7 mode 0 は 3bit index なので 8階調ありますが、先頭 pixel の
インデックスは 2bit しかなく前半の 4階調しか選択できません。
●独立インデックス
BC7 の Alpha 付きモードでは DXT3/DXT5 のように 16個の index を 2セット
保持することが可能です。共有するモードもあります。
・カラーとアルファのインデックスを共有
それぞれ 16個の index があり独立している。合計 32個
・カラーとアルファのインデックスを共有
16個のインデックスのみ
●独立インデックスの入れ替え
BC7 の Alpha 独立インデックスでは RGB が共有されます。
rotation モード指定により、特別扱いするチャンネル (component) を
Alpha 以外にも設定できます。
例えば BC7 mode 4 で rotation = 1 の場合 BGA が共有され、R のみ独立した
専用の index 参照が可能となります。
●BC7 のモード
選択可能な分割パターン、格納するカラー(endpoint) の bit サイズ等、画像に
合わせていくつかの組み合わせから選択することが出来ます。
BC7 では下記の 8モードが定義されています。4x4 block 単位で任意のモードを
選択することが可能です。
BC7 mode bit mode0 = 1 mode1 = 10 mode2 = 100 mode3 = 1000 mode4 = 10000 mode5 = 100000 mode6 = 1000000 mode7 = 10000000
モード符号化の構造的上、モード数を拡張することが可能ですがデータの格納
効率は落ちます。
●BC7 の各モードの詳細
BC7 はモードごとに異なる複雑な bit 配置を取りますが、データは順番に詰めて
格納されるため BC6H のように飛び飛びの bit を拾い集める必要がありません。
BC7 mode 0 3分割 16通り endpoint: RGB 444 x6色 (subset x3) + P-bit index: 3bit (8段階) 1bit mode 指定 4bit partition 指定、16種類 24bit R 4bit x 6 24bit G 4bit x 6 24bit B 4bit x 6 6bit P-bit 1bit x 6 45bit index (3bit x13 + 2bit x3) BC7 mode1 2分割 64通り endpoint: RGB 666 x4色 (subset x2) + P-bit (shared) index: 3bit (8段階) 2bit mode 指定 6bit partition 指定、64種類 24bit R 6bit x 4 24bit G 6bit x 4 24bit B 6bit x 4 1bit shared P-bit 47bit index (3bit x14 + 2bit x1) BC7 mode2 3分割 64通り endpoint: RGB 555 x6色 (subset x3) index: 2bit (4段階) 3bit mode 指定 6bit partition 指定、64種類 30bit R 5bit x 6 30bit G 5bit x 6 30bit B 5bit x 6 29bit index (2bit x13 + 1bit x3) BC7 mode3 2分割 64通り endpoint: RGB 777 x4色 (subset x2) + P-bit index: 2bit (4段階) 4bit mode 指定 6bit partition 指定、64種類 28bit R 7bit x 4 28bit G 7bit x 4 28bit B 7bit x 4 4bit P-bit 1bit x 4 30bit index (2bit x14 + 1bit x2) BC7 mode4 分割なし endpoint: RGBA 5556 x2色 (subset x1) index: 2bit (4段階), 3bit (8階調) 5bit mode 指定 2bit rotation 指定 (A→RGB 入れ替え) 1bit Index 選択 (color 4段 + alpha 8段 or color8段 + alpha 4段) 10bit R 5bit x 2 10bit G 5bit x 2 10bit B 5bit x 2 12bit A 6bit x 2 31bit index (2bit x15 + 1bit x1) 47bit index (3bit x14 + 2bit x1) BC7 mode5 分割なし endpoint: RGBA 7778 x2色 (subset x1) index: 2bit (4段階) x2 6bit mode 指定 2bit rotation 指定 (A→RGB 入れ替え) 14bit R 7bit x 2 14bit G 7bit x 2 14bit B 7bit x 2 16bit A 8bit x 2 31bit index (2bit x15 + 1bit x1) 31bit index (2bit x15 + 1bit x1) BC7 mode6 分割なし endpoint: RGBA 7777 x2色 (subset x1) + P-bit index: 4bit (16段階) 7bit mode 指定 14bit R 7bit x 2 14bit G 7bit x 2 14bit B 7bit x 2 14bit A 7bit x 2 2bit P-bit 1bit x 2 63bit index (4bit x15 + 3bit x1) BC7 mode7 2分割 64通り endpoint: RGBA 5555 x4色 (subset x2) + P-bit index: 2bit (4段階) 8bit mode 指定 20bit R 5bit x 4 20bit G 5bit x 4 20bit B 5bit x 4 20bit A 5bit x 4 4bit P-bit 1bit x 4 30bit index (2bit x14 + 1bit x2)
続きます。
関連エントリ
・OpenGL の圧縮テクスチャ (3) BPTC, BC6H/BC7
・OpenGL の圧縮テクスチャ (2) 法線圧縮
・Android OpenGL ES 2.0 の圧縮テクスチャ
2011/02/27
OpenGL の圧縮テクスチャ (3) BPTC, BC6H/BC7
DXT1/DXT3/DXT5/ETC1 等の圧縮テクスチャは、カラー値 RGB をピクセル当たり
4bit (4bpp) に変換しています。
DXT3/5 など Alpha 付きの場合は 8bpp ですがカラー成分は 4bpp のままです。
Alpha チャンネル単独で 4bpp 分追加しています。
この垣根を無くして 8bpp 分をまるごとカラー情報に割り当てられれば、
より高品位な画像圧縮ができると考えられます。
単純に DXT1 相当と考えても、ちょうどテクスチャ 2枚分の情報を格納することが
できるわけです。4x4 エリアを 2分割してそれぞれに DXT1 相当の画素を入れたり、
保持しているベースカラーの精度を上げる事も考えられます。
Direct3D 11 で追加されたテクスチャフォーマット BC6H/BC7 はこのように
8bpp (4x4 block 128bit) を自由にリフォーマットして多くの情報を詰め込みます。
調べてみると、単に情報を増やすだけでなく画像に合わせてさまざまなモードを
選択できる自由度の高さが強みのようです。
データの格納方法もさまざまで、ベース値の精度も複数選択できます。
やはり 4x4 block は分割可能のようです。ただし ETC1 のような 4x2 ではなく
プリセットされた 32/64 通りから選べます。
その分ビット単位で情報の配置が変化するため非常に複雑な構造になっています。
・BC6H HDR 対応。16bit float に拡張
・BC7 SDR で解像度を優先
OpenGL にも BPTC と呼ばれる BC6H/BC7 相当の圧縮フォーマットが追加されています。
RADEON HD 5850 / GeForce GTX 460 で対応していることが確認できました。
実際に Direct3D 11 SDK のコンバータ texconvex で変換した bc6h_uf16/sf16/bc7
画像を OpenGL 4.1 で描画できています。
S3TC(BC1/2/3) や 3DC(BC4/5) と同じようにバイナリで互換性が保たれているようです。
OpenGL や OpenGL ES 2.0 向け GPU で使える圧縮テクスチャの種類と対応をこちらにまとめました。
・OpenGL/OpenGL ES 2.0 テクスチャフォーマットまとめ
関連エントリ
・OpenGL の圧縮テクスチャ (2) 法線圧縮
・Android OpenGL ES 2.0 の圧縮テクスチャ
4bit (4bpp) に変換しています。
DXT3/5 など Alpha 付きの場合は 8bpp ですがカラー成分は 4bpp のままです。
Alpha チャンネル単独で 4bpp 分追加しています。
この垣根を無くして 8bpp 分をまるごとカラー情報に割り当てられれば、
より高品位な画像圧縮ができると考えられます。
単純に DXT1 相当と考えても、ちょうどテクスチャ 2枚分の情報を格納することが
できるわけです。4x4 エリアを 2分割してそれぞれに DXT1 相当の画素を入れたり、
保持しているベースカラーの精度を上げる事も考えられます。
Direct3D 11 で追加されたテクスチャフォーマット BC6H/BC7 はこのように
8bpp (4x4 block 128bit) を自由にリフォーマットして多くの情報を詰め込みます。
調べてみると、単に情報を増やすだけでなく画像に合わせてさまざまなモードを
選択できる自由度の高さが強みのようです。
データの格納方法もさまざまで、ベース値の精度も複数選択できます。
やはり 4x4 block は分割可能のようです。ただし ETC1 のような 4x2 ではなく
プリセットされた 32/64 通りから選べます。
その分ビット単位で情報の配置が変化するため非常に複雑な構造になっています。
・BC6H HDR 対応。16bit float に拡張
・BC7 SDR で解像度を優先
OpenGL にも BPTC と呼ばれる BC6H/BC7 相当の圧縮フォーマットが追加されています。
RADEON HD 5850 / GeForce GTX 460 で対応していることが確認できました。
DXGI(DirectX) OpenGL ----------------------------------------------------------------------- DXGI_FORMAT_BC6H_UF16 GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB DXGI_FORMAT_BC6H_SF16 GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB DXGI_FORMAT_BC7_UNORM GL_COMPRESSED_RGBA_BPTC_UNORM_ARB DXGI_FORMAT_BC7_UNORM_SRGB GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB
実際に Direct3D 11 SDK のコンバータ texconvex で変換した bc6h_uf16/sf16/bc7
画像を OpenGL 4.1 で描画できています。
S3TC(BC1/2/3) や 3DC(BC4/5) と同じようにバイナリで互換性が保たれているようです。
OpenGL や OpenGL ES 2.0 向け GPU で使える圧縮テクスチャの種類と対応をこちらにまとめました。
・OpenGL/OpenGL ES 2.0 テクスチャフォーマットまとめ
関連エントリ
・OpenGL の圧縮テクスチャ (2) 法線圧縮
・Android OpenGL ES 2.0 の圧縮テクスチャ
2011/02/20
OpenGL の圧縮テクスチャ (2) 法線圧縮
ノーマルマップの圧縮フォーマットは 3DC が有名です。
Tangent Space の法線マップの場合 z の符号が不要なので (x,y,z) のうち
x,y のみ保存しておけば z= sqrt( 1- (x*x + y*y) ) で値が求まります。
上記の通りシェーダー側に多少追加コードが必要となるものの、RGB8 24bpp
ではなく LA8/RG8 など 16bpp の画像に保存することができます。
さらに DXT5 (8bpp) の color, alpha を独立した 2チャンネルとみなして
法線圧縮する手法 (DXT5n) があります。その応用で DXT5 の alpha 圧縮の構造を
用いて独立 2チャンネルを格納するのが 3DC です。
同じように 1 チャンネルの 4bpp フォーマットもあります。
・Block Compression (Direct3D 10)
最近 OpenGL の GPU で見かける latc, rgtc も同様の構造を持った 1,2 チャンネル
圧縮フォーマットのようです。
3DC が Direct3D 10 以降 DXGI で BC4, BC5 と呼ばれているのと同様に、
OpenGL で定義された呼び方だと思われます。
LATC と RGTC の違いはチャンネルへの展開方法だけです。
RGTC は 3DC や BC5 と互換性があります。
その代わり LATC は DXT5n とシェーダーコードを共有できます。
RADEON (GL4.1) の場合いくつか注意点があります。
glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS, lists )
が列挙を返してきません。代わりに Extension String の
glGetStringi( GL_EXTENSIONS, i ) で判定する必要があります。
また GL_ATI_texture_compression_3dc があっても OpenGL ES 2.0 と違い
rgtc の方を使います。
つまり GL_3DC_XY ではなく GL_COMPRESSED_RED_GREEN_RGTC2_EXT 。
OpenGL ES 2.0 GPU の場合 Adreno (ATI系) が 3DC、Tegra2 が LATC に対応
しています。
利用可能なカラー圧縮、法線圧縮フォーマットをまとめると下記の通りです。
対応していない GPU は非圧縮 LA8 で代用しなければなりません。
圧縮に対応していても RG(3DC) と LA でシェーダーを完全に共有するのは
難しそうです。
関連エントリ
・Android OpenGL ES 2.0 の圧縮テクスチャ
Tangent Space の法線マップの場合 z の符号が不要なので (x,y,z) のうち
x,y のみ保存しておけば z= sqrt( 1- (x*x + y*y) ) で値が求まります。
上記の通りシェーダー側に多少追加コードが必要となるものの、RGB8 24bpp
ではなく LA8/RG8 など 16bpp の画像に保存することができます。
さらに DXT5 (8bpp) の color, alpha を独立した 2チャンネルとみなして
法線圧縮する手法 (DXT5n) があります。その応用で DXT5 の alpha 圧縮の構造を
用いて独立 2チャンネルを格納するのが 3DC です。
同じように 1 チャンネルの 4bpp フォーマットもあります。
・Block Compression (Direct3D 10)
最近 OpenGL の GPU で見かける latc, rgtc も同様の構造を持った 1,2 チャンネル
圧縮フォーマットのようです。
3DC が Direct3D 10 以降 DXGI で BC4, BC5 と呼ばれているのと同様に、
OpenGL で定義された呼び方だと思われます。
ATI DX9 DX10/DXGI OpenGL ES OpenGL ------------------------------------------------------------ 3DC_X 4bpp ATI1 BC4 LATC1 LATC1/RGTC1 3DC_XY 8bpp ATI2 BC5 LATC2 LATC1/RGTC2
DX10/DXGI FourCC OpenGL ----------------------------------------------------------------------------- DXGI_FORMAT_BC4_UNORM "BC4U" GL_COMPRESSED_RED_RGTC1_EXT 0x8dbb DXGI_FORMAT_BC4_SNORM "BC4S" GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8dbc DXGI_FORMAT_BC5_UNORM "ATI2" GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8dbd DXGI_FORMAT_BC5_SNORM "BC5S" GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8dbe
LATC と RGTC の違いはチャンネルへの展開方法だけです。
RGTC は 3DC や BC5 と互換性があります。
その代わり LATC は DXT5n とシェーダーコードを共有できます。
vec4 tex_normal= texture2D( NormalMap, otexcoord ); // RGTC unsigned, 3DC_XY, RG8 tex_normal.xy= tex_normal.xy * 2.0 - 1.0; tex_normal.z= sqrt( 1.0- dot( tex_normal.xy, tex_normal.xy ) ); // LATC unsigned, DXT5n, LA8 tex_normal.xy= tex_normal.yw * 2.0 - 1.0; tex_normal.z= sqrt( 1.0- dot( tex_normal.xy, tex_normal.xy ) );
RADEON (GL4.1) の場合いくつか注意点があります。
glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS, lists )
が列挙を返してきません。代わりに Extension String の
glGetStringi( GL_EXTENSIONS, i ) で判定する必要があります。
また GL_ATI_texture_compression_3dc があっても OpenGL ES 2.0 と違い
rgtc の方を使います。
つまり GL_3DC_XY ではなく GL_COMPRESSED_RED_GREEN_RGTC2_EXT 。
// GL_EXT_texture_compression_latc GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 // GL_EXT_texture_compression_rgtc GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
OpenGL ES 2.0 GPU の場合 Adreno (ATI系) が 3DC、Tegra2 が LATC に対応
しています。
利用可能なカラー圧縮、法線圧縮フォーマットをまとめると下記の通りです。
COLOR COLOR-EA COLOR-IA NORMAL NORMAL-S 1ch -------------------------------------------------------------- PowerVR PVRTC -- PVRTC-A -- -- -- Adreno ATC ATC-A ATC-I 3DC_XY -- 3DC_X Tegra DXT1 DXT3 DXT5 LATC2 LATC2-S LATC1 ZMS DXT1 DXT3 DXT5 (DXT5n) -- -- Mali ETC1 -- -- -- -- --
対応していない GPU は非圧縮 LA8 で代用しなければなりません。
圧縮に対応していても RG(3DC) と LA でシェーダーを完全に共有するのは
難しそうです。
関連エントリ
・Android OpenGL ES 2.0 の圧縮テクスチャ
2011/02/16
Android OpenGL ES 2.0 の圧縮テクスチャ
OpenGL ES 2.0 では使用可能な圧縮テクスチャ形式が GPU 毎に異なっています。
カラー向けのフォーマットは現在大きく分けて下記の 4 通りあります。
(1) PVRTC 系
(2) ATITC 系
(3) S3TC(DXT) 系
(4) ETC 系
●(1) PVRTC 系
PowerVR SGX 系各種。
iOS 系の全機種で使われているため対応ハードはかなり多いはずです。
Android の場合は Galaxy S/Tab の Samsung S5PC110 等。
フォーマットは下記の 4通り。
PVRTC は 2bpp/4bpp 選択可能で alpha チャンネルを含めることができるため
同一解像度なら他のフォーマットよりも少ない容量に変換されます。
反面、正方形しばりがあります。元画像が正方形でない場合は引き伸ばすことに
なるため逆に容量が大きくなるケースがあります。
2倍までのスケーリングなら 2bpp に落とすことでほぼ同等の画質と容量を維持
することができると思われます。
例
・元画像が 256x256 なら 4bpp に変換
・元画像が 128x256 なら 256x256 に拡大+ 2bpp に変換
変換ツールは開発者サイト PowerVR Insder にあります。
・Imagination PowerVR Insider
テクスチャは専用の pvr 形式で保存しますが、pvr 形式自体は ETC,DXT 等
さまざまなフォーマットを格納可能です。
●(2) ATITC 系
ATI の Imageon 及び、Qualcomm の Snapdragon 等に搭載されている Adreno
シリーズで対応しています。
Android に限定すると対応端末はかなり多いと思われます。
4bpp 時に 1bit alpha を含められない以外は圧縮率も機能共にほぼ
DXT1/DXT3/DXT5 と同等になっているようです。画質に関しては未調査。
圧縮ツールは AMD(ATI) 製のものがあります。
このツールは ATC や ETC を DDS 形式で保存します。
・AMD The Compressonator
Adreno と改名した後 Qualcomm も開発者向けページを用意しています。
・Adreno Graphics
ATITC 系 GPU は法線などカラー以外に応用可能な 3DC (BC4/5) も対応している
のが特徴です。
●(3) S3TC/DXT 系
NVIDIA Tegra2, 3DLabs ZMS-08 HD, PC 向け GPU 各種。
DirectX の標準フォーマットであり、OpenGL でも多くの PC 向け GPU が
対応しています。
とにかく対応しているツール数が多く、変換や扱いで困ることがありません。
DXT1 は 1bit の alpha 値を含めることが出来ますが、OpenGL の場合この
両者を区別しています。厳密には 4x4 pixel の block 単位で切り替えられる
ため DirectX では区別がありません。
DXT1/DXT3/DXT5 は Direct3D 10 以降 BC1/BC2/BC3 と呼ばれます。
●(4) ETC 系
Android の場合すべての GPU で利用できます。
ARM Mali など ETC のみ対応している GPU もあります。
iOS では PowerVR 一つなので問題ありませんが、Android では GPU 毎に
互換性のない様々な圧縮テクスチャ形式を持っています。
Android で唯一の共通フォーマットとして利用出来るのが ETC1 圧縮です。
Froyo 2.2 以降 ETC1 専用の API も用意されています。
iOS では使えませんが Android 上では PowerVR も ETC1 が使えます。
ETC1 の圧縮は比較的多くのツールで対応しています。
例えば ATITC で紹介した AMD The Compressonator も ETC 変換可能で DDS として
保存できます。
ただし ETC 圧縮時に画質(変換速度)を指定できず、プレビューで極端に劣化した
画像が表示されることがあります。PVR 用の PVRTexTool ツールで読み込ませると
正しく表示されるため、The Compressonator だと ETC 画像の読み込み部に
何らかの問題がありそうです。
Ericsson 本家及び Mali のツールがあります。
・Ericsson Texture Compression
・Mali Developer Center
●ファイルフォーマット
●DDS
DirectX 標準フォーマットです。mipmap, cubemap, volume, array など各種形式に
対応可能で、古くから使われているためツール類が揃っています。
特殊なフォーマットは FourCC で識別しているので、4文字のコードが決まれば
新しい圧縮形式でも対応できます。
・DDS Texture format memo
●PVR
PVRTC だけでなく DXT/ETC などさまざまな画像フォーマットに対応しているようです。
ATITC のファイルタイプは定義されていないので格納できません。
比較的ツールも揃っているようです。
●KTX
OpenGL / OpenGL ES 向けに新たに作られたフォーマットのようです。
PVRTexTool が対応しています。
GL のシンボル値をそのまま格納するので GL API と相性が良いのが特徴。
OpenGL で数値が定義されていれば、新しい圧縮形式でもそのまま保存する
ことが出来ます。
・Khronos KTX File Format Specification
画像格納時の優先順が DDS と逆で、3d/cube/array を持ったデータが mipmap 個
並ぶ順番になっています。
ツールでは画像の上下など GL の定義に厳密に変換される可能性があるようです。
メタデータ KTXorientation を調べることで uv の向きがわかります。
ヘッダが Bigendian/Littleendian 両対応しているなど、ターゲットハードに
最適化した実行時向けのフォーマットと思われます。
●PKM
ETC1 (PACKMAN) のための専用フォーマットのようです。
Android の ETC1 用 API が対応しています。
●Android とテクスチャ
効率を考えると GPU Native なフォーマットの方が有利ですが管理が大変です。
それでも速度最優先なら全部持つしかなさそうです。
1. alpha 不要なら ETC1
2. alpha が必要で速度優先なら PVRTC,ATITC,S3TC,非圧縮 全部
カラー向けのフォーマットは現在大きく分けて下記の 4 通りあります。
(1) PVRTC 系
(2) ATITC 系
(3) S3TC(DXT) 系
(4) ETC 系
iOS PowerVR SGX PVRTC Android Qualcomm Adreno ETC1, ATITC, 3DC, PALETTE ATI Imageon ETC1, ATITC, 3DC, PALETTE Imagination PowerVR ETC1, PVRTC NVIDIA Tegra2 ETC1, S3TC(DXT), LATC ZiiLabs ZMS-08 HD ETC1, S3TC(DXT), PALETTE
●(1) PVRTC 系
PowerVR SGX 系各種。
iOS 系の全機種で使われているため対応ハードはかなり多いはずです。
Android の場合は Galaxy S/Tab の Samsung S5PC110 等。
フォーマットは下記の 4通り。
PVRTC RGB 4bpp PVRTC RGBA 4bpp PVRTC RGB 2bpp PVRTC RGBA 2bpp
PVRTC は 2bpp/4bpp 選択可能で alpha チャンネルを含めることができるため
同一解像度なら他のフォーマットよりも少ない容量に変換されます。
反面、正方形しばりがあります。元画像が正方形でない場合は引き伸ばすことに
なるため逆に容量が大きくなるケースがあります。
2倍までのスケーリングなら 2bpp に落とすことでほぼ同等の画質と容量を維持
することができると思われます。
例
・元画像が 256x256 なら 4bpp に変換
・元画像が 128x256 なら 256x256 に拡大+ 2bpp に変換
変換ツールは開発者サイト PowerVR Insder にあります。
・Imagination PowerVR Insider
テクスチャは専用の pvr 形式で保存しますが、pvr 形式自体は ETC,DXT 等
さまざまなフォーマットを格納可能です。
●(2) ATITC 系
ATI の Imageon 及び、Qualcomm の Snapdragon 等に搭載されている Adreno
シリーズで対応しています。
Android に限定すると対応端末はかなり多いと思われます。
FourCC bpp ATITC RGB 'ATC ' 4bpp ATITC RGBA 'ATCA' 8bpp Explicit Alpha ATITC RGBA 'ATCI' 8bpp Interpolated Alpha
4bpp 時に 1bit alpha を含められない以外は圧縮率も機能共にほぼ
DXT1/DXT3/DXT5 と同等になっているようです。画質に関しては未調査。
圧縮ツールは AMD(ATI) 製のものがあります。
このツールは ATC や ETC を DDS 形式で保存します。
・AMD The Compressonator
Adreno と改名した後 Qualcomm も開発者向けページを用意しています。
・Adreno Graphics
ATITC 系 GPU は法線などカラー以外に応用可能な 3DC (BC4/5) も対応している
のが特徴です。
●(3) S3TC/DXT 系
NVIDIA Tegra2, 3DLabs ZMS-08 HD, PC 向け GPU 各種。
DirectX の標準フォーマットであり、OpenGL でも多くの PC 向け GPU が
対応しています。
とにかく対応しているツール数が多く、変換や扱いで困ることがありません。
FourCC bpp dx10 S3TC RGB 'DXT1' 4bpp BC1 S3TC RGBA 'DXT1' 4bpp BC1 (1bit alpha) S3TC RGBA 'DXT3' 8bpp BC2 S3TC RGBA 'DXT5' 8bpp BC3
DXT1 は 1bit の alpha 値を含めることが出来ますが、OpenGL の場合この
両者を区別しています。厳密には 4x4 pixel の block 単位で切り替えられる
ため DirectX では区別がありません。
DXT1/DXT3/DXT5 は Direct3D 10 以降 BC1/BC2/BC3 と呼ばれます。
●(4) ETC 系
Android の場合すべての GPU で利用できます。
ARM Mali など ETC のみ対応している GPU もあります。
iOS では PowerVR 一つなので問題ありませんが、Android では GPU 毎に
互換性のない様々な圧縮テクスチャ形式を持っています。
Android で唯一の共通フォーマットとして利用出来るのが ETC1 圧縮です。
Froyo 2.2 以降 ETC1 専用の API も用意されています。
iOS では使えませんが Android 上では PowerVR も ETC1 が使えます。
FourCC bpp ETC RGB 'ETC ' 4bpp
ETC1 の圧縮は比較的多くのツールで対応しています。
例えば ATITC で紹介した AMD The Compressonator も ETC 変換可能で DDS として
保存できます。
ただし ETC 圧縮時に画質(変換速度)を指定できず、プレビューで極端に劣化した
画像が表示されることがあります。PVR 用の PVRTexTool ツールで読み込ませると
正しく表示されるため、The Compressonator だと ETC 画像の読み込み部に
何らかの問題がありそうです。
Ericsson 本家及び Mali のツールがあります。
・Ericsson Texture Compression
・Mali Developer Center
●ファイルフォーマット
PVRTC ATITC S3TC ETC 拡張 ---------------------------------- DDS -- ◯ ◎ ◯ FourCC PVR ◎ -- ◯ ◯ KTX ◯ ◯ ◯ ◯ GL_* PKM -- -- -- ◎
●DDS
DirectX 標準フォーマットです。mipmap, cubemap, volume, array など各種形式に
対応可能で、古くから使われているためツール類が揃っています。
特殊なフォーマットは FourCC で識別しているので、4文字のコードが決まれば
新しい圧縮形式でも対応できます。
・DDS Texture format memo
●PVR
PVRTC だけでなく DXT/ETC などさまざまな画像フォーマットに対応しているようです。
ATITC のファイルタイプは定義されていないので格納できません。
比較的ツールも揃っているようです。
●KTX
OpenGL / OpenGL ES 向けに新たに作られたフォーマットのようです。
PVRTexTool が対応しています。
GL のシンボル値をそのまま格納するので GL API と相性が良いのが特徴。
OpenGL で数値が定義されていれば、新しい圧縮形式でもそのまま保存する
ことが出来ます。
・Khronos KTX File Format Specification
画像格納時の優先順が DDS と逆で、3d/cube/array を持ったデータが mipmap 個
並ぶ順番になっています。
ツールでは画像の上下など GL の定義に厳密に変換される可能性があるようです。
メタデータ KTXorientation を調べることで uv の向きがわかります。
ヘッダが Bigendian/Littleendian 両対応しているなど、ターゲットハードに
最適化した実行時向けのフォーマットと思われます。
●PKM
ETC1 (PACKMAN) のための専用フォーマットのようです。
Android の ETC1 用 API が対応しています。
●Android とテクスチャ
効率を考えると GPU Native なフォーマットの方が有利ですが管理が大変です。
それでも速度最優先なら全部持つしかなさそうです。
1. alpha 不要なら ETC1
2. alpha が必要で速度優先なら PVRTC,ATITC,S3TC,非圧縮 全部
2011/02/07
Android NDK と NativeActivity
Android OS 2.3、API Level 9 から NativeActivity が利用出来るようになります。
画面の初期化やイベントの取得も Java コードを通らずに C/C++ だけで
記述することが可能です。
とは言え実際にアプリケーションを記述する手段はこれまでとほとんど変わりません。
jni フォルダに C/C++ コードを置いて ndk-build を使います。
生成されるバイナリも従来同様 Dynamic Link Library (dll) ~.so です。
・今までの NDK (jni)
Java 上で dll をロードし、interface class を経由して呼び出し
・NativeActivity
システムが直接 dll をロードし dll 内のエントリポイントを直接呼び出す
●エントリポイントの指定
最初に呼ばれる関数名を AndroidManifest.xml に記述します。
・Java コードを含まないことを宣言
<application> のアトリビュートに android:hasCode="false"
・dll 名の指定
<activity> 宣言内に <meta-data> で指定する。
例えば libappmain.so の場合
・エントリポイント名の指定
例えば関数 Main_onCreate() から開始する場合
これで Activity の起動時に libappmain.so 内の Main_onCreate() が
直接呼び出されるようになります。
●イベント
Java と全く同様に NativeActivity も onStart, onResume, onPause, onStop,
onDestroy, onRestart 等のイベントが呼ばれます。
あらかじめイベントごとに Callback 関数を登録しておく必要があります。
onCreate のみ特別で、Callback ではなく Activity 起動時のエントリ関数として
AndroidManifest.xml に記述します。
AndroidManifest.xml に func_name の記述がない場合は関数名
ANativeActivity_onCreate() とみなします。
この関数の実体はアプリケーション側で記述しておく必要があります。
(1) onCreate で AndroidManifest.xml に記述した関数が呼ばれる
(2) onCreate 内部で他のイベントの Callback 関数を登録する
(3) 各イベントで Callback 関数が呼ばれる
●android_native_app_glue
ndk の sample/native-activity や NativeActivity の Reference に
掲載されてるコードは android_native_app_glue を使っています。
これはサンプルに含まれる Utility Library です。
内部では下記の動作を行っています。
1. 各イベントごとの Callback 関数を登録する
2. NativeActivity 用のスレッドを生成する
3. イベントを格納するキューを作る
4. ユーザー定義関数 android_main() をスレッドから呼び出す
つまり、これにより android_main をイベント待ちのループとして記述できる
ようになります。Win32 API とかでよくあるスタイルです。
●static 領域の初期化
NativeActivity でも従来の jni 経由の NDK (dll) 呼び出しと全く同じです。
Activity が onDestroy で破棄されても dll 自体はしばらくメモリ上に
常駐する可能性があります。
この場合再び onCreate しても static 変数の値が初期化されずに以前の値を
残しています。
onCreate 時に自分で初期化するか前回試したような dll の分離が必要となります。
参考ページ
・NativeActivity
関連エントリ
・Android NDK の初期化と dll の分離
・Android アプリケーションとプロセス
画面の初期化やイベントの取得も Java コードを通らずに C/C++ だけで
記述することが可能です。
とは言え実際にアプリケーションを記述する手段はこれまでとほとんど変わりません。
jni フォルダに C/C++ コードを置いて ndk-build を使います。
生成されるバイナリも従来同様 Dynamic Link Library (dll) ~.so です。
・今までの NDK (jni)
Java 上で dll をロードし、interface class を経由して呼び出し
・NativeActivity
システムが直接 dll をロードし dll 内のエントリポイントを直接呼び出す
●エントリポイントの指定
最初に呼ばれる関数名を AndroidManifest.xml に記述します。
・Java コードを含まないことを宣言
<application> のアトリビュートに android:hasCode="false"
・dll 名の指定
<activity> 宣言内に <meta-data> で指定する。
例えば libappmain.so の場合
<meta-data android:name="android.app.lib_name" android:value="appmain" />
・エントリポイント名の指定
例えば関数 Main_onCreate() から開始する場合
<meta-data android:name="android.app.func_name" android:value="Main_onCreate" />
これで Activity の起動時に libappmain.so 内の Main_onCreate() が
直接呼び出されるようになります。
●イベント
Java と全く同様に NativeActivity も onStart, onResume, onPause, onStop,
onDestroy, onRestart 等のイベントが呼ばれます。
あらかじめイベントごとに Callback 関数を登録しておく必要があります。
onCreate のみ特別で、Callback ではなく Activity 起動時のエントリ関数として
AndroidManifest.xml に記述します。
AndroidManifest.xml に func_name の記述がない場合は関数名
ANativeActivity_onCreate() とみなします。
この関数の実体はアプリケーション側で記述しておく必要があります。
(1) onCreate で AndroidManifest.xml に記述した関数が呼ばれる
(2) onCreate 内部で他のイベントの Callback 関数を登録する
(3) 各イベントで Callback 関数が呼ばれる
●android_native_app_glue
ndk の sample/native-activity や NativeActivity の Reference に
掲載されてるコードは android_native_app_glue を使っています。
これはサンプルに含まれる Utility Library です。
内部では下記の動作を行っています。
1. 各イベントごとの Callback 関数を登録する
2. NativeActivity 用のスレッドを生成する
3. イベントを格納するキューを作る
4. ユーザー定義関数 android_main() をスレッドから呼び出す
つまり、これにより android_main をイベント待ちのループとして記述できる
ようになります。Win32 API とかでよくあるスタイルです。
●static 領域の初期化
NativeActivity でも従来の jni 経由の NDK (dll) 呼び出しと全く同じです。
Activity が onDestroy で破棄されても dll 自体はしばらくメモリ上に
常駐する可能性があります。
この場合再び onCreate しても static 変数の値が初期化されずに以前の値を
残しています。
onCreate 時に自分で初期化するか前回試したような dll の分離が必要となります。
参考ページ
・NativeActivity
関連エントリ
・Android NDK の初期化と dll の分離
・Android アプリケーションとプロセス
2011/02/06
Android NDK の初期化と dll の分離
NDK では C/C++ のコードをそのまま使うことが出来ます。
Windows 上で作っていた lib やアプリケーションを移植し Android 上で
走らせています。
実際に動作するのですが少々問題があって、正しく起動する場合もあれば
アイコンをタッチした瞬間に落ちる場合があります。
Activity が終了しても Process イメージは残り、再び onCreate した時に
常駐している Native コードが再利用される可能性があるからです。
bss/data セグメントが初期化されていないことが原因でしょう。
static 変数は初期値に戻らず global オブジェクトのコンストラクタも走りません。
NVIDIA の資料でアプリ本体を別の dll に分離する手法が紹介されていたので
試してみました。
・GameSauce 2010: Fast and Pretty: Making Responsive, Quality 3D Content on Android
Java Application からロードされるダミー (Thunk) dll を作り、その中で
自分でアプリ本体の dll を load/unload します。
確実に Unload できる点がポイントです。
NDK で複数の Dynamic Link Library (~.so) を build するには下記のようにします。
ndk-build で 2つの dll ファイル libappmain.so, libjniproxy.so が作られます。
include $(CLEAR_VARS) は LOCAL_~ の変数を再定義可能にします。
Java 側でロードする dll は libjniproxy.so だけです。
jniproxy.cpp は libappmain.so のロード管理や呼び出しを行います。
元の android_main.cpp では jni 名を app_~ に変更しておきます。
アプリケーション側で dll の読み込みと終了タイミングを指定します。
スレッドの違いに注意が必要です。
例えば GL API は異なるスレッドから呼び出すことが出来ませんが、
GLSurfaceView.Renderer は別スレッドで動作しています。
Activity から呼び出す場合は GLSurfaceView.queueEvent() を使います。
現在 Activity の onPause() と GLSurfaceView.Renderer の
onSurfaceChanged() を使っています。
dll の分離はうまくいっており、比較的簡単な追加コードだけで確実に初期化が
行われるようになりました。libjniproxy.so は 4KB 程度。
安定して動いています。
その代わり onPause()/onResume() で unload/load となるので、
端末を Sleep させたり別のアプリに切り替えただけでアプリケーションの
ndk 部は再起動とほぼ同様の状態となります。
関連エントリ
・Android アプリケーションとプロセス
Windows 上で作っていた lib やアプリケーションを移植し Android 上で
走らせています。
実際に動作するのですが少々問題があって、正しく起動する場合もあれば
アイコンをタッチした瞬間に落ちる場合があります。
Activity が終了しても Process イメージは残り、再び onCreate した時に
常駐している Native コードが再利用される可能性があるからです。
bss/data セグメントが初期化されていないことが原因でしょう。
static 変数は初期値に戻らず global オブジェクトのコンストラクタも走りません。
NVIDIA の資料でアプリ本体を別の dll に分離する手法が紹介されていたので
試してみました。
・GameSauce 2010: Fast and Pretty: Making Responsive, Quality 3D Content on Android
Java Application からロードされるダミー (Thunk) dll を作り、その中で
自分でアプリ本体の dll を load/unload します。
確実に Unload できる点がポイントです。
NDK で複数の Dynamic Link Library (~.so) を build するには下記のようにします。
# Andriod.mak LOCAL_PATH:= $(call my-dir) #-------------------------------------- include $(CLEAR_VARS) LOCAL_SRC_FILES := android_main.cpp ~ LOCAL_MODULE := libappmain LOCAL_CFLAGS := LOCAL_C_INCLUDES:= LOCAL_LDLIBS := -llog -lGLESv2 include $(BUILD_SHARED_LIBRARY) #-------------------------------------- #-------------------------------------- include $(CLEAR_VARS) LOCAL_SRC_FILES := jniproxy.cpp LOCAL_MODULE := libjniproxy LOCAL_CFLAGS := LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) #--------------------------------------
ndk-build で 2つの dll ファイル libappmain.so, libjniproxy.so が作られます。
include $(CLEAR_VARS) は LOCAL_~ の変数を再定義可能にします。
Java 側でロードする dll は libjniproxy.so だけです。
// appmain.java package jp.flatlib.appmain; public class appmain { static { System.loadLibrary( "jniproxy" ); } public static native void init(); public static native void quit(); public static native int render(); ~ }
jniproxy.cpp は libappmain.so のロード管理や呼び出しを行います。
// jniproxy.cpp #include <jni.h> #include <android/log.h> #include <dlfcn.h> template<typename T> void auto_load( T& a, void* ptr ) { a= reinterpret_cast<T>( ptr ); } #define get_proc_0( image, func_name ) auto_load( proc_##func_name, dlsym( image, #func_name ) ) #define get_proc( func_name ) get_proc_0( LoadApplication, func_name ) //----------------------------------------------------------------------------- static void JNICALL (*proc_app_init)( JNIEnv* env, jobject obj ); static void JNICALL (*proc_app_quit)( JNIEnv* env, jobject obj ); static jint JNICALL (*proc_app_render)( JNIEnv* env, jobject obj ); ~ //----------------------------------------------------------------------------- static void* LoadApplication= NULL; static void InitializeApplication() { // lib 読み込み LoadApplication= dlopen( "/data/data/jp.flatlib.appmain/lib/libappmain.so", RTLD_LAZY ); if( !LoadApplication ){ ~ error } // API 取り出し get_proc( app_init ); get_proc( app_quit ); get_proc( app_render ); ~ } static void FinalizeApplication() { if( LoadApplication ){ dlclose( LoadApplication ); LoadApplication= NULL; } } extern "C" { //----------------------------------------------------------------------------- JNIEXPORT void JNICALL Java_jp_flatlib_appmain_appmain_init( JNIEnv* env, jobject obj ) { if( !LoadApplication ){ InitializeApplication(); proc_app_init( env, obj ); } } JNIEXPORT void JNICALL Java_jp_flatlib_appmain_appmain_quit( JNIEnv* env, jobject obj ) { if( LoadApplication ){ proc_app_quit( env, obj ); FinalizeApplication(); } } JNIEXPORT jint JNICALL Java_jp_flatlib_appmain_appmain_render( JNIEnv* env, jobject obj ) { return LoadApplication ? proc_app_render( env, obj ) : 0; } ~ //----------------------------------------------------------------------------- };
元の android_main.cpp では jni 名を app_~ に変更しておきます。
// android_main.cpp ~ extern "C" { JNIEXPORT void JNICALL app_init( JNIEnv* env, jobject obj ) { } JNIEXPORT void JNICALL app_quit( JNIEnv* env, jobject obj ) { } JNIEXPORT jint JNICALL app_render( JNIEnv* env, jobject obj ) { } ~ };
アプリケーション側で dll の読み込みと終了タイミングを指定します。
スレッドの違いに注意が必要です。
例えば GL API は異なるスレッドから呼び出すことが出来ませんが、
GLSurfaceView.Renderer は別スレッドで動作しています。
Activity から呼び出す場合は GLSurfaceView.queueEvent() を使います。
mView.queueEvent( new Runnable(){ public void run(){ appmain.quit(); } });
現在 Activity の onPause() と GLSurfaceView.Renderer の
onSurfaceChanged() を使っています。
dll の分離はうまくいっており、比較的簡単な追加コードだけで確実に初期化が
行われるようになりました。libjniproxy.so は 4KB 程度。
安定して動いています。
その代わり onPause()/onResume() で unload/load となるので、
端末を Sleep させたり別のアプリに切り替えただけでアプリケーションの
ndk 部は再起動とほぼ同様の状態となります。
関連エントリ
・Android アプリケーションとプロセス
2011/02/05
Android アプリケーションとプロセス
Android のアプリケーションは明確な終了をあまり意識させない作りになっています。
それでも使っているうちにだんだん Android の挙動が分かってきます。
・Home ボタンでホームメニューに戻っただけでは終了しない
・Back ボタンで戻る場合はアプリが終了していることが多い
よってアプリケーションの切り替え方法は 2種類あります。
(1) 現在の状態を保ったままバックグラウンドに切り替える方法
(2) 現在の状態を捨てて前の画面(アプリ)に戻る方法
さらにあまり意識していないだけでもう1つあることがわかりました。
(3) 現在の状態を保ったまま別のアプリを呼び出す。
例えばアプリ内から URL をタッチしてブラウザが呼ばれた場合。
また Home ボタン長押しでタスクマネージャーを呼び出し、そこからアプリを
呼び出した場合も同様です。
どちらも Back ボタンを押すと前のアプリの画面に戻ることが出来ます。
(2) はスタックから pop する動作で、ブラウザに例えると [←] ボタン。
(3) はスタックに push する動作で、ブラウザだとページ内のリンクのクリック。
(1) はスタックを切り替えます。ブラウザの新しい Tab を開くようなものです。
厳密にはアプリケーションは Activity という単位に分かれており、
実行したり外部から呼び出されるのはこの Activity です。
アプリケーションがどこかのサイトを示すなら Activity はページ相当でしょうか。
Android は複数のサイト(アプリ)間にまたがって各ページにリンクを貼ることが
可能で、その履歴が保存されます。
この Activity の呼び出しヒストリが保存されている一連のスタックを "Task" と
呼んでいます。やはりブラウザの Tab のように、操作によっては複数の履歴
スタック ("Task") が作られます。
これらのアプリが動作している VM は Linux の Process の上で動いています。
Android はマルチタスクの OS なので複数のアプリケーションが起動します。
動作中のアプリがバックグラウンドに残ってシステムが重くならないよう、
普段から意識して Back ボタンを多用していました。
ブラウザのように明確な Tab 切り替えができて、かつ Tab 単位で Close
ボタンがあればもっと分かりやすくなっていたのではないかと思います。
●複数の終了・中断状態
画面から見えなくなったりバックグラウンドに回るとアプリケーションは停止し
待機状態になります。Activity には下記のイベントが発生します。
・onPause
・onStop
・onDestory
Home ボタン等でバックグラウンドに切り替わった場合は下記の通り。
・onPause → onStop
アプリが切り替わっても部分的に画面が見ている場合は onPause だけです。
Back ボタンで前のアプリに戻る場合はさらに onDestory も呼ばれて終了します。
・onPause → onStop → onDestory
最初ここでわからなかったのが Linux process との関係です。
onDestory で Activity のインスタンスが削除されても Linux から見える
Process は残っています。
RAM 容量に十分な空きがある場合、Process 空間にロードされたプログラム
コードをすぐ削除せずに、キャッシュとして再利用することが目的のようです。
この状態ではメモリは占有していますが停止しているため CPU は消費しません。
メモリが足りなくなると即座に回収されます。
(B) は Activity が終了しても Process が残っている状態を意味しています。
メモリが足りなくなった場合システムは (B)→(A) の順で回収します。
裏でアプリが動いて重くなるのは (A) 状態のまま多数存在していることが原因と
考えられます。ただしその挙動やリソース消費は厳密にはアプリ依存です。
(B) は CPU を消費しないキャッシュなので、一見 RAM を消費し Process が
残っているように見えますが気にする必要はなさそうです。
アプリを作る上で注意しなければならない点は下記の通り。
・onPause や onStop 状態からも強制終了させられる可能性がある
・onDestory でもプロセス空間は残っていることがある
特に NDK を使っていると 2つ目の点で困ったことが起こります。
続く
参考ページ
・Application Fundamentals
それでも使っているうちにだんだん Android の挙動が分かってきます。
・Home ボタンでホームメニューに戻っただけでは終了しない
・Back ボタンで戻る場合はアプリが終了していることが多い
よってアプリケーションの切り替え方法は 2種類あります。
(1) 現在の状態を保ったままバックグラウンドに切り替える方法
(2) 現在の状態を捨てて前の画面(アプリ)に戻る方法
さらにあまり意識していないだけでもう1つあることがわかりました。
(3) 現在の状態を保ったまま別のアプリを呼び出す。
例えばアプリ内から URL をタッチしてブラウザが呼ばれた場合。
また Home ボタン長押しでタスクマネージャーを呼び出し、そこからアプリを
呼び出した場合も同様です。
どちらも Back ボタンを押すと前のアプリの画面に戻ることが出来ます。
(2) はスタックから pop する動作で、ブラウザに例えると [←] ボタン。
(3) はスタックに push する動作で、ブラウザだとページ内のリンクのクリック。
(1) はスタックを切り替えます。ブラウザの新しい Tab を開くようなものです。
厳密にはアプリケーションは Activity という単位に分かれており、
実行したり外部から呼び出されるのはこの Activity です。
アプリケーションがどこかのサイトを示すなら Activity はページ相当でしょうか。
Android は複数のサイト(アプリ)間にまたがって各ページにリンクを貼ることが
可能で、その履歴が保存されます。
この Activity の呼び出しヒストリが保存されている一連のスタックを "Task" と
呼んでいます。やはりブラウザの Tab のように、操作によっては複数の履歴
スタック ("Task") が作られます。
これらのアプリが動作している VM は Linux の Process の上で動いています。
Android はマルチタスクの OS なので複数のアプリケーションが起動します。
動作中のアプリがバックグラウンドに残ってシステムが重くならないよう、
普段から意識して Back ボタンを多用していました。
ブラウザのように明確な Tab 切り替えができて、かつ Tab 単位で Close
ボタンがあればもっと分かりやすくなっていたのではないかと思います。
●複数の終了・中断状態
画面から見えなくなったりバックグラウンドに回るとアプリケーションは停止し
待機状態になります。Activity には下記のイベントが発生します。
・onPause
・onStop
・onDestory
Home ボタン等でバックグラウンドに切り替わった場合は下記の通り。
・onPause → onStop
アプリが切り替わっても部分的に画面が見ている場合は onPause だけです。
Back ボタンで前のアプリに戻る場合はさらに onDestory も呼ばれて終了します。
・onPause → onStop → onDestory
最初ここでわからなかったのが Linux process との関係です。
onDestory で Activity のインスタンスが削除されても Linux から見える
Process は残っています。
RAM 容量に十分な空きがある場合、Process 空間にロードされたプログラム
コードをすぐ削除せずに、キャッシュとして再利用することが目的のようです。
この状態ではメモリは占有していますが停止しているため CPU は消費しません。
メモリが足りなくなると即座に回収されます。
リソース\状態 (A)onPause/onStop (B)onDestory (C)未実行 ------------------------------------------------------------------- Activity インスタンス 存在 無し 無し メモリ空間 専有 専有 無し CPU リソース アプリ依存で消費 無し 無し
(B) は Activity が終了しても Process が残っている状態を意味しています。
メモリが足りなくなった場合システムは (B)→(A) の順で回収します。
裏でアプリが動いて重くなるのは (A) 状態のまま多数存在していることが原因と
考えられます。ただしその挙動やリソース消費は厳密にはアプリ依存です。
(B) は CPU を消費しないキャッシュなので、一見 RAM を消費し Process が
残っているように見えますが気にする必要はなさそうです。
アプリを作る上で注意しなければならない点は下記の通り。
・onPause や onStop 状態からも強制終了させられる可能性がある
・onDestory でもプロセス空間は残っていることがある
特に NDK を使っていると 2つ目の点で困ったことが起こります。
続く
参考ページ
・Application Fundamentals